Using qui rather than rbuic for qtdesigner .ui files

D

David Brunell

I'm trying to load .ui files at runtime using the qui extension and
WidgetFactory rather than pre-translating the .ui XML file to ruby with
rbuic. Here's a simple program:

require 'Qt'
require 'qui'
a = Qt::Application.new(ARGV)
w = QUI::WidgetFactory.create "sampledialog.ui"
w.show()
a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
a.exec()

This works just fine in that it dynamically loads and presents the .ui
file as a window. However, how do I connect signals and slots? I
understand the process of method override when doing it the rbuic way,
but this doesn't seem to be working with WidgetFactory. The signals and
slots (but not their handling) are defined in the .ui file. Could
someone give this noob an example of how to implement a slot method? I
tried looking at some C++ examples, but I'm just not making the
connection to ruby. The .ui file is below. It just has two buttons,
Test and Close.

Thanks,

David


<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>SampleDialogUI</class>
<widget class="QDialog">
<property name="name">
<cstring>SampleDialogUI</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>155</width>
<height>45</height>
</rect>
</property>
<property name="caption">
<string>Sample Dialog</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QPushButton" row="1" column="2">
<property name="name">
<cstring>closeButton</cstring>
</property>
<property name="text">
<string>Close</string>
</property>
<property name="toolTip" stdset="0">
<string>Close this dialog</string>
</property>
</widget>
<widget class="QPushButton" row="1" column="1">
<property name="name">
<cstring>testButton</cstring>
</property>
<property name="text">
<string>Test</string>
</property>
<property name="toolTip" stdset="0">
<string>Test command execution</string>
</property>
</widget>
</grid>
</widget>
<connections>
<connection>
<sender>testButton</sender>
<signal>clicked()</signal>
<receiver>SampleDialogUI</receiver>
<slot>testButton_clicked()</slot>
</connection>
<connection>
<sender>closeButton</sender>
<signal>clicked()</signal>
<receiver>SampleDialogUI</receiver>
<slot>closeButton_clicked()</slot>
</connection>
</connections>
<slots>
<slot>testButton_clicked()</slot>
<slot>closeButton_clicked()</slot>
</slots>
<layoutdefaults spacing="6" margin="11"/>
</UI>
 
S

Stefano Crocco

Alle mercoled=C3=AC 14 gennaio 2009, David Brunell ha scritto:
I'm trying to load .ui files at runtime using the qui extension and
WidgetFactory rather than pre-translating the .ui XML file to ruby with
rbuic. Here's a simple program:

require 'Qt'
require 'qui'
a =3D Qt::Application.new(ARGV)
w =3D QUI::WidgetFactory.create "sampledialog.ui"
w.show()
a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
a.exec()

This works just fine in that it dynamically loads and presents the .ui
file as a window. However, how do I connect signals and slots? I
understand the process of method override when doing it the rbuic way,
but this doesn't seem to be working with WidgetFactory. The signals and
slots (but not their handling) are defined in the .ui file. Could
someone give this noob an example of how to implement a slot method? I
tried looking at some C++ examples, but I'm just not making the
connection to ruby. The .ui file is below. It just has two buttons,
Test and Close.

Thanks,

David

Not tested, because I'm using Qt 4 while, I think, you're using Qt 3. The i=
dea=20
is to create a custom widget class and to add the widget returned by=20
WidgetFactory.create as child widget. You shouldn't define custom slots in =
the=20
ui file, since there's no way to implement them. Any custom slot you'd defi=
ne=20
in the ui file is instead defined in the custom widget. Here's a simple=20
example which should work:

require 'Qt'
require 'qui'

class MainWidget < Qt::Widget
=20
slots 'test()'
=20
def initialize
@widget =3D QUI::WidgetFactory.create "sampledialog.ui"
self.layout =3D Qt::VBoxLayout.new
self.layout.add_widget @widget
connect @widget.child('testButton'), SIGNAL('clicked()'), self,=20
SLOT('test()')
end
=20
def test
puts "test button clicked"
end
=20
end

app =3D Qt::Application.new ARGV
w =3D MainWidget.new=20
w.show
a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
a.exec


I hope this helps

Stefano
 
D

David Brunell

Stefano said:
require 'Qt'
require 'qui'

class MainWidget < Qt::Widget

slots 'test()'

def initialize
@widget = QUI::WidgetFactory.create "sampledialog.ui"
self.layout = Qt::VBoxLayout.new
self.layout.add_widget @widget
connect @widget.child('testButton'), SIGNAL('clicked()'), self,
SLOT('test()')
end

def test
puts "test button clicked"
end

end

app = Qt::Application.new ARGV
w = MainWidget.new
w.show
a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
a.exec

Many thanks for your kind reply. I get the following error when running
your suggested code:

quitest2.rb:10:in `method_missing': undefined method `layout=' for
:MainWidget (NoMethodError)

I somewhat understand this error, but upon commenting out the two
self.layout lines, I then get the following error:

quitest2.rb:12:in `method_missing': super: no superclass method
`connect'(NoMethodError)

If I change "connect" to "Qt::Object.connect" (this is what the rbuic
compiler would generate) the error persists. Any ideas?

Thanks,

David
 
S

Stefano Crocco

Alle gioved=C3=AC 15 gennaio 2009, David Brunell ha scritto:
Many thanks for your kind reply. I get the following error when running
your suggested code:

quitest2.rb:10:in `method_missing': undefined method `layout=3D' for

:MainWidget (NoMethodError)

