[Kde-bindings] branches/KDE/3.5/kdebindings/qtruby

Richard Dale Richard_Dale at tipitina.demon.co.uk
Wed Sep 13 17:29:13 UTC 2006


SVN commit 583859 by rdale:

* Blocks can now be used as slots in Qt::Object.connect() calls. There are two
  versions, a singleton method and an instance method. 

* Here is an example of the class method connect() call with a block as a target:

	app = Qt::Application.new(ARGV)
	quit = Qt::PushButton.new('Quit')
	Qt::Object.connect(quit, SIGNAL('clicked()'), app) { puts 'quit clicked' }

  The block is executed in the context of the target instance, 'app' in this 
  case.

* And the instance method form:

	class MyButton < Qt::Button
		def initialize(text)
			super(text)
			connect(self, SIGNAL('clicked()')) { puts 'button clicked' }
		end
		...

  The block is executed in the context of self - the instance making the 
  connect() call.

* The Rails version of the Ruby 1.9 method Object#instance_exec was used
  to invoke the block. Thanks to kelko on the #kde-ruby channel for the
  idea and the code, and #rickdangerous for further discussion.

CCMAIL: kde-bindings at kde.org



 M  +30 -0     ChangeLog  
 M  +17 -0     rubylib/qtruby/Qt.cpp  
 M  +43 -0     rubylib/qtruby/lib/Qt/qtruby.rb  


--- branches/KDE/3.5/kdebindings/qtruby/ChangeLog #583858:583859
@@ -1,3 +1,33 @@
+2006-09-13  Richard Dale  <rdale at foton.es>
+
+	* Blocks can now be used as slots in Qt::Object.connect() calls. There are two
+	  versions, a singleton method and an instance method. 
+
+	* Here is an example of the class method connect() call with a block as a target:
+
+		app = Qt::Application.new(ARGV)
+		quit = Qt::PushButton.new('Quit')
+		Qt::Object.connect(quit, SIGNAL('clicked()'), app) { puts 'quit clicked' }
+
+	  The block is executed in the context of the target instance, 'app' in this 
+	  case.
+
+	* And the instance method form:
+
+		class MyButton < Qt::Button
+			def initialize(text)
+				super(text)
+				connect(self, SIGNAL('clicked()')) { puts 'button clicked' }
+			end
+			...
+
+	  The block is executed in the context of self - the instance making the 
+	  connect() call.
+
+	* The Rails version of the Ruby 1.9 method Object#instance_exec was used
+	  to invoke the block. Thanks to kelko on the #kde-ruby channel for the
+	  idea and the code, and #rickdangerous for further discussion.
+
 2006-08-29  Richard Dale  <rdale at foton.es>
 
 	* Backported some memory leak fixes from Qt4 QtRuby
--- branches/KDE/3.5/kdebindings/qtruby/rubylib/qtruby/Qt.cpp #583858:583859
@@ -1853,6 +1853,21 @@
     return Qtrue;
 }
 
+static VALUE
+qobject_connect(int argc, VALUE * argv, VALUE self)
+{
+	if (rb_block_given_p()) {
+		if (argc == 2) {
+			return rb_funcall(qt_internal_module, rb_intern("connect"), 4, argv[0], argv[1], self, rb_block_proc());
+		} else if (argc == 3) {
+			return rb_funcall(qt_internal_module, rb_intern("connect"), 4, argv[0], argv[1], argv[2], rb_block_proc());
+		} else {
+			rb_raise(rb_eArgError, "Invalid argument list");
+		}
+	} else {
+		return rb_call_super(argc, argv);
+	}
+}
 
 // --------------- Ruby C functions for Qt::_internal.* helpers  ----------------
 
@@ -2695,6 +2710,8 @@
 	rb_define_method(klass, "receivers", (VALUE (*) (...)) receivers_qobject, 0);
 	rb_define_method(klass, "className", (VALUE (*) (...)) class_name, 0);
 	rb_define_method(klass, "inherits", (VALUE (*) (...)) inherits_qobject, -1);
+	rb_define_method(klass, "connect", (VALUE (*) (...)) qobject_connect, -1);   
+	rb_define_singleton_method(klass, "connect", (VALUE (*) (...)) qobject_connect, -1);   
     
 	return klass;
 }
--- branches/KDE/3.5/kdebindings/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb #583858:583859
@@ -1204,6 +1204,19 @@
 			return !@value 
 		end
 	end
+
+	class BlockInvocation < Qt::Object
+		def initialize(target, block, args)
+			super(target)
+			self.class.slots "invoke(#{args})"
+			@target = target
+			@block = block
+		end
+
+		def invoke(*args)
+			@target.instance_exec(*args, &@block)
+		end
+	end
 	
 	module Internal
 		@@classes   = {}
@@ -1601,6 +1614,14 @@
 			
 			meta.metaobject
 		end
+
+		def Internal.connect(src, signal, target, block)
+			signature = (signal =~ /\((.*)\)/) ? $1 : ""
+			return Qt::Object.connect(	src,
+										signal,
+										Qt::BlockInvocation.new(target, block, signature),
+										SLOT("invoke(#{signature})") )
+		end
 	end # Qt::Internal
 
 	Meta = {}
@@ -1730,8 +1751,30 @@
 	def emit(signal)
 		return signal
 	end
+
+	# See the discussion here: http://eigenclass.org/hiki.rb?instance_exec
+	# about implementations of the ruby 1.9 method instance_exec(). This
+	# version is the one from Rails. It isn't thread safe, but that doesn't
+	# matter for the intended use in invoking blocks as Qt slots.
+	def instance_exec(*arguments, &block)
+		block.bind(self)[*arguments]
+	end
 end
 
+class Proc 
+	# Part of the Rails Object#instance_exec implementation
+	def bind(object)
+		block, time = self, Time.now
+		(class << object; self end).class_eval do
+			method_name = "__bind_#{time.to_i}_#{time.usec}"
+			define_method(method_name, &block)
+			method = instance_method(method_name)
+			remove_method(method_name)
+			method
+		end.bind(object)
+	end
+end
+
 class Module
 	alias_method :_constants, :constants
 	alias_method :_instance_methods, :instance_methods



More information about the Kde-bindings mailing list