(mandriva,eclipse,Qt) elementary problem : signals and slots

L

lolveley

hi,

I would like to make a little program using Qt : it's a displayer /
converter between farenheit and celsius degrees.
I also want to use QtDesigner.

I made a little widget with QtDesigner, and this widget contains two
dials(dial and dial_2) and two spinboxes(kind of textboxes) (spinbox and
spinbox_2).
There are some connections : see below for the ruby file I obtained with
the tool rbuic4 (which converts the ".ui" file into ".rb").
my problem is this : I want that some changes made in dial_2 modify dial
(and then spinbox), eg :
0 celsius degrees => 32 farenheit degrees.

here is the file made by rbuic4 and after this my try to modify the slot
setValue (but it doesn't run: the value of dial is always the same as
the one of dial_2.

temp.rb
*******************************************************************
=begin
** Form generated from reading ui file 'temp.ui'
**
** Created: lun. mai 11 21:43:04 2009
** by: Qt User Interface Compiler version 4.5.0
**
** WARNING! All changes made in this file will be lost when recompiling
ui file!
=end

class Ui_Form
attr_accessor :dial
attr_reader :dial_2
attr_reader :spinBox
attr_reader :spinBox_2

def setupUi(form)
if form.objectName.nil?
form.objectName = "form"
end
form.resize(400, 300)
@dial = Qt::Dial.new(form)
@dial.objectName = "dial"
@dial.geometry = Qt::Rect.new(90, 40, 91, 101)
@dial_2 = Qt::Dial.new(form)
@dial_2.objectName = "dial_2"
@dial_2.geometry = Qt::Rect.new(230, 30, 91, 121)
@spinBox = Qt::SpinBox.new(form)
@spinBox.objectName = "spinBox"
@spinBox.geometry = Qt::Rect.new(100, 200, 58, 28)
@spinBox_2 = Qt::SpinBox.new(form)
@spinBox_2.objectName = "spinBox_2"
@spinBox_2.geometry = Qt::Rect.new(240, 200, 58, 28)

retranslateUi(form)
Qt::Object.connect(@dial_2, SIGNAL('valueChanged(int)'), @spinBox_2,
SLOT('setValue(int)'))
Qt::Object.connect(@dial, SIGNAL('valueChanged(int)'), @spinBox,
SLOT('setValue(int)'))
Qt::Object.connect(@dial_2, SIGNAL('valueChanged(int)'), @dial,
SLOT('setValue(int)'))

Qt::MetaObject.connectSlotsByName(form)
end # setupUi

def setup_ui(form)
setupUi(form)
end

def retranslateUi(form)
form.windowTitle = Qt::Application.translate("Form", "Form", nil,
Qt::Application::UnicodeUTF8)
end # retranslateUi

def retranslate_ui(form)
retranslateUi(form)
end

end

module Ui
class Form < Ui_Form
end
end # module Ui


*******************************************************************

temp_dsc_form.rb
*******************************************************************
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)


def (Un_form.dial).setValue(v)

#super((1.8*v+32).to_i)
super(0)
end

un_wdg.show
une_appli.exec

*******************************************************************


can you help me?

thx,

lolveley.











___________________________________________________________________________
Yahoo! Mail réinvente le mail ! Découvrez le nouveau Yahoo! Mail et son interface révolutionnaire.
http://fr.mail.yahoo.com
 
S

Stefano Crocco

