(Added install of qt4-dev-tools; useful for launch qt assisant from qt demos) |
(→Install the appropriate packages) |
||
| (8 intermediate revisions by 5 users not shown) | |||
| Line 1: | Line 1: | ||
| + | |||
'''Developing Qt4 Applications using Qt Designer and Ruby on Kubuntu Jaunty 9.04''' | '''Developing Qt4 Applications using Qt Designer and Ruby on Kubuntu Jaunty 9.04''' | ||
| Line 10: | Line 11: | ||
*Programmatically control the display of widgets on screen | *Programmatically control the display of widgets on screen | ||
*Do some simple debugging using ruby-debug | *Do some simple debugging using ruby-debug | ||
| − | |||
| − | |||
Ground breaking in the extreme! | Ground breaking in the extreme! | ||
{{Note|These instructions are tested with Kubuntu 9.04 (Jaunty Jackalope). They have also been tested successfully with Ubuntu 9.04. If you are a user of another distro, you are invited to post how you installed it on your distro. This will be very useful to other users!}} | {{Note|These instructions are tested with Kubuntu 9.04 (Jaunty Jackalope). They have also been tested successfully with Ubuntu 9.04. If you are a user of another distro, you are invited to post how you installed it on your distro. This will be very useful to other users!}} | ||
| − | |||
| − | |||
= Install the appropriate packages = | = Install the appropriate packages = | ||
From a command line terminal run<br> | From a command line terminal run<br> | ||
| − | < | + | <syntaxhighlight lang="bash"> |
sudo apt-get install libkorundum4-ruby1.8 | sudo apt-get install libkorundum4-ruby1.8 | ||
sudo apt-get install qt4-designer | sudo apt-get install qt4-designer | ||
| Line 28: | Line 25: | ||
sudo apt-get install libqt4-ruby1.8-examples | sudo apt-get install libqt4-ruby1.8-examples | ||
sudo apt-get install qt4-doc qt4-doc-html qt4-demos qt4-dev-tools | sudo apt-get install qt4-doc qt4-doc-html qt4-demos qt4-dev-tools | ||
| − | </ | + | </syntaxhighlight> |
| − | < | + | |
| + | For Mandriva 2010.1, i'have installed : | ||
| + | <syntaxhighlight lang="bash">sudo urpmi qt4-assistant qt4-debug qt4-designer qt4-doc qt4-examples ruby-qt4 ruby-qt4-devel</syntaxhighlight> | ||
| + | |||
| + | |||
| + | For Ubuntu 12.04 (Tried with ruby1.9) | ||
| + | <syntaxhighlight lang="bash"> | ||
| + | sudo apt-get install qtcreator | ||
| + | sudo gem install qtbindings | ||
| + | </syntaxhighlight> | ||
= Create a simple Form with Qt4 Designer<br> = | = Create a simple Form with Qt4 Designer<br> = | ||
| Line 60: | Line 66: | ||
*If you want to take a quick look at your form select Preview from the Form menu<br> | *If you want to take a quick look at your form select Preview from the Form menu<br> | ||
*But we're done with GUI stuff now! Let's get hacking... | *But we're done with GUI stuff now! Let's get hacking... | ||
| − | |||
| − | |||
= Creating the basic application structure<br> = | = Creating the basic application structure<br> = | ||
| Line 72: | Line 76: | ||
#For instant gratification run the command <tt>ruby dashboard_ui.rb</tt> | #For instant gratification run the command <tt>ruby dashboard_ui.rb</tt> | ||
#Woaa!!! You should see your beautiful form before your very eyes. But when the excitement dies down, be aware that if you were to add any code to your dashboard_ui.rb file it would get blown away every time we run <tt>rbuic4</tt> on this file to pick up the latest changes we made to the UI using Qt4 Designer. But it needn't be this way...<br> {{Note|The <tt>-x</tt> bit of the <tt>rbuic4</tt> command says to create a little stub (like a main function in C/C++ or public static void main in Java) that kicks off the application. Otherwise your application would have no entry point. | #Woaa!!! You should see your beautiful form before your very eyes. But when the excitement dies down, be aware that if you were to add any code to your dashboard_ui.rb file it would get blown away every time we run <tt>rbuic4</tt> on this file to pick up the latest changes we made to the UI using Qt4 Designer. But it needn't be this way...<br> {{Note|The <tt>-x</tt> bit of the <tt>rbuic4</tt> command says to create a little stub (like a main function in C/C++ or public static void main in Java) that kicks off the application. Otherwise your application would have no entry point. | ||
| − | |||
The <tt>-o dashboard_ui.rb</tt> bit of the command says dump the resulting ruby code into a file called dashboard_ui.rb | The <tt>-o dashboard_ui.rb</tt> bit of the command says dump the resulting ruby code into a file called dashboard_ui.rb | ||
| Line 83: | Line 86: | ||
*Move the following code from the dashboard_ui.rb file to main.rb<br> | *Move the following code from the dashboard_ui.rb file to main.rb<br> | ||
| − | < | + | <syntaxhighlight lang="ruby">if $0 == __FILE__ |
a = Qt::Application.new(ARGV) | a = Qt::Application.new(ARGV) | ||
u = Ui_Dialog.new | u = Ui_Dialog.new | ||
| Line 90: | Line 93: | ||
w.show | w.show | ||
a.exec | a.exec | ||
| − | end</ | + | end</syntaxhighlight> |
*Inside the main.rb file, there is no need for the opening <tt>if $0 == __FILE__'</tt> line (and it's enclosing <tt>end</tt> statement). This is because main.rb is going to be the entry point to our application. So you can safely remove those two lines. | *Inside the main.rb file, there is no need for the opening <tt>if $0 == __FILE__'</tt> line (and it's enclosing <tt>end</tt> statement). This is because main.rb is going to be the entry point to our application. So you can safely remove those two lines. | ||
| Line 115: | Line 118: | ||
*This gives us a main.rb file that looks like<br> | *This gives us a main.rb file that looks like<br> | ||
| − | < | + | <syntaxhighlight lang="ruby">require 'Qt4' |
require 'dashboard_ui' | require 'dashboard_ui' | ||
| Line 124: | Line 127: | ||
u.setup_ui(w) | u.setup_ui(w) | ||
w.show | w.show | ||
| − | a.exec</ | + | a.exec</syntaxhighlight> |
{{Note|It is fine to have more than one <tt>require 'Qt4'</tt> in your code, they just get ignored after the first one.}} | {{Note|It is fine to have more than one <tt>require 'Qt4'</tt> in your code, they just get ignored after the first one.}} | ||
| Line 139: | Line 142: | ||
In Qt4, this is the primary way to separate autogenerated from code from our own logic. Using a text editor '''create a new file in your my_first_project folder called dashboard.rb''' with the following contents. (Note: For the rest of this article be careful to pay attention as to whether we are talking about dashboard_ui.rb or dashboard.rb). The comments should explain what's going on. | In Qt4, this is the primary way to separate autogenerated from code from our own logic. Using a text editor '''create a new file in your my_first_project folder called dashboard.rb''' with the following contents. (Note: For the rest of this article be careful to pay attention as to whether we are talking about dashboard_ui.rb or dashboard.rb). The comments should explain what's going on. | ||
| − | < | + | <syntaxhighlight lang="ruby"> |
# We pull in the file containing the class which consists of generated code | # We pull in the file containing the class which consists of generated code | ||
require 'dashboard_ui' | require 'dashboard_ui' | ||
| Line 167: | Line 170: | ||
end | end | ||
| − | </ | + | </syntaxhighlight> |
== Giving our Dashboard class the power! == | == Giving our Dashboard class the power! == | ||
| Line 178: | Line 181: | ||
* Finally, we move the <tt>setup_ui</tt> function call and the creation of a <tt>Ui::Dialog</tt> instance from main.rb to '''our''' Dashboard class in dashboard.rb. As we do so we rename variables to be a little more meaningful. Here's what main.rb should look like when you're done... | * Finally, we move the <tt>setup_ui</tt> function call and the creation of a <tt>Ui::Dialog</tt> instance from main.rb to '''our''' Dashboard class in dashboard.rb. As we do so we rename variables to be a little more meaningful. Here's what main.rb should look like when you're done... | ||
| − | < | + | <syntaxhighlight lang="ruby"> |
require 'Qt4' | require 'Qt4' | ||
require 'dashboard' | require 'dashboard' | ||
| Line 186: | Line 189: | ||
dashboard.show | dashboard.show | ||
a.exec | a.exec | ||
| − | </ | + | </syntaxhighlight> |
<br> | <br> | ||
| Line 192: | Line 195: | ||
And here's what dashboard.rb should look like when you're done... | And here's what dashboard.rb should look like when you're done... | ||
| − | < | + | <syntaxhighlight lang="ruby"> |
# We pull in the file containing the class which consists of generated code | # We pull in the file containing the class which consists of generated code | ||
require 'dashboard_ui' | require 'dashboard_ui' | ||
| Line 233: | Line 236: | ||
end | end | ||
| − | </ | + | </syntaxhighlight> |
| − | + | ||
== Programmatically control how the List Widget is populated on app startup == | == Programmatically control how the List Widget is populated on app startup == | ||
| Line 242: | Line 244: | ||
From the the <tt>setupUi</tt> function in dashboard_ui.rb file to the bottom of our own dashboard.rb file's initialize function, move the lines | From the the <tt>setupUi</tt> function in dashboard_ui.rb file to the bottom of our own dashboard.rb file's initialize function, move the lines | ||
| − | < | + | <syntaxhighlight lang="ruby">Qt::ListWidgetItem.new(@listWidget) |
| − | Qt::ListWidgetItem.new(@listWidget)</ | + | Qt::ListWidgetItem.new(@listWidget)</syntaxhighlight> |
From the the <tt>retranslateUi</tt> function in dashboard_ui.rb file to the bottom of our dashboard.rb file's initialize function, move the lines | From the the <tt>retranslateUi</tt> function in dashboard_ui.rb file to the bottom of our dashboard.rb file's initialize function, move the lines | ||
| − | < | + | <syntaxhighlight lang="ruby"> |
@listWidget.item(0).text = Qt::Application.translate("Dialog", "First Line", nil, Qt::Application::UnicodeUTF8) | @listWidget.item(0).text = Qt::Application.translate("Dialog", "First Line", nil, Qt::Application::UnicodeUTF8) | ||
| − | @listWidget.item(1).text = Qt::Application.translate("Dialog", "Second Line", nil, Qt::Application::UnicodeUTF8)</ | + | @listWidget.item(1).text = Qt::Application.translate("Dialog", "Second Line", nil, Qt::Application::UnicodeUTF8)</syntaxhighlight> |
'''NB: Use <tt>@ui.listwidget</tt> in instead of just <tt>@listwidget</tt> in the lines that you move. This is because <tt>@ui</tt> is the variable that contains the Dialog which in turn contains the List Widget.''' | '''NB: Use <tt>@ui.listwidget</tt> in instead of just <tt>@listwidget</tt> in the lines that you move. This is because <tt>@ui</tt> is the variable that contains the Dialog which in turn contains the List Widget.''' | ||
| Line 255: | Line 257: | ||
This gives us a dashboard.rb file that looks as follows... | This gives us a dashboard.rb file that looks as follows... | ||
| − | + | <syntaxhighlight lang="ruby"> | |
| − | < | + | |
# We pull in the file containing the class which consists of generated code | # We pull in the file containing the class which consists of generated code | ||
require 'dashboard_ui' | require 'dashboard_ui' | ||
| Line 307: | Line 308: | ||
end | end | ||
| − | </ | + | </syntaxhighlight> |
| − | + | ||
| − | + | ||
= Debugging your application<br> = | = Debugging your application<br> = | ||
| Line 318: | Line 317: | ||
Ya, sure we don't need no stinkin' GUI! But don't tell those Qt guys - they seem to produce quite nice ones! | Ya, sure we don't need no stinkin' GUI! But don't tell those Qt guys - they seem to produce quite nice ones! | ||
| − | |||
= Useful Links and Articles<br> = | = Useful Links and Articles<br> = | ||
| Line 328: | Line 326: | ||
* Most Qt reference documentation is written with the C++ flavour of Qt in mind - for example the wealth of information available at http://qt.nokia.com/doc/4.5/index.html. It will talk of things like <tt>QFileDialog</tt>, <tt>QDir</tt> and so on. You need to release that when you use those framework classes in Qt Ruby you need to use <tt>Qt::FileDialog</tt>, <tt>Qt::Dir</tt> and so on. So don't forget to change that leading <tt>Q</tt> on the class names into a <tt>Qt::</tt>. A bit of mental jiggery-pokery to keep you on your toes! | * Most Qt reference documentation is written with the C++ flavour of Qt in mind - for example the wealth of information available at http://qt.nokia.com/doc/4.5/index.html. It will talk of things like <tt>QFileDialog</tt>, <tt>QDir</tt> and so on. You need to release that when you use those framework classes in Qt Ruby you need to use <tt>Qt::FileDialog</tt>, <tt>Qt::Dir</tt> and so on. So don't forget to change that leading <tt>Q</tt> on the class names into a <tt>Qt::</tt>. A bit of mental jiggery-pokery to keep you on your toes! | ||
* We have no maximize, minimize titler bar buttons in our little app. That's because the type of window in our application in a <tt>QDialog</tt>. If you want to have max and min buttons easily in your application's title bar use a <tt>QMainWindow</tt> instead. It's a good exercise for you to try and figure out how to do this. | * We have no maximize, minimize titler bar buttons in our little app. That's because the type of window in our application in a <tt>QDialog</tt>. If you want to have max and min buttons easily in your application's title bar use a <tt>QMainWindow</tt> instead. It's a good exercise for you to try and figure out how to do this. | ||
| + | |||
| + | [[Category:Ruby]] | ||
Developing Qt4 Applications using Qt Designer and Ruby on Kubuntu Jaunty 9.04
Part of Qt's great power lies in the fact that you get a top notch GUI design kit to please the most avid designer as well as an elegant development framework to keep the application coders happy. In this article we will take you through both sides of this equation as we show you how to create a small application which displays a list of items (pieces of text) and let's you move these items up and down via drag'n'drop. You'll learn how to
Ground breaking in the extreme!
| Note |
|---|
| These instructions are tested with Kubuntu 9.04 (Jaunty Jackalope). They have also been tested successfully with Ubuntu 9.04. If you are a user of another distro, you are invited to post how you installed it on your distro. This will be very useful to other users! |
From a command line terminal run
sudo apt-get install libkorundum4-ruby1.8 sudo apt-get install qt4-designer sudo apt-get install libqt4-ruby1.8-dev sudo apt-get install libqt4-ruby1.8-examples sudo apt-get install qt4-doc qt4-doc-html qt4-demos qt4-dev-tools
For Mandriva 2010.1, i'have installed :
sudo urpmi qt4-assistant qt4-debug qt4-designer qt4-doc qt4-examples ruby-qt4 ruby-qt4-devel
For Ubuntu 12.04 (Tried with ruby1.9)
sudo apt-get install qtcreator sudo gem install qtbindings
| Note |
|---|
| The -x bit of the rbuic4 command says to create a little stub (like a main function in C/C++ or public static void main in Java) that kicks off the application. Otherwise your application would have no entry point.
The -o dashboard_ui.rb bit of the command says dump the resulting ruby code into a file called dashboard_ui.rb We need to rerun this command every time we change the form using Qt4 Designer. Usually we won't add the -x flag |
if $0 == __FILE__ a = Qt::Application.new(ARGV) u = Ui_Dialog.new w = Qt::Dialog.new u.setupUi(w) w.show a.exec end
| Note |
|---|
| So what is the if $0 == __FILE__ line all about?
If the code within the if statement is in a file that is included by a separate top level program then this condition will be false. The code inside the if statement will not be executed. Note: you can always use rbuic4 with the -x option even for a production program - just that you will have a test hook in there if you ever just want to test the UI. |
| Note |
|---|
| To some, the latter is more Rubyesque. If you look in the autogenerated file dashboard_ui.rb, you will see that the function sampleUi() is wrapped by another function sample_ui().
Again for Rubyesque-ness, we change Ui_Dialog.new to Ui::Dialog.new This is just aesthetics. Syntactic sugar, but important syntactic sugar nonetheless! |
require 'Qt4' require 'dashboard_ui' a = Qt::Application.new(ARGV) u = Ui::Dialog.new w = Qt::Dialog.new u.setup_ui(w) w.show a.exec
| Note |
|---|
| It is fine to have more than one require 'Qt4' in your code, they just get ignored after the first one. |
Ok, so where are we at now? Well if you run ruby main.rb from the command line your dinky little dialog should appear. The way we are using the dialog in our application is called the Direct Approach. For more information (which is beyond the scope of this article) check out http://doc.trolltech.com/4.0/designer-using-a-component.html to see what the different approaches are. That article is very C++ based but you should get the gist of what is going on. But basically a lot of the important work is being done in the main.rb file; this means that we don't have much control over our widgets programmatically.
In the next section, we will switch to using the Single Inheritance Approach. Then we'll show you how to programmatically populate the List Widget on application startup. Fasten your seatbelts!
Ok, everything you learned is a lie! Well, not really, but definitely you'll want to do take the Single Inheritance Approach over the Direct Approach.
In Qt4, this is the primary way to separate autogenerated from code from our own logic. Using a text editor create a new file in your my_first_project folder called dashboard.rb with the following contents. (Note: For the rest of this article be careful to pay attention as to whether we are talking about dashboard_ui.rb or dashboard.rb). The comments should explain what's going on.
# We pull in the file containing the class which consists of generated code require 'dashboard_ui' # We inherit from Qt:Dialog as it gives us access to User Interface # functionality such as connecting slots and signals class Dashboard < Qt::Dialog # We are then free to put our own code into this class without fear # of it being overwritten. Here we add a initialize function which # can be used to customise how the form looks on startup. The method # initialize() is a constructor in Ruby def initialize(parent = nil) # Widgets in Qt can be optionally be children of other widgets. # That's why we accept parent as a parameter # This super call causes the constructor of the base class (Qt::Widget) # to be called, shepherding on the parent argument super(parent) # We'll be putting some code here real soon... end end
Next we need to move the creation of the actual dialog out of main.rb and into the dashboard.rb to make the Dashboard class responsible for managing the widget. This is a core concept to understand. At the same time, we make the following changes to the main.rb file
| Note |
|---|
| Why do we change the require statement? Because we are using the Dashboard class that we have defined and control rather than the Ui::Dialog class autogenerated by rbuic4 |
| Note |
|---|
| Why can we call the show method on the Dashboard object? Because of the subclassing we are implementing, Dashboard now is a Qt::Dialog object! |
require 'Qt4' require 'dashboard' a = Qt::Application.new(ARGV) dashboard = Dashboard.new dashboard.show a.exec
And here's what dashboard.rb should look like when you're done...
# We pull in the file containing the class which consists of generated code require 'dashboard_ui' # We inherit from Qt:Dialog as it gives us access to User Interface # functionality such as connecting slots and signals class Dashboard < Qt::Dialog # We are then free to put our own code into this class without fear # of it being overwritten. Here we add a initialize function which # can be used to customise how the form looks on startup. The method # initialize() is a constructor in Ruby def initialize(parent = nil) # Widgets in Qt can optionally be children of other widgets. # That's why we accept parent as a parameter # This super call causes the constructor of the base class (Qt::Widget) # to be called, shepherding on the parent argument super(parent) # The Dashboard class we are in holds presentation logic and exists # to 'manage' the dialog widget we created in Qt Designer earlier. # An instance of this dialog widget is created and stored in @ui variable @ui = Ui::Dialog.new # Calling setup_ui causes the dialog widget to be initialised with the # defaults you may have specified in Qt Designer. For example, it # - populates the 'First Line' and 'Second Line' items in the List Widget # - sets the drag drop mode to 'Internal' # - and much much more. Peer into the dashboard_ui.rb if you want to the # full gory details @ui.setup_ui(self) end end
Now currently all the code to insert the items into the Item List is controlled in the autogenerated file dashboard_ui.rb. Let's take the power back!
From the the setupUi function in dashboard_ui.rb file to the bottom of our own dashboard.rb file's initialize function, move the lines
Qt::ListWidgetItem.new(@listWidget) Qt::ListWidgetItem.new(@listWidget)
From the the retranslateUi function in dashboard_ui.rb file to the bottom of our dashboard.rb file's initialize function, move the lines
@listWidget.item(0).text = Qt::Application.translate("Dialog", "First Line", nil, Qt::Application::UnicodeUTF8) @listWidget.item(1).text = Qt::Application.translate("Dialog", "Second Line", nil, Qt::Application::UnicodeUTF8)
NB: Use @ui.listwidget in instead of just @listwidget in the lines that you move. This is because @ui is the variable that contains the Dialog which in turn contains the List Widget.
This gives us a dashboard.rb file that looks as follows...
# We pull in the file containing the class which consists of generated code require 'dashboard_ui' # We inherit from Qt:Dialog as it gives us access to User Interface # functionality such as connecting slots and signals class Dashboard < Qt::Dialog # We are then free to put our own code into this class without fear # of it being overwritten. Here we add a initialize function which # can be used to customise how the form looks on startup. The method # initialize() is a constructor in Ruby def initialize(parent = nil) # Widgets in Qt can optionally be children of other widgets. # That's why we accept parent as a parameter # This super call causes the constructor of the base class (Qt::Widget) # to be called, shepherding on the parent argument super(parent) # The Dashboard class we are in holds presentation logic and exists # to 'manage' the dialog widget we created in Qt Designer earlier. # An instance of this dialog widget is created and stored in @ui variable @ui = Ui::Dialog.new # Calling setup_ui causes the dialog widget to be initialised with the # defaults you may have specified in Qt Designer. For example, it # - populates the 'First Line' and 'Second Line' items in the List Widget # - sets the drag drop mode to 'Internal' # - and much much more. Peer into the dashboard_ui.rb if you want to the # full gory details @ui.setup_ui(self) # As promised... Qt::ListWidgetItem.new(@ui.listWidget) Qt::ListWidgetItem.new(@ui.listWidget) #And also... @ui.listWidget.item(0).text = Qt::Application.translate("Dialog", "First Line", nil, Qt::Application::UnicodeUTF8) @ui.listWidget.item(1).text = Qt::Application.translate("Dialog", "Second Line", nil, Qt::Application::UnicodeUTF8) end end
You should now be able to run ruby main.rb and see you're lovely form appear. Try to drag the first line and second line up and down. Not bad, eh?
One last thing if you need to do some simple debugging on your app, make sure that you have the ruby-debug gem installed (sudo gem install ruby-debug) and stick the line debugger in your source code anywhere you want to put a breakpoint. Then instead of the ruby command run rdebug main.rb and this will drop you into a nifty command line debugger. Initially it will be at line 1 in your source file but if you type c it will bring you to your breakpoint. For more on using command line debugging see ruby-debug in 30 seconds (we don't need no stinkin' GUI!).
Ya, sure we don't need no stinkin' GUI! But don't tell those Qt guys - they seem to produce quite nice ones!