I somewhat understand this error, but upon commenting out the two
self.layout lines, I then get the following error:

quitest2.rb:12:in `method_missing': super: no superclass method
`connect'(NoMethodError)

Sorry, I forgot one line. The initialize method should be:

def initialize
super # this is the new part
@widget =3D QUI::WidgetFactory.create "sampledialog.ui"
self.layout =3D Qt::VBoxLayout.new
self.layout.add_widget @widget
connect @widget.child('testButton'), SIGNAL('clicked()'), self,=20
SLOT('test()')
end

This will solve the second problem and most likely also the first. If the f=
irs=20
remains, try replacing

self.layout =3D

set_layout

Stefano
 
D

David Brunell

Stefano said:
Sorry, I forgot one line. The initialize method should be:

def initialize
super # this is the new part

Well, now I get no errors. However, the dialog which appears is a blank
dialog, not the one which I designed with Qt designer. Any thoughts? I
can always go back to the rbuic compiler if I have to. Here is my code
at this point:

########################
require 'Qt'
require 'qui'

class MainWidget < Qt::Widget

slots 'test()'

def initialize
super
@widget = QUI::WidgetFactory.create "sampledialog.ui"
set_layout = Qt::VBoxLayout.new
set_layout.add_widget @widget
connect @widget.child('testButton'), SIGNAL('clicked()'), self,
SLOT('test()')
end

def test
puts "test button clicked"
end

end

a = Qt::Application.new ARGV
w = MainWidget.new
w.show
a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
a.exec
################################

Many thanks,

David
 
D

David Brunell

Ok, I got it working. Here is my code:

##########################################
require 'Qt'
require 'qui'

class MainWidget < Qt::Widget

slots 'test()', 'close()'

def initialize(app)
super()
@app = app
@widget = QUI::WidgetFactory.create "sampledialog.ui"
connect @widget.child('testButton'), SIGNAL('clicked()'), self,
SLOT('test()')
connect @widget.child('closeButton'), SIGNAL('clicked()'), self,
SLOT('close()')
@widget.show
end

def test
puts "test button clicked"
end

def close
@app.exit(0)
end

end

app = Qt::Application.new ARGV
dialog = MainWidget.new(app)
app.exec
######################################

The .ui file is the same as in the original post. I'm not sure this is
the most elegant way to make it work, so if you have any ideas on how to
clean it up, I'm open to suggestions.

One other question...what about Qt4? I think I need rbuic4 if I am
going to pre-compile the ui. Is there a qui4 for dynamic loading?

Kind regards,

David
 
S

Stefano Crocco

Alle luned=C3=AC 19 gennaio 2009, David Brunell ha scritto:
One other question...what about Qt4? =C2=A0I think I need rbuic4 if I am
going to pre-compile the ui. =C2=A0Is there a qui4 for dynamic loading?

The following should work using a recent svn revision from kdebindings.=20
However, it doesn't because findChild fails. I think it's a bug and I'll tr=
y=20
to contact the developers to=20

require 'Qt4'
require 'qtuitools'

class Dlg < Qt::Dialog
=20
slots 'test()'
=20
def initialize parent =3D nil
super
file =3D Qt::File.new File.expand_path('~/temp/test_ui.ui')
file.open(Qt::File::ReadOnly)
loader =3D Qt::UiLoader.new
@widget =3D loader.load file, self
file.close
self.layout =3D Qt::VBoxLayout.new self
layout.add_widget @widget
@close_btn =3D @widget.findChild(Qt::pushButton, 'close_btn')
@test_btn =3D @widget.findChild(Qt::pushButton, 'test_btn')
connect @close_btn, SIGNAL('clicked()'), Qt::Application.instance,=20
SLOT('close()')
connect @test_btn, SIGNAL('clicked()'), self, SLOT('test()')
end
=20
def test
puts "testing"
end
=20
end

app =3D Qt::Application.new ARGV
dlg =3D Dlg.new
dlg.exec
app.exec

Stefano
 
S

Stefano Crocco

Alle mercoled=C3=AC 21 gennaio 2009, Stefano Crocco ha scritto:
Alle luned=C3=AC 19 gennaio 2009, David Brunell ha scritto:

The following should work using a recent svn revision from kdebindings.
However, it doesn't because findChild fails. I think it's a bug and I'll
try to contact the developers to

require 'Qt4'
require 'qtuitools'

class Dlg < Qt::Dialog

slots 'test()'

def initialize parent =3D nil
super
file =3D Qt::File.new File.expand_path('~/temp/test_ui.ui')
file.open(Qt::File::ReadOnly)
loader =3D Qt::UiLoader.new
@widget =3D loader.load file, self
file.close
self.layout =3D Qt::VBoxLayout.new self
layout.add_widget @widget
@close_btn =3D @widget.findChild(Qt::pushButton, 'close_btn')
@test_btn =3D @widget.findChild(Qt::pushButton, 'test_btn')
connect @close_btn, SIGNAL('clicked()'), Qt::Application.instance,
SLOT('close()')
connect @test_btn, SIGNAL('clicked()'), self, SLOT('test()')
end

def test
puts "testing"
end

end

app =3D Qt::Application.new ARGV
dlg =3D Dlg.new
dlg.exec
app.exec

Stefano

My previous code contained an error: the clicked() signal of @close_btn sho=
uld=20
be connected to the quit() slot of Qt::Application.instance, not to the=20
close() signal (which it doesn't exist).

Also, to work around the bug I spoke about, it's enough to replace=20
Qt::pushButton with Qt::Object in the two calls to findChild.

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top