|hi,
|
|I would like to make a little program using Qt : it's a displayer /
|converter between farenheit and celsius degrees.
|I also want to use QtDesigner.
|
|I made a little widget with QtDesigner, and this widget contains two
|dials(dial and dial_2) and two spinboxes(kind of textboxes) (spinbox and
|spinbox_2).
|There are some connections : see below for the ruby file I obtained with
|the tool rbuic4 (which converts the ".ui" file into ".rb").
|my problem is this : I want that some changes made in dial_2 modify dial
|(and then spinbox), eg :
| 0 celsius degrees => 32 farenheit degrees.
|
|here is the file made by rbuic4 and after this my try to modify the slot
|setValue (but it doesn't run: the value of dial is always the same as
|the one of dial_2.

I don't know why it doesn't work, as I never used the designer to make
signal/slot connections. I'd say it should work, but there might be some
limitations which I'm not aware of. My suggestion is to use a custom widget
class instead of a generic Qt::Widget and to implement the slot which converts
the values there. Here's how the tmp_dsc_form.rb could look like:

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

Of course, if you use this you can remove the connections made from the
designer.

I hope this helps

Stefano
 
R

richard.j.dale

I don't know why it doesn't work, as I never used the designer to make
signal/slot connections. I'd say it should work, but there might be some
limitations which I'm not aware of. My suggestion is to use a custom widget
class instead of a generic Qt::Widget and to implement the slot which converts
the values there. Here's how the tmp_dsc_form.rb could look like:

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

Of course, if you use this you can remove the connections made from the
designer.
I'm not sure if this solves the problem of making the changes bi-
directional because if you use the 'valueChanged(int)' signal, as you
will end up with a loop because each dial will try to change the
other.

I think the original rbuic4 generated code was nearly correct, but it
should use 'sliderMoved(int)' signals in one dial connected to
'setValue(int)' in the other dial because that would loop. And it
needs an extra connection so that @dial_2 is changed when @dial is
changed.

Qt::Object.connect(@dial, SIGNAL('sliderMoved(int)'), @dial_2, SLOT
('setValue(int)'))
Qt::Object.connect(@dial_2, SIGNAL('sliderMoved(int)'), @dial, SLOT
('setValue(int)'))

But that wouldn't convert the values. So instead it needs an
intermediate Qt::Object (doesn't need to be a Qt::Widget) to convert
the values as Stefano suggests.


-- Richard
 
L

lolveley

hello,

thank you richard and stefano for your answers.
I'm afraid I haven't well understood the system of slots, if I want to
rewrite a slot - say setValue(int) - of a dial what can I put in this
method? I have to put a statement telling the slot to modify graphically
the widget, but I don't think it is possible.

I think _ but I'm not sure _ I have understood the solution of richard :
it is to create a class with a slot (for example setValue) which receive
the value in degree, and this slot emit a signal (here
dial.setValue(int)) which send the converted value (in Farenheit).

is it this?

lolveley.



(e-mail address removed) a écrit :
I'm not sure if this solves the problem of making the changes bi-
directional because if you use the 'valueChanged(int)' signal, as you
will end up with a loop because each dial will try to change the
other.

I think the original rbuic4 generated code was nearly correct, but it
should use 'sliderMoved(int)' signals in one dial connected to
'setValue(int)' in the other dial because that would loop. And it
needs an extra connection so that @dial_2 is changed when @dial is
changed.

Qt::Object.connect(@dial, SIGNAL('sliderMoved(int)'), @dial_2, SLOT
('setValue(int)'))
Qt::Object.connect(@dial_2, SIGNAL('sliderMoved(int)'), @dial, SLOT
('setValue(int)'))

But that wouldn't convert the values. So instead it needs an
intermediate Qt::Object (doesn't need to be a Qt::Widget) to convert
the values as Stefano suggests.


-- Richard






___________________________________________________________________________
Yahoo! Mail réinvente le mail ! Découvrez le nouveau Yahoo! Mail et son interface révolutionnaire.
http://fr.mail.yahoo.com
 
R

richard.j.dale

hello,

thank you richard and stefano for your answers.
I'm afraid I haven't well understood the system of slots, if I want to
rewrite a slot - say setValue(int) - of a dial what can I put in this
method? I have to put a statement telling the slot to modify graphically
the widget, but I don't think it is possible.

I think _ but I'm not sure _ I have understood the solution of richard :
it is to create a class with a slot (for example setValue) which receive
the value in degree, and this slot emit a signal (here
dial.setValue(int)) which send the converted value (in Farenheit).
You could emit a signal from the intermediate 'converter' Qt::Widget
or Qt::Object which is connected to the target dial's 'setValue()'
slot, or you can just call the slot directly with the converted value
- the effect is the same.
is it this?

In QtRuby, a slot can either be a normal Ruby method, or it can be a
block. Maybe it is easier to understand if you connect a block
directly to each dial's 'sliderMoved(int)' signal, like this:

Un_form.dial.connect(SIGNAL('sliderMoved(int)')) do |farenheit|
celcius = ((farenheit - 32) / 1.8).to_i
puts "dial: #{farenheit} farenheit ==> #{celcius} celcius"
Un_form.dial_2.value = celcius
Un_form.spinBox_2.value = celcius
end

Un_form.dial_2.connect(SIGNAL('sliderMoved(int)')) do |celcius|
farenheit = ((1.8 * celcius) + 32).to_i
puts "dial_2: #{celcius} celcius ==> #{farenheit} farenheit"
Un_form.dial.value = farenheit
Un_form.spinBox.value = farenheit
end

The you don't need an intermediate Qt::Widget or Qt::Object to do the
conversion calculations.

Note that in QtRuby you can write 'setFoo(v)' methods like 'foo = v',
and so

Un_form.spinBox.setValue(farenheit)

can also be written as:

Un_form.spinBox.value = farenheit

-- Richard
 
L

lolveley

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.


Stefano Crocco a écrit :
I don't know why it doesn't work, as I never used the designer to make
signal/slot connections. I'd say it should work, but there might be some
limitations which I'm not aware of. My suggestion is to use a custom widget
class instead of a generic Qt::Widget and to implement the slot which converts
the values there. Here's how the tmp_dsc_form.rb could look like:

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

Of course, if you use this you can remove the connections made from the
designer.

I hope this helps

Stefano






___________________________________________________________________________
Yahoo! Mail réinvente le mail ! Découvrez le nouveau Yahoo! Mail et son interface révolutionnaire.
http://fr.mail.yahoo.com
 
S

Stefano Crocco

|Stefano Crocco a =E9crit :
|> require 'Qt4'
|> require 'temp.rb'
|>
|> class MyWidget < Qt::Widget
|>
|> slots 'change_values(int)'
|>
|> def initialize
|> super
|> @ui =3D 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 =3D (1.8*val+32).to_i
|> @ui.spinBox.value =3D new_value
|> @ui.dial.value =3D new_value
|> end
|>
|> end
|>
|> une_appli=3DQt::Application.new(ARGV)
|> un_wdg =3D 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=
=20
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 o=
f=20
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 fro=
m=20
the UI designer: the dial has a signal which informs of the fact that the=20
value has changed and the spin box has a slot which allows to change the va=
lue=20
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 s=
lot=20
in the first dial which make the conversion for you. In theory, this would=
=20
mean that you have to create a Qt::Object-derived class, define a method wh=
ich=20
does the conversion and sets the value of the first dial, and declare it as=
a=20
slot using the slots class method. In my code, I did this in the dial's par=
ent=20
widget, because I think it's the natural place to put code which connects=20
together the behaviour of two child widgets, but you don't have to do that.=
=20
However, as Richard suggested, in Ruby you have another choice to do that:=
=20
instead of connecting signals to slots, you can connect them to a block. Th=
is=20
way, you could keep all of your original code, replacing the method definit=
ion=20
with a connection to a block. It could look like this:

require 'temp.rb'
require 'Qt4'

une_appli=3DQt::Application.new(ARGV)
un_wdg=3DQt::Widget.new
Un_form=3DUi_Form.new
Un_form.setupUi(un_wdg)
Un_form.dial_2.connect(SIGNAL('valueChanged(int)')) do |v|
new_val =3D (1.8*val+32).to_i
Un_form.dial.value =3D new_val
Un_form.spinBox.value =3D new_val
end

un_wdg.show
une_appli.exec

A block connected with a signal will be called whenever the signal is emitt=
ed,=20
just like a slot, and the signal's argument will be passed to the block (th=
e=20
only downside of using blocks is that you can't disconnect them using=20
Qt::Object#disconnect).

To avoid having to remember to change the value of the first spin box, you =
can=20
also connect the first dial's valueChanged signal to the first spin box=20
setValue slot (you can do this from the designer) and remove the last line =
of=20
the block above. When the block is called and the value of the first dial=20
changes, it will emit the valueChanged signal with the new value as argumen=
t=20
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=20
tutorial you can find at
http://doc.trolltech.com/4.4/tutorials-tutorial.html (it seems it has been=
=20
removed from Qt 4.5 but you can find it in the documentation if you have a=
=20
less recent version). It's written for C++, but it should be quite easy to=
=20
understant. You can also find a ruby version of the tutorial in the qtruby=
=20
source tarball in the ruby/qtruby/examples/tutorial directory.

I hope this helps

Stefano
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top