Search code examples
rubyqtqt4qtruby

QtRuby connect signals and slots with parameters/arguments


I would like to know how I can connect to a signal that take parameters (using Ruby blocks).

I know how to connect to one which does not take parameters:

myCheckbox.connect(SIGNAL :clicked) { doStuff }

However, this does not work:

myCheckbox.connect(SIGNAL :toggle) { doStuff }

It doesn't work because the toggle slot take a parameter void QAbstractButton::toggled ( bool checked ). How can I make it work with parameters?

Thanks.


Solution

  • The short answer to your question is that you must declare your method signature for the slot to connect to, using the slots method:

    class MainGUI < Qt::MainWindow
      # Declare all the custom slots that we will connect to
      # Can also use Symbol for slots with no params, e.g. :open and :save
      slots 'open()', 'save()',
            'tree_selected(const QModelIndex &,const QModelIndex &)'
    
      def initialize(parent=nil)
        super
        @ui = Ui_MainWin.new # Created by rbuic4 compiling a Qt Designer .ui file
        @ui.setupUi(self)    # Create the interface elements from Qt Designer
        connect_menus!
        populate_tree!
      end
    
      def connect_menus!
        # Fully explicit connection
        connect @ui.actionOpen, SIGNAL('triggered()'), self, SLOT('open()')
    
        # You can omit the third parameter if it is self
        connect @ui.actionSave, SIGNAL('triggered()'), SLOT('save()')
    
        # close() is provided by Qt::MainWindow, so we did not need to declare it
        connect @ui.actionQuit,   SIGNAL('triggered()'), SLOT('close()')       
      end
    
      # Add items to my QTreeView, notify me when the selection changes
      def populate_tree!
        tree = @ui.mytree
        tree.model = MyModel.new(self) # Inherits from Qt::AbstractItemModel
        connect(
          tree.selectionModel,
          SIGNAL('currentChanged(const QModelIndex &, const QModelIndex &)'),
          SLOT('tree_selected(const QModelIndex &,const QModelIndex &)')
        )
      end
    
      def tree_selected( current_index, previous_index )
        # …handle the selection change…
      end
    
      def open
        # …handle file open…
      end
    
      def save
        # …handle file save…
      end
    end
    

    Note that the signatures passed to SIGNAL and SLOT do not include any variable names.

    Also, as you concluded in your comment, it is simpler (and more Ruby-esque) to do away with the "slot" concept altogether and just use a Ruby block to connect the signal to invoke whatever method you like (or put the logic inline). Using the following syntax, you do not need to use the slots method to pre-declare your method or handling code.

    changed = SIGNAL('currentChanged(const QModelIndex &, const QModelIndex &)')
    
    # Call my method directly
    @ui.mytree.selectionMode.connect( changed, &method(:tree_selected) )
    
    # Alternatively, just put the logic in the same spot as the connection
    @ui.mytree.selectionMode.connect( changed ) do |current_index, previous_index|
      # …handle the change here…
    end