From: Stefano Crocco Date: 2009-05-13T18:47:14+09:00 Subject: Re: (mandriva,eclipse,Qt) elementary problem : signals and slots On Tuesday 12 May 2009, lolveley wrote: > |Stefano Crocco a écrit : > |> require 'Qt4' > |> require 'temp.rb' > |> > |> class MyWidget < Qt::Widget > |> > |> slots 'change_values(int)' > |> > |> def initialize > |> super > |> @ui = Ui_Form.new > |> @ui.setupUi self > |> connect @ui.dial_2, SIGNAL('valueChanged(int)'), self, > |> SLOT('change_values(int)') > |> end > |> > |> def change_values val > |> new_value = (1.8*val+32).to_i > |> @ui.spinBox.value = new_value > |> @ui.dial.value = new_value > |> end > |> > |> end > |> > |> une_appli=Qt::Application.new(ARGV) > |> un_wdg = MyWidget.new > |> un_wdg.show > |> une_appli.exec > |hi stefano, > | > |I tried your example and it works fine, but I find this is not very > |simple, indeed this is a basic example : what would it be for a more > |complicated example? > | > |lolveley. The concept is quite simple: you want to do something when the value of the second dial changes. In particular, you want to: 1. make the second spin box show the value chosen with the second dial 2. set the value of the first dial to the equivalent in Farenheit degrees of the value in the second dial 3. make the first spin box show the value chosen with the first dial As you have already discovered, the first goal can be achieved directly from the UI designer: the dial has a signal which informs of the fact that the value has changed and the spin box has a slot which allows to change the value it displays: connect the signal and the slot and you're done. The second and third goal require a bit more work, as there's no suitable slot in the first dial which make the conversion for you. In theory, this would mean that you have to create a Qt::Object-derived class, define a method which does the conversion and sets the value of the first dial, and declare it as a slot using the slots class method. In my code, I did this in the dial's parent widget, because I think it's the natural place to put code which connects together the behaviour of two child widgets, but you don't have to do that. However, as Richard suggested, in Ruby you have another choice to do that: instead of connecting signals to slots, you can connect them to a block. This way, you could keep all of your original code, replacing the method definition with a connection to a block. It could look like this: require 'temp.rb' require 'Qt4' une_appli=Qt::Application.new(ARGV) un_wdg=Qt::Widget.new Un_form=Ui_Form.new Un_form.setupUi(un_wdg) Un_form.dial_2.connect(SIGNAL('valueChanged(int)')) do |v| new_val = (1.8*val+32).to_i Un_form.dial.value = new_val Un_form.spinBox.value = new_val end un_wdg.show une_appli.exec A block connected with a signal will be called whenever the signal is emitted, just like a slot, and the signal's argument will be passed to the block (the only downside of using blocks is that you can't disconnect them using Qt::Object#disconnect). To avoid having to remember to change the value of the first spin box, you can also connect the first dial's valueChanged signal to the first spin box setValue slot (you can do this from the designer) and remove the last line of the block above. When the block is called and the value of the first dial changes, it will emit the valueChanged signal with the new value as argument and that will trigger the setValue slot of the spin box. If you want to learn more about Qt programming, I suggest you the excellent Qt tutorial you can find at http://doc.trolltech.com/4.4/tutorials-tutorial.html (it seems it has been removed from Qt 4.5 but you can find it in the documentation if you have a less recent version). It's written for C++, but it should be quite easy to understant. You can also find a ruby version of the tutorial in the qtruby source tarball in the ruby/qtruby/examples/tutorial directory. I hope this helps Stefano