ZetCode Ruby QT Tutorial
ZetCode Ruby QT Tutorial
This is Ruby Qt tutorial. In this tutorial you will learn the basics of GUI programming in Qt with Ruby language. The tutorial is suitable for beginners and intermediate programmers.
Qt
Qt is a cross-platform application development framework. ome of the well known applications developed with Qt are !"#$ %pera$ Google #arth and kype. Qt was first publicly released on &ay '((). It is dual licensed. That means$ it can be used for creating open source applications as well as commercial ones. Qt toolkit is a very powerful toolkit. It is well established in the open source community.
Introduction to Ruby Qt
In this part of the Ruby Qt tutorial$ we will introduce the Qt toolkit and create our first programs using the Ruby programming language. The purpose of this tutorial is to get you started with the Qt toolkit with the Ruby language. Images used in this tutorial can be downloaded here. I used some icons from the tango icons pack of the Gnome pro*ect.
About
Qt is one of the leading toolkits for creating graphical user interfaces. Ruby is a popular scripting language.
Creating a Tooltip
The first e+ample will show a tooltip. , tooltip is a small rectangular window$ which gives a brief information about an ob*ect. It is usually a GUI component. It is part of the help system of the application.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This code shows a tooltip on a window. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
'
super set*indowTitle ,Tooltip, setToolTip ,This is Qt::*id+et, resize #-$. %-$ o/e 0$$. 0$$ show end end
The e+ample creates a window. If we hover a mouse pointer over the area of the window$ a tooltip pops up.
re&uire 'Qt'
The re&uire keyword imports necessery types that we will use in the application.
class Qt(pp ) Qt::*id+et
The e+ample inherits from a Qt::*id+et. The -idget class is the base class of all user interface ob*ects. The widget is the atom of the user interface. It receives mouse$ keyboard and other events from the window system.
set*indowTitle ,Tooltip,
0igure1 Tooltip
Centering a window
In the second e+ample$ we will center the window on the screen.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra centers a window on the screen. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' *56T7 1 #-$ 78527T 1 %-$ class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,Center, resize *56T7. 78527T center show end de! center &dw 1 Qt::6es9top*id+et.new screen*idth 1 &dw.width screen7ei+ht 1 &dw.hei+ht 4 1 :screen*idth ; *56T7< / # y 1 :screen7ei+ht ; 78527T< / # o/e 4. y end end
These two constants define the width and height of the application window.
&dw 1 Qt::6es9top*id+et.new
.ere we calculate the +$ y coordinates of the centered window. To center a window on the screen$ we need to know the si3e of the screen and the si3e of the window.
o/e 4. y
Quit button
In the last e+ample of this section$ we will create a 4uit button. -hen we press this button$ the application terminates.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra creates a &uit button. *hen we press the button. the application ter inates. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
super set*indowTitle ,Quit button, init=ui resize #-$. %-$ o/e 0$$. 0$$ show end de! init=ui &uit 1 Qt::>ushButton.new 'Quit'. sel! &uit.resize ?$. 0$ &uit. o/e -$. -$ connect &uit. "52@(A:'clic9ed:<'<. B&(pp. "ACT:'&uit:<'< end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
The Qt::>ushButton class shows a button in Ruby Qt. It is a rectangular widget and usually shows a te+t label.
init=ui
-e create the button widget. The first parameter of the constructor is the label which the button displays. The second parameter is the parent widget of the button.
&uit.resize ?$. 0$ &uit. o/e -$. -$
The clic9ed signal is emitted$ when we click on the 4uit button. The connect method connects a signal to a particular slot of an ob*ect. In our case it is the &uit method of the application ob*ect. The B&(pp is a global pointer to the application instance.
0igure1 Quit button This section was an introduction to the Qt toolkit with the Ruby language.
Layout management
In this part of the Ruby Qt programming tutorial$ we will introduce layout managers. -hen we design the GUI of our application$ we decide what components we will use and how we will organi3e those components in the application. To organi3e our components$ we use speciali3ed non visible ob*ects called layout managers. There are several options in Qt. -e can use absolute positioning$ built-in layout managers or create a custom layout manager. -e can also visually build the layouts using the Qt "esigner. Qt has some important built-in layout managers. The Qt::3Bo4Aayout class lines up widgets vertically. Qt::7Bo4Aayout lines up widgets hori3ontally. The Qt::2ridAayout class lays out widgets in a grid. The grid layout is the most fle+ible layout manager. The bo+ layouts can be nested into one another to create comple+ layouts.
Absolute positioning
In most cases$ programmers should use layout managers. There are a few situations$ where we can use absolute positioning. In absolute positioning$ the programmer specifies the position and the si3e of each widget in pi+els. The si3e and the position of a widget do not change$ if you resi3e a window. ,pplications look different on various platforms$ and what looks %! on 6inu+$ might not look %! on &ac. 7hanging fonts in your application might spoil the layout. If you translate your application into another language$ you must redo your layout. 0or all these issues$ use the absolute positioning only when you have a reason to do so.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial 5n this pro+ra . we lay out wid+ets usin+ absolute positionin+. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,(bsolute, init=ui resize 0$$. #?$ o/e 0$$. 0$$ end show
de! init=ui set"tyle"heet ,Q*id+et D bac9+round;color: #E%E%E% F, bardeGo/ 1 Qt::>i4 ap.new ,bardeGo/.Gp+, rotunda 1 Qt::>i4 ap.new ,rotunda.Gp+, incol 1 Qt::>i4 ap.new , incol.Gp+, barAabel 1 Qt::Aabel.new sel! barAabel.set>i4 ap bardeGo/ barAabel. o/e #$. #$ rotAabel 1 Qt::Aabel.new sel! rotAabel.set>i4 ap rotunda rotAabel. o/e E$. %H$ inAabel 1 Qt::Aabel.new sel! inAabel.set>i4 ap incol inAabel. o/e %I$. -$ end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
-e use the o/e method to position the label on the window at +9/:$ y9/:. -hen we resi3e the window$ the labels retain their initial si3e.
Buttons example
In the following e+ample$ we will position two buttons in the bottom right corner of the window.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial 5n this pro+ra . we use bo4 layouts to position two buttons in the botto ri+ht corner o! the window. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,Buttons, init=ui resize 00$. %I$ o/e 0$$. 0$$ end show
<
hbo4 1 Qt::7Bo4Aayout.new o9 1 Qt::>ushButton.new ,CJ,. sel! apply 1 Qt::>ushButton.new ,(pply,. sel! hbo4.add*id+et o9. %. Qt::(li+nRi+ht hbo4.add*id+et apply /bo4.add"tretch % /bo4.addAayout hbo4 end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
These are the two buttons that will go into the bottom right corner of the window.
hbo4.add*id+et o9. %. Qt::(li+nRi+ht
-e put the ok button into the hori3ontal bo+. The second parameter is the stretch factor. It e+pands the area allotted to the ok button. It takes all available space left. The alignment of the windget inside this area is controlled by the third parameter. The Qt::(li+nRi+ht will align the button to the right.
/bo4.add"tretch %
This line creates a vertically e+panded white space$ which will push the hori3ontal bo+ with the buttons to the bottom.
/bo4.addAayout hbo4
Windows example
The following is a more complicated e+ample with nested bo+ layouts.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial 5n this pro+ra . use bo4 layouts to create a *indows e4a ple author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,*indows, init=ui resize 0-$. 0$$ o/e 0$$. 0$$ end show
de! init=ui /bo4 1 Qt::3Bo4Aayout.new sel! /bo4% 1 Qt::3Bo4Aayout.new hbo4% 1 Qt::7Bo4Aayout.new hbo4# 1 Qt::7Bo4Aayout.new windAabel 1 Qt::Aabel.new ,*indows,. sel! edit 1 Qt::Te4t8dit.new sel! edit.set8nabled !alse acti/ate 1 Qt::>ushButton.new ,(cti/ate,. sel!
':
close 1 Qt::>ushButton.new ,Close,. sel! help 1 Qt::>ushButton.new ,7elp,. sel! o9 1 Qt::>ushButton.new ,CJ,. sel! /bo4.add*id+et windAabel /bo4%.add*id+et /bo4%.add*id+et hbo4%.add*id+et hbo4%.addAayout acti/ate close. $. Qt::(li+nTop edit /bo4%
/bo4.addAayout hbo4% hbo4#.add*id+et help hbo4#.add"tretch % hbo4#.add*id+et o9 /bo4.addAayout hbo4#. % setAayout /bo4 end end
0irst goes the label widget. It goes simply to the top of the vertical bo+.
/bo4%.add*id+et /bo4%.add*id+et hbo4%.add*id+et hbo4%.addAayout acti/ate close. $. Qt::(li+nTop edit /bo4%
/bo4.addAayout hbo4%
In the center part of the window we have a te+t edit widget and two vertically lined up buttons. The buttons go into a vertical bo+. The buttons are aligned to the top within this vertical bo+. The vertical bo+ and the te+t edit go into a hori3ontal bo+. This hori3ontal bo+ goes to the base vertical bo+$ *ust below the label widget.
hbo4#.add*id+et help hbo4#.add"tretch % hbo4#.add*id+et o9 /bo4.addAayout hbo4#. %
The help and the ok button go into another hori3ontal bo+. There is an e+panded white space between these two buttons. ,gain$ the hori3ontal bo+ goes to the base vertical bo+. ''
setAayout /bo4
The base vertical bo+ is set to be the main layout of the window.
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,@ew Kolder, init=ui resize 0$$. 0$$ o/e 0$$. 0$$
'/
end
show
de! init=ui +rid 1 Qt::2ridAayout.new sel! na eAabel 1 Qt::Aabel.new ,@a e,. sel! na e8dit 1 Qt::Aine8dit.new sel! te4t 1 Qt::Te4t8dit.new sel! o9Button 1 Qt::>ushButton.new ,CJ,. sel! closeButton 1 Qt::>ushButton.new ,Close,. sel! +rid.add*id+et na eAabel. $. $ +rid.add*id+et na e8dit. $. %. %. 0 +rid.add*id+et te4t. %. $. #. E +rid.setColu n"tretch %. % +rid.add*id+et o9Button. E. # +rid.add*id+et closeButton. E. 0 end end
In our e+ample$ we have one label$ one line edit$ one te+t edit and two buttons.
+rid 1 Qt::2ridAayout.new sel!
-e place the label widget in the first cell of the grid. The cells count from :. The last two parameters are the row and column number.
+rid.add*id+et na e8dit. $. %. %. 0
The line edit widget is placed at the first row$ second column. The last two parameters are the row span and the column span. .ori3ontally$ the widget will span three columns.
+rid.setColu n"tretch %. %
The parameters of the method are the column number and the stretch factor. .ere we set stretch factor ' to the second column. This means$ that this column will take all remaining space. This was set$ because we wanted our buttons to retain their initial si3e.
'2
0igure1 >ew 0older e+ample In this part of the Ruby Qt tutorial$ we mentioned layout management of widgets.
Widgets
In this part of the Ruby Qt programming tutorial$ we will cover basic widgets. -idgets are basic building blocks of a GUI application. %ver the years$ several widgets became a standard in all toolkits on all % platforms. 0or e+ample a button$ a check bo+ or a scroll bar. Qt has a rich set of widgets which covers most of the programming needs. &ore speciali3ed widgets can be created as custom widgets.
Qt::CheckBox
The Qt::Chec9Bo4 is a widget$ that has two states. %n and %ff. The %n state is visuali3ed by a check mark. It is used to denote some boolean property. The Qt117heck=o+ widget provides a checkbo+ with a te+t label.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra uses Qt::Chec9Bo4 wid+et to show/hide the title o! the window. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt'
'5
class Qt(pp ) Qt::*id+et slots 'on=to++led:bool<' de! initialize super set*indowTitle ,Qt::Chec9Bo4, init=ui resize #-$. %-$ o/e 0$$. 0$$ end show
de! init=ui cb 1 Qt::Chec9Bo4.new ,"how Title,. sel! cb.setChec9ed true connect cb. "52@(A:,to++led:bool<,<. sel!. "ACT:,on=to++led:bool<,< cb. o/e -$. -$ end de! on=to++led state i! state set*indowTitle ,Qt::Chec9Bo4, else set*indowTitle ,, end end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In our e+ample$ we place a check bo+ on the window. The check bo+ shows?hides the title of the window.
set*indowTitle ,Qt::Chec9Bo4,
"uring the construction of the window$ we set a title for the window.
cb 1 Qt::Chec9Bo4.new ,"how Title,. sel!
The Qt::Chec9Bo4 widget is created. The first parameter of the constructor is its te+t label. The second parameter is the parent widget.
cb.setChec9ed true
The title is visible at the start of the application. o the check bo+ must be checked too.
connect cb. "52@(A:,to++led:bool<,<.
')
sel!. "ACT:,on=to++led:bool<,<
The to++led signal is emitted when the state of a check bo+ changes. -hen the signal is emitted$ we trigger the on=to++led method.
i! state set*indowTitle ,Qt::Chec9Bo4, else set*indowTitle ,, end
"epending on the state of the check bo+$ we show or hide the title of the window.
0igure1 Qt117heck=o+
Qt::Label
The Qt::Aabel widget is used to display te+t or image. >o user interaction is available.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra uses Qt::Aabel wid+et to show lyrics o! a son+. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,Lou 9now 5' init=ui resize #-$. %-$ o/e 0$$. 0$$ show no 2ood,
'8
end de! init=ui te4t 1 ,Meet you downstairs in the bar and heard your rolled up slee/es and your s9ull t;shirt Lou say why did you do it with hi todayN and sni!! e out li9e 5 was Tan&uerayOn cause you're y !ella. y +uy hand e your stella and !ly by the ti e 5' out the door you tear en down li9e Ro+er MooreOn 5 cheated ysel! li9e 5 9new 5 would 5 told ya. 5 was trouble you 9now that 5' no +ood, label 1 Qt::Aabel.new te4t. sel! label.setKont Qt::Kont.new ,>urisa,. P /bo4 1 Qt::3Bo4Aayout.new /bo4.add*id+et label setAayout /bo4 end end
Instead of manually coding the position and si3e of the label$ we put the label into a bo+ layout.
';
0igure1 Qt116abel
Qt::Line dit
The Qt::Aine8dit is a widget that allows to enter and edit a single line of plain te+t. There are undo?redo$ cut?paste and drag @ drop functions available for a Qt::Aine8dit widget.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra shows te4t which is entered in a Qt::Aine8dit wid+et in a Qt::Aabel wid+et. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'on=chan+ed:Q"trin+<' de! initialize super set*indowTitle ,Aine8dit, init=ui resize #-$. %-$ o/e 0$$. 0$$ show
'<
end de! init=ui Qlabel 1 Qt::Aabel.new sel! edit 1 Qt::Aine8dit.new sel! connect edit. "52@(A:,te4tChan+ed:Q"trin+<,<. sel!. "ACT:,on=chan+ed:Q"trin+<,< edit. o/e H$. %$$ Qlabel. o/e H$. E$ end de! on=chan+ed te4t Qlabel.setTe4t te4t Qlabel.adGust"ize end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In our e+ample we show two widgets. , line edit and a label widget. The te+t entered into the line edit is shown in the label widget.
edit 1 Qt::Aine8dit.new sel!
-hen we type or delete some te+t from the line edit$ the on=chan+ed method is triggered.
de! on=chan+ed te4t Qlabel.setTe4t te4t Qlabel.adGust"ize end
In the on=chan+ed method$ we set the contents of the line edit to the label widget. The adGust"ize method ensures that all te+t is visible.
'(
Toggle buttons
Toggle buttons are push buttons with a checkable flag set. Toggle button is a button that has two states. Aressed and not pressed. Bou toggle between these two states by clicking on it. There are situations where this functionality fits well.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra uses to++le buttons to chan+e the bac9+round colour o! a wid+et. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'on=clic9ed:<' de! initialize super set*indowTitle ,To++le button, init=ui resize 0$$. %?$ o/e 0$$. 0$$ show end de! init=ui Qcolor 1 Qt::Color.new $. $. $ set2eo etry 0$$. 0$$. #?$. %I$ set*indowTitle ,To++leButton, Qredb 1 Qt::>ushButton.new 'Red'. sel! Qredb.setChec9able true Qredb. o/e %$. %$ connect Qredb. "52@(A:,clic9ed:<,<. "ACT:,on=clic9ed:<,< Q+reenb 1 Qt::>ushButton.new '2reen'. sel! Q+reenb.setChec9able true Q+reenb. o/e %$. H$ connect Q+reenb. "52@(A:'clic9ed:<'<. "ACT:,on=clic9ed:<,<
/:
Qblueb 1 Qt::>ushButton.new ,Blue,. sel! Qblueb.setChec9able true Qblueb. o/e %$. %%$ connect Qblueb. "52@(A:,clic9ed:<,<. "ACT:,on=clic9ed:<,< Qs&uare 1 Qt::*id+et.new sel! Qs&uare.set2eo etry %-$. #$. %$$. %$$ Qs&uare.set"tyle"heet ,Q*id+et D bac9+round;color: Rs F, R Qcolor.na e end de! on=clic9ed red 1 Qcolor.red +reen 1 Qcolor.+reen blue 1 Qcolor.blue i! Qredb.isChec9ed red 1 #-else red 1 $ end i! Q+reenb.isChec9ed +reen 1 #-else +reen 1 $ end i! Qblueb.isChec9ed blue 1 #-else blue 1 $ end Qcolor 1 Qt::Color.new red. +reen. blue Qs&uare.set"tyle"heet:,Q*id+et D bac9+round;color: Rs F, R Qcolor.na e< end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In the code e+ample$ we use three toggle buttons to change the colour of a rectangular widget.
Qredb 1 Qt::>ushButton.new 'Red'. sel! Qredb.setChec9able true
-e create a Qt::>ushButton widget. The setChec9able method changes the push button into a toggle button.
connect Qredb. "52@(A:,clic9ed:<,<. "ACT:,on=clic9ed:<,<
/'
Qs&uare 1 Qt::*id+et.new sel! Qs&uare.set2eo etry %-$. #$. %$$. %$$ Qs&uare.set"tyle"heet ,Q*id+et D bac9+round;color: Rs F, R Qcolor.na e
-e create a s4uare widget. -e set its si3e. ,t the beginning$ it is black. In Qt$ we use style sheets to customi3e the appearance of a widget. Inside the on=clic9ed method$ we determine the colour value and update the s4uare widget to a new colour.
red 1 Qcolor.red +reen 1 Qcolor.+reen blue 1 Qcolor.blue
The red part of the colour is changed$ depending on the state of the red toggle button.
Qcolor 1 Qt::Color.new red. +reen. blue
Qt::ComboBox
The Qt::Co boBo4 is a widget that allows the user to choose from a list of options. It is a selection widget that displays the current item$ and can pop up a list of selectable items. , combo bo+ may be editable. It presents a list of options to the user in a way that takes up the minimum amount of screen space.
//
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra uses the Qt::Co boBo4 wid+et. The option selected !ro the co bo bo4 is displayed in the label wid+et. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epet ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'on=acti/ated:Q"trin+<' de! initialize super set*indowTitle ,Qt::Co boBo4, init=ui resize #-$. %-$ o/e 0$$. 0$$ show end de! init=ui Qlabel 1 Qt::Aabel.new ,Sbuntu,. sel! co bo 1 Qt::Co boBo4.new sel! co co co co co bo.add5te bo.add5te bo.add5te bo.add5te bo.add5te ,Sbuntu, ,Kedora, ,Mandri/a, ,Red 7at, ,Mint,
connect co bo. "52@(A:,acti/ated:Q"trin+<,<. sel!. "ACT:,on=acti/ated:Q"trin+<,< co bo. o/e -$. 0$ Qlabel. o/e -$. %$$ end de! on=acti/ated te4t Qlabel.setTe4t te4t Qlabel.adGust"ize end end app 1 Qt::(pplication.new (R23 Qt(pp.new
/2
app.e4ec
In our code e+ample$ we have two widgets. , combo bo+ and a label widget. The option selected from a combo bo+ is shown in the label.
Qlabel 1 Qt::Aabel.new ,Sbuntu,. sel!
This is the label$ that will show the currently selected option from the combo bo+.
co bo 1 Qt::Co boBo4.new sel!
-hen we select an option from the combo bo+$ the on=acti/ated method is triggered.
de! on=acti/ated te4t Qlabel.setTe4t te4t Qlabel.adGust"ize end
In the on=acti/ated method$ we update the label widget to the currently selected string from the combo bo+.
0igure1 Qt117ombo=o+ widget In this part of the Ruby Qt tutorial$ we have presented several Qt widgets.
/5
, menubar is one of the most visible parts of the GUI application. It is a group of commands located in various menus. -hile in console applications you had to remember all those arcane commands$ here we have most of the commands grouped into logical parts. There are accepted standards that further reduce the amount of time spending to learn a new application. &enus group commands that we can use in an application. Toolbars provide a 4uick access to the most fre4uently used commands.
!imple menu
The first e+ample will show a simple menu.
#!/usr/bin/ruby # # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra shows a si ple enu. 5t has one action. which will ter inate the pro+ra . when selected. author: Jan Bodnar website: www.zetcode.co last odi!ied: @o/e ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::Main*indow de! initialize super set*indowTitle ,"i ple init=ui resize #-$. %-$ o/e 0$$. 0$$ end show enu,
de! init=ui &uit 1 Qt::(ction.new ,TQuit,. sel! !ile 1 enuBar:<.addMenu ,TKile, !ile.add(ction &uit connect:&uit. "52@(A:,tri++ered:<,<. Qt::(pplication.instance. "ACT:,&uit:<,<<
end end
/)
-e have a menubar$ a menu and an action. In order to work with menus$ we must inherit from Main*indow widget.
&uit 1 Qt::(ction.new ,TQuit,. sel!
This code line creates a (ction. #ach Menu has one or more action ob*ects. >ote the ampersand C@D character. It creates a shortcut for the item. ,lt E Q. It also underlines the Q character. The shortcut is active$ when the file menu is dropped down.
!ile 1 enuBar:<.addMenu ,TKile, !ile.add(ction &uit
-e create a Menu ob*ect. The ampersand character creates a shortcut. ,lt E 0. The consecutive shortcuts ,lt E 0$ ,lt E Q 4uit the application.
connect:&uit. "52@(A:,tri++ered:<,<. Qt::(pplication.instance. "ACT:,&uit:<,<<
-hen we select this option from the menu$ the application 4uits.
!ubmenu
, submenu is a menu plugged into another menu ob*ect. The ne+t e+ample demonstrates this.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra sub enu creates a
author: Jan Bodnar website: www.zetcode.co last odi!ied: @o/e ber #$%#
/8
set*indowTitle ,"ub enu, init=ui resize #?$. #$$ o/e 0$$. 0$$ show end de! init=ui &uit 1 Qt::(ction.new ,TQuit,. sel! !ile 1 enuBar:<.addMenu ,TKile, i p 1 Qt::Menu.new ,5 port, seeds 1 Qt::(ction.new ,5 port news !eed...,. sel! ar9s 1 Qt::(ction.new ,5 port boo9 ar9s...,. sel! ail 1 Qt::(ction.new ,5 port ail...,. sel! i p .add(ction seeds i p .add(ction ar9s i p .add(ction ail !ile.addMenu i p !ile.add(ction &uit connect:&uit. "52@(A:,tri++ered:<,<. Qt::(pplication.instance. "ACT:,&uit:<,<<
end end
-e have two Menu ob*ects. The file menu and the import menu.
seeds 1 Qt::(ction.new ,5 port news !eed...,. sel! ar9s 1 Qt::(ction.new ,5 port boo9 ar9s...,. sel! ail 1 Qt::(ction.new ,5 port ail...,. sel!
/;
0igure1 ubmenu
re&uire 'Qt' class Qt(pp ) Qt::Main*indow de! initialize super set*indowTitle ,5 a+e init=ui resize #?$. #$$ o/e 0$$. 0$$ show enu,
/<
end de! init=ui newpi4 1 Qt::5con.new ,new.pn+, openpi4 1 Qt::5con.new ,open.pn+, &uitpi4 1 Qt::5con.new ,e4it.pn+, newa 1 Qt::(ction.new newpi4. ,T@ew,. sel! open 1 Qt::(ction.new openpi4. ,TCpen,. sel! &uit 1 Qt::(ction.new &uitpi4. ,TQuit,. sel! &uit.set"hortcut ,CtrlUQ, !ile 1 enuBar:<.addMenu ,TKile, !ile.add(ction newa !ile.add(ction open !ile.add"eparator !ile.add(ction &uit connect:&uit. "52@(A:,tri++ered:<,<. Qt::(pplication.instance. "ACT:,&uit:<,<< end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In our e+ample$ we have one menu with three actions. %nly the 4uit action will actually do something$ if we select it. -e also create a separator and a 7trl E Q shortcut$ which will terminate the application.
newpi4 1 Qt::5con.new ,new.pn+, openpi4 1 Qt::5con.new ,open.pn+, &uitpi4 1 Qt::5con.new ,e4it.pn+,
.ere we create three action ob*ects. The first parameter is the 5con.
&uit.set"hortcut ,CtrlUQ,
This line creates a shortcut. =y pressing this shortcut$ we will run the 4uit action$ which will 4uit the application.
!ile.add"eparator
-e create a separator. The separator is a hori3ontal line$ which enables us to group menu actions into some logical parts.
/(
A toolbar
The ToolBar class provides a movable panel that contains a set of controls$ which provide a 4uick access to the application actions.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra toolbar creates a
author: Jan Bodnar website: www.zetcode.co last odi!ied: @o/e ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::Main*indow de! initialize super set*indowTitle ,Toolbar, init=ui resize #-$. %-$ o/e 0$$. 0$$ end show
de! init=ui newpi 1 Qt::5con.new ,new#.pn+, openpi 1 Qt::5con.new ,open#.pn+, &uitpi 1 Qt::5con.new ,e4it#.pn+, toolbar 1 addToolBar , ain toolbar, toolbar.add(ction newpi. ,@ew Kile, toolbar.add(ction openpi. ,Cpen Kile,
2:
toolbar.add"eparator &uit 1 toolbar.add(ction &uitpi. ,Quit (pplication, connect:&uit. "52@(A:,tri++ered:<,<. Qt::(pplication.instance. "ACT:,&uit:<,<<
end end
The addToolBar method of the Main*indow creates a toolbar for the application. The te+t string gives a toolbar a name. This name is used to reference this toolbar$ because there can be multiple toolbars in one application. If we right click on the window area$ we can see a checkable option$ which shows?hides the toolbar.
toolbar.add"eparator
0igure1 Toolbar
$ndo redo
The following e+ample demonstrates$ how we can deactivate toolbar buttons on the toolbar. It is a common practice in GUI programming. 0or e+ample the save button. If we save all
2'
changes of our document to the disk$ the save button is deactivated in most te+t editors. This way the application indicates to the user$ that all changes are already saved.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra disables/enables actions on a toolbar author: Jan Bodnar website: www.zetcode.co last odi!ied: @o/e ber #$%#
re&uire 'Qt' class Qt(pp ) Qt::Main*indow slots 'count:<' de! initialize super set*indowTitle ,Toolbar, init=ui resize #-$. %-$ o/e 0$$. 0$$ end show
de! init=ui Qcount 1 # undoi 1 Qt::5con.new ,undo.pn+, redoi 1 Qt::5con.new ,redo.pn+, &uitpi 1 Qt::5con.new ,&uit.pn+, toolbar 1 addToolBar ,!irst toolbar, Qund 1 toolbar.add(ction undoi. ,Sndo, Qred 1 toolbar.add(ction redoi. ,Redo, connect Qund. "52@(A:,tri++ered:<,<. sel!. "ACT:,count:<,< connect Qred. "52@(A:,tri++ered:<,<. sel!. "ACT:,count:<,< toolbar.add"eparator &uit 1 toolbar.add(ction &uitpi. ,Quit (pplication, connect &uit. "52@(A:,tri++ered:<,<. Qt::(pplication.instance. "ACT:,&uit:<,<
end
de! count
2/
action 1 sender i! ,Sndo, 11 action.te4t Qcount 1 Qcount ; % else Qcount 1 Qcount U % end i! Qcount )1 $ Qund.set6isabled true Qred.set6isabled !alse end i! Qcount V1 Qund.set6isabled !alse Qred.set6isabled true end end end
In our e+ample$ we have three (ction ob*ects and a separator. ,fter several clicks on the undo or redo buttons$ they become deactivated. Fisually$ the buttons are grayed out.
Qcount 1 #
7licking on the toolbar button$ the tri++ered signal is emitted. -e connect this signal to the count method.
action 1 sender
=oth toolbar buttons call the count method. -e need to tell between them. This line determines$ which action ob*ect actually emitted the signal.
i! ,Sndo, 11 action.te4t Qcount 1 Qcount ; % else Qcount 1 Qcount U % end
The undo toolbar button subtracts ' from the count variable. The redo adds '. "epending on the value of the count variable$ we enable?disable the toolbar buttons.
i! Qcount )1 $ Qund.set6isabled true Qred.set6isabled !alse end
22
0igure1 Undo redo In this part of the Ruby Qt tutorial$ we mentioned the menus and toolbars.
Dialogs
In this part of the Ruby Qt programming tutorial$ we will work with dialogs. "ialog windows or dialogs are an indispensable part of most modern GUI applications. , dialog is defined as a conversation between two or more persons. In a computer application a dialog is a window which is used to GtalkG to the application. , dialog is used to input data$ modify data$ change the application settings etc. "ialogs are important means of communication between a user and a computer program.
%essage boxes
&essage bo+es are convenient dialogs that provide messages to the user of the application. The message consists of te+t and image data.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra de onstrates Messa+eBo4 dialo+s author: Gan bodnar website: www.zetcode.co last odi!ied: July #$$P
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'show6ialo+:<' de! initialize super set*indowTitle ,Messa+e dialo+s,
25
de! init=ui +rid 1 Qt::2ridAayout.new sel! +rid.set"pacin+ # error 1 Qt::>ushButton.new ,8rror,. sel! warnin+ 1 Qt::>ushButton.new ,*arnin+,. sel! &uestion 1 Qt::>ushButton.new ,Question,. sel! in!or ation 1 Qt::>ushButton.new ,5n!or ation,. sel! about 1 Qt::>ushButton.new ,(bout,. sel! +rid.add*id+et +rid.add*id+et +rid.add*id+et +rid.add*id+et +rid.add*id+et error. $. $ warnin+. $. % &uestion. %. $ in!or ation. %. % about. #. $
connect:error. "52@(A:,clic9ed:<,<. sel!. "ACT:,show6ialo+:<,<< connect:warnin+. "52@(A:,clic9ed:<,<. sel!. "ACT:,show6ialo+:<,<< connect:&uestion. "52@(A:,clic9ed:<,<. sel!. "ACT:,show6ialo+:<,<< connect:in!or ation. "52@(A:,clic9ed:<,<. sel!. "ACT:,show6ialo+:<,<< connect:about. "52@(A:,clic9ed:<,<. sel!. "ACT:,show6ialo+:<,<< end de! show6ialo+ button 1 sender i! ,8rror, 11 button.te4t Qt::Messa+eBo4.critical sel!. ,8rror,. ,8rror loadin+ !ile!, elsi! ,*arnin+, 11 button.te4t Qt::Messa+eBo4.warnin+ sel!. ,*arnin+,. ,Cperation not per itted!, elsi! ,Question, 11 button.te4t Qt::Messa+eBo4.&uestion sel!. ,Question,. ,(re you sure to &uitN, elsi! ,5n!or ation, 11 button.te4t Qt::Messa+eBo4.in!or ation sel!. ,5n!or ation,. ,6ownload co pleted., elsi! ,(bout, 11 button.te4t Qt::Messa+eBo4.about sel!. ,(bout,. ,ZetCode Ruby Qt tutorial., end
2)
-e use the 2ridAayout manager to set up a grid of five buttons. #ach of the buttons shows a different message bo+.
i! ,8rror, 11 button.te4t Qt::Messa+eBo4.critical sel!. ,8rror,. ,8rror loadin+ !ile!,
In case we pressed the error button$ we show the error dialog. -e use static methods of the Messa+eBo4 class to show the message bo+es.
"nput&ialog
The 5nput6ialo+ class provides a simple convenience dialog to get a single value from the user. The input value can be a string$ a number or an item from a list. , label must be set to tell the user what they should enter.
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra dialo+ shows an input
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'show6ialo+:<' de! initialize super set*indowTitle ,5nput dialo+, init=ui
28
resize E$$. ?$ o/e 0$$. 0$$ show end de! init=ui show 1 Qt::>ushButton.new ,6ialo+,. sel! connect:show. "52@(A:,clic9ed:<,<. sel!. "ACT:,show6ialo+:<,<< show. o/e #$. #$ Qedit 1 Qt::Aine8dit.new sel! Qedit. o/e %0$. ## end de! show6ialo+ te4t 1 Qt::5nput6ialo+.+etTe4t sel!. ,5nput 6ialo+,. ,8nter your na e, i! te4t !1 nil na e 1 te4t.strip i! not na e.e ptyN Qedit.setTe4t na e end end end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In the code e+ample$ we have a button and a line edit. The button shows an input dialog. -e get some te+t and the te+t is shown in the line edit widget.
te4t 1 Qt::5nput6ialo+.+etTe4t sel!. ,5nput 6ialo+,. ,8nter your na e,
The +etTe4t static method creates the input dialog. The te+t from the dialog is stored in the te+t variable.
i! te4t !1 nil na e 1 te4t.strip i! not na e.e ptyN Qedit.setTe4t na e end end
=efore we update the line edit$ we ensure$ that the te+t variable is not null and that it is not empty and does not consists only from spaces.
2;
Color&ialog
The Color6ialo+ class provides a dialog widget for specifying colors. The color dialogHs function is to allow users to choose colors.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial 5n this pro+ra . we use the Color6ialo+ to chan+e the color o! a label te4t author: Gan bodnar website: www.zetcode.co last odi!ied: July #$$P
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'show6ialo+:<' de! initialize super set*indowTitle ,Color dialo+, init=ui resize E$$. 0$$ o/e 0$$. 0$$ end show
de! init=ui Qlabel 1 Qt::Aabel.new ,ZetCode Ruby Qt tutorial,. sel! /bo4 1 Qt::3Bo4Aayout.new sel! Qlabel.set(li+n ent Qt::(li+nCenter /bo4.add*id+et Qlabel end de! ouse>ress8/ent e/ent
2<
color 1 Qt::Color6ialo+.+etColor i! not color.is3alid return end Qlabel.set"tyle"heet ,Q*id+et D color: Rs F, R color.na e end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
-e show a some te+t in the center of the window. =y clicking on the area of the window$ we show a color dialog. -e change the te+t foreground color to the selected color from the dialog.
de! end ouse>ress8/ent e/ent ...
In order to receive mouse press events for our window$ we must reimplement the ouse>ress8/ent method.
color 1 Qt::Color6ialo+.+etColor
The Color6ialo+ is being created. The selected color is stored in the color variable.
Qlabel.set"tyle"heet ,Q*id+et D color: Rs F, R color.na e
0igure1 7olor"ialog
2(
Font&ialog
The Kont6ialo+ class provides a dialog widget for selecting a font.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial 5n this pro+ra . we use the Kont6ialo+ to chan+e the !ont o! a label te4t author: Gan bodnar website: www.zetcode.co last odi!ied: July #$$P
re&uire 'Qt' class Qt(pp ) Qt::*id+et slots 'show6ialo+:<' de! initialize super set*indowTitle ,Kont dialo+, init=ui resize E$$. 0$$ o/e 0$$. 0$$ show end de! init=ui Qlabel 1 Qt::Aabel.new ,ZetCode Ruby Qt tutorial,. sel! /bo4 1 Qt::3Bo4Aayout.new sel! Qlabel.set(li+n ent Qt::(li+nCenter /bo4.add*id+et Qlabel end de! ouse>ress8/ent e/ent o9 1 Qt::Boolean.new !ont 1 Qt::Kont6ialo+.+etKont o9 i! not o9 return end Qlabel.setKont !ont end end
5:
Qt(pp.new app.e4ec
This e+ample is similar to the previous one. This time$ we change the font of the te+t.
!ont 1 Qt::Kont6ialo+.+etKont o9
The boolean ok variable is true$ if we clicked on the %! button of the dialog. -e return from the method$ if the cancel button was pressed.
Qlabel.setKont !ont
0igure1 0ont"ialog In this part of the Ruby Qt tutorial$ we worked with dialog windows.
Painting
In this part of the Ruby Qt programming tutorial we will do some painting. -hen do we need to paintI There are situations$ when we need to create a widget from scratch. In such a case$ we need to do painting. %r we want to create charts$ special ornaments$ effects or widget enhancements. The >ainter class is instrumental when we do some painting in the Qt library. Aaint events are received in the paint8/ent method. To do custom painting$ we must reimplement this method.
5'
'atterns
In Qt$ there are various patterns$ that we can use to fill the interiors of shapes.
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra draws nine rectan+les. The interiors are !illed with di!!erent built;in patterns. author: Gan bodnar website: www.zetcode.co last odi!ied: June #$$P
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,>atterns, resize 0-$. #?$ o/e 0$$. 0$$ end show
de! paint8/ent e/ent painter 1 Qt::>ainter.new sel! draw>atterns painter painter.end end de! draw>atterns painter painter.set>en Qt::@o>en painter.setBrush Qt::7or>attern painter.drawRect %$. %-. P$. H$ painter.setBrush Qt::3er>attern painter.drawRect %0$. %-. P$. H$ painter.setBrush Qt::Cross>attern painter.drawRect #-$. %-. P$. H$ painter.setBrush Qt::6enseI>attern painter.drawRect %$. %$-. P$. H$ painter.setBrush Qt::6enseH>attern painter.drawRect %0$. %$-. P$. H$
5/
painter.setBrush Qt::6ense->attern painter.drawRect #-$. %$-. P$. H$ painter.setBrush Qt::B6ia+>attern painter.drawRect %$. %P-. P$. H$ painter.setBrush Qt::K6ia+>attern painter.drawRect %0$. %P-. P$. H$ painter.setBrush Qt::6ia+Cross>attern painter.drawRect #-$. %P-. P$. H$
end end
In the code e+ample$ we will draw nine rectangles and fill them with different brush patterns.
de! paint8/ent e/ent painter 1 Qt::>ainter.new sel! draw>atterns painter painter.end
end
-hen the window area needs to be redrawn$ the paint8/ent method is called. This happens$ when we resi3e the window$ ma+imi3e it or minimi3e it etc. Inside this method$ we create the >ainter ob*ect. This ob*ect is used to do all painting in Qt. The painting itself is delegated to the draw>atterns method.
painter.set>en Qt::@o>en
The pen ob*ect is used to draw outlines of the shapes. In our e+ample we will not use a pen.
painter.setBrush Qt::7or>attern
-e draw a rectangle$ with the current pen and brush. The first two parameters of the method are the +$ y coordinates. The last two parameters are the width and height of the rectangle.
painter.end
52
0igure1 Aatterns
!hapes
The Qt painting ,AI can draw various shapes. The following programming code e+ample will show some of them.
#!/usr/bin/ruby # # # # # # # ZetCode Ruby Qt tutorial This pro+ra draws basic shapes
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,Basic shapes, resize 0-$. #?$ o/e 0$$. 0$$ end show
55
end de! draw"hapes painter painter.setRender7int Qt::>ainter::(ntialiasin+ painter.set>en Qt::Color.new %-$. %-$. %-$ painter.setBrush Qt::Brush.new Qt::Color.new %-$. %-$. %-$ path% 1 Qt::>ainter>ath.new path%. o/eTo -. path%.cubicTo E$. -. -$. -$. path%.cubicTo -. PP. -$. -$. painter.draw>ath path% PP. PP -. -
painter.draw>ie %0$. #$. P$. H$. 0$W%H. %#$W%H painter.drawChord #E$. 0$. P$. H$. $. %HW%?$ painter.drawRoundRect #$. %#$. ?$. -$ points 1 XY points.push points.push points.push points.push points.push Qt::>oint.new Qt::>oint.new Qt::>oint.new Qt::>oint.new Qt::>oint.new %0$. %?$. %?$. ##$. %E$. %E$ %I$ %E$ %%$ %$$
poly+on 1 Qt::>oly+on.new points painter.draw>oly+on poly+on painter.drawRect #-$. %%$. H$. H$ baseline 1 Qt::>ointK.new #$. #-$ !ont 1 Qt::Kont.new ,2eor+ia,. -path# 1 Qt::>ainter>ath.new path#.addTe4t baseline. !ont. ,Q, painter.draw>ath path# painter.draw8llipse %E$. #$$. H$. H$ painter.draw8llipse #E$. #$$. P$. H$ end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In this code e+ample$ we draw nine different shapes on the window. , comple+ path$ a pie$ a chord$ a rounded rectangle$ a polygon$ a rectangle$ a character based shape$ a circle and an ellipse.
painter.setRender7int Qt::>ainter::(ntialiasin+
-e use antialiasing in the e+ample. ,ntialiased shapes look better$ but it takes more time to draw them.
painter.set>en Qt::Color.new %-$. %-$. %-$ painter.setBrush Qt::Brush.new Qt::Color.new %-$. %-$. %-$
5)
The first comple+ shape is created with the >ainter>ath ob*ect. The AainterAath class provides a container for painting operations. , painter path is an ob*ect composed of a number of graphical building blocks$ such as rectangles$ ellipses$ lines$ and curves.
painter.draw>ie %0$. #$. P$. H$. 0$W%H. %#$W%H painter.drawChord #E$. 0$. P$. H$. $. %HW%?$ painter.drawRoundRect #$. %#$. ?$. -$
58
0igure1 hapes
Transparent rectangles
Transparency is the 4uality of being able to see through a material. The easiest way to understand transparency is to imagine a piece of glass or water. Technically$ the rays of light can go through the glass and this way we can see ob*ects behind the glass. In computer graphics$ we can achieve transparency effects using alpha compositing. ,lpha compositing is the process of combining an image with a background to create the appearance of partial transparency. The composition process uses an alpha channel. Cwikipedia.org$ answers.comD
#!/usr/bin/ruby # # # # # # # # # ZetCode Ruby Qt tutorial This pro+ra draws ten rectan+les with di!!erent le/els o! transparency. author: Gan bodnar website: www.zetcode.co last odi!ied: June #$$P
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,Transparent rectan+les, resize -P$. P$ o/e 0$$. 0$$ show
5;
end de! paint8/ent e/ent painter 1 Qt::>ainter.new sel! drawRectan+les painter painter.end
end
de! drawRectan+les painter painter.set>en Qt::@o>en !or i in %..%$ painter.setBrush Qt::Brush.new Qt::Color.new $. $. #--. iW#painter.drawRect -$Wi. #$. E$. E$ end end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
In the e+ample we will draw ten rectangles with different levels of transparency.
painter.set>en Qt::@o>en
-e use no pen.
!or i in %..%$ painter.setBrush Qt::Brush.new Qt::Color.new $. $. #--. iW#painter.drawRect -$Wi. #$. E$. E$ end
The last parameter of the 7olor ob*ect is the alpha transparency value.
&onut !hape
In the following e+ample we create a comple+ shape by rotating a bunch of ellipses.
#!/usr/bin/ruby # ZetCode Ruby Qt tutorial
5<
# # # # # # #
draws a donut
re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,6onut, resize 0-$. #?$ o/e 0$$. 0$$ end show
de! paint8/ent e/ent painter 1 Qt::>ainter.new sel! draw6onut painter painter.end end de! draw6onut painter painter.setRender7int Qt::>ainter::(ntialiasin+ color 1 Qt::Color.new color.set@a edColor ,#000000, pen 1 Qt::>en.new color pen.set*idth % painter.set>en pen w 1 width h 1 hei+ht painter.translate Qt::>oint.new w/#. h/# I#.ti es do painter.draw8llipse ;%#-. ;E$. #-$. ?$ painter.rotate -.$ end
end end
In this e+ample$ we create a donut. The shape resembles a cookie$ hence the name donut. 5(
-e move the coordinate system to the middle of the window. This way we make the drawing mathematically easier.
I#.ti es do painter.draw8llipse ;%#-. ;E$. #-$. ?$ painter.rotate -.$ end
-e draw an ellipse ob*ect ;/ times. #ach time$ we rotate the ellipse by ) degrees. This will create our donut shape.
0igure1 "onut
&rawing text
In the last e+ample$ we are going to draw te+t on the window.
#!/usr/bin/ruby # ZetCode Ruby Qt tutorial # # This pro+ra draws te4t # on the window #
):
# author: Gan bodnar # website: www.zetcode.co # last odi!ied: June #$$P re&uire 'Qt' class Qt(pp ) Qt::*id+et de! initialize super set*indowTitle ,"oul ate, resize 0I$. #E$ o/e 0$$. 0$$ end show
de! paint8/ent e/ent painter 1 Qt::>ainter.new sel! drawTe4t painter painter.end end de! drawTe4t painter painter.setBrush Qt::Brush.new Qt::Color.new #-. #-. #painter.setKont Qt::Kont.new ,>urisa,. %$ painter.drawTe4t Qt::>oint.new:#$. 0$<. ,Most relationships see so transitory, painter.drawTe4t Qt::>oint.new:#$. H$<. ,They're +ood but not the per anent one, painter.drawTe4t Qt::>oint.new:#$. %#$<. ,*ho doesn't lon+ !or so eone to hold, painter.drawTe4t Qt::>oint.new:#$. %-$<. ,*ho 9nows how to lo/e without bein+ told, painter.drawTe4t Qt::>oint.new:#$. %?$<. ,"o ebody tell e why 5' on y own, painter.drawTe4t Qt::>oint.new:#$. #%$<. ,5! there's a soul ate !or e/eryone, end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec
)'
0igure1 "rawing te+t In this part of the Ruby Qt programming tutorial$ we did some painting.
Custom widget
In this part of the Ruby Qt programming tutorial$ we will create a custom widget. Toolkits usually provide only the most common widgets like buttons$ te+t widgets$ sliders etc. >o toolkit can provide all possible widgets. Arogrammers must create such widgets by themselves. They do it by using the drawing tools provided by the toolkit. There are two possibilities. , programmer can modify or enhance an e+isting widget. %r he can create a custom widget from scratch.
)/
re&uire 'Qt' >(@8A=78527T 1 0$ 65"T(@C8 1 %P A5@8=*56T7 1 6535"5C@" 1 %$ KSAA=C(>(C5TL 1 I$$ M(Z=C(>(C5TL 1 I-$ class Burnin+ ) Qt::*id+et de! initialize:parent< super:parent< Qnu 1 X ,I-,. ,%-$,. ,##-,. ,0$$,. ,0I-,. ,E-$,. ,-#-,. ,H$$,. ,HI-, Y
QredColor 1 Qt::Color.new #--. %I-. %IQyellowColor 1 Qt::Color.new #--. #--. %?E Qparent 1 parent setMini u 7ei+ht >(@8A=78527T end de! paint8/ent e/ent painter 1 Qt::>ainter.new sel! draw*id+et painter painter.end
end
de! draw*id+et painter w 1 width.to=! slid=width 1 Qparent.+etCurrent*idth step 1 :w / 6535"5C@"<.round.to=! till 1 ::w / M(Z=C(>(C5TL< W slid=width<.to=! !ull 1 ::w / M(Z=C(>(C5TL< W KSAA=C(>(C5TL<.to=! i! slid=width V KSAA=C(>(C5TL painter.set>en QyellowColor painter.setBrush Qt::Brush.new QyellowColor painter.drawRect Qt::RectK.new $. $. !ull. >(@8A=78527T painter.set>en QredColor painter.setBrush Qt::Brush.new QredColor painter.drawRect Qt::RectK.new !ullU%. $. till;!ull. >(@8A=78527T else i! slid=width V $ painter.set>en QyellowColor painter.setBrush Qt::Brush.new QyellowColor painter.drawRect Qt::RectK.new $. $. till. >(@8A=78527T end
)2
end painter.set>en Qt::Color.new P$. P$. P$ painter.setBrush Qt::@oBrush painter.drawRect $. $. w;%. >(@8A=78527T;% newKont 1 !ont newKont.set>oint"ize I painter.setKont newKont !or i in :%..Qnu .len+th< painter.drawAine Qt::AineK.new iWstep. %. iWstep. A5@8=*56T7 etrics 1 Qt::KontMetrics.new newKont w 1 etrics.width Qnu Xi;%Y painter.drawTe4t:Qt::>ointK.new:iWstep;w/#. 65"T(@C8<. Qnu Xi; end end end
%Y<
class Qt(pp ) Qt::*id+et slots 'onChan+ed:int<' de! initialize super set*indowTitle ,The Burnin+ *id+et, initS5 resize 0I$. #$$ o/e 0$$. 0$$ show end de! initS5 Qcur=width 1 $ Qslider 1 Qt::"lider.new Qt::7orizontal . sel! Qslider.setMa4i u M(Z=C(>(C5TL Qslider.set2eo etry -$. -$. %0$. 0$ connect:Qslider. "52@(A:,/alueChan+ed:int<,<. sel!. "ACT:,onChan+ed:int<,<< /bo4 1 Qt::3Bo4Aayout.new sel! hbo4 1 Qt::7Bo4Aayout.new /bo4.add"tretch % Qwid+et 1 Burnin+.new sel! hbo4.add*id+et Qwid+et. $ /bo4.addAayout hbo4 setAayout /bo4 end
)5
de! onChan+ed /al Qcur=width 1 /al Qwid+et.repaint end de! +etCurrent*idth return Qcur=width end
end
These are important constants. The >(@8A=78527T defines the height for the custom widget. The 65"T(@C8 is the distance of the numbers on the scale from the top of their parent border. The A5@8=*56T7 is the vertical line width. The 6535"5C@" is the number of parts of the scale. The KSAA=C(>(C5TL is the ma+imum capacity of the media. ,fter it is reached$ overburning happens. This is visuali3ed by a red color. The M(Z=C(>(C5TL is the ma+imum capacity of a medium.
Qnu 1 X ,I-,. ,%-$,. ,##-,. ,0$$,. ,0I-,. ,E-$,. ,-#-,. ,H$$,. ,HI-, Y
))
-e get the width of the widget. The width of the custom widget is dynamic. It can be resi3ed by a user.
till 1 ::w / M(Z=C(>(C5TL< W slid=width<.to=! !ull 1 ::w / M(Z=C(>(C5TL< W KSAA=C(>(C5TL<.to=!
-e use the w variable to do the transformations. =etween the values of the scale and the custom widgetHs measures. >ote that we use floating point values. -e get greater precision in drawing.
painter.set>en QredColor painter.setBrush Qt::Brush.new QredColor painter.drawRect Qt::RectK.new !ullU%. $. till;!ull. >(@8A=78527T
These three lines draw the red rectangle$ indicating the overburning.
painter.drawRect $. $. w;%. >(@8A=78527T;%
.ere we draw the numbers of the scale. To precisely position the numbers$ we must get the width of the string.
Qwid+et 1 Burnin+.new sel! hbo4.add*id+et Qwid+et. $
-e create the instance of the =urning widget and add it to the hori3ontal bo+.
de! onChan+ed /al Qcur=width 1 /al Qwid+et.repaint end
-hen the value of the slider changes$ we store it inside the Qcur=width variable and repaint the custom widget.
de! +etCurrent*idth return Qcur=width end
This method is called by the custom widget to get the actual slider value.
)8
0igure1 The =urning widget In this part of the Ruby Qt tutorial$ we have demonstrated how to create a custom widget.
Nibbles
In this part of the Ruby Qt programming tutorial$ we will create a >ibbles game clone. Nibbles is an older classic video game. It was first created in late ;:s. 6ater it was brought to A7s. In this game the player controls a snake. The ob*ective is to eat as many apples as possible. #ach time the snake eats an apple$ its body grows. The snake must avoid the walls and its own body.
&e(elopment
The si3e of each of the *oints of a snake is ':p+. The snake is controlled with the cursor keys. Initially$ the snake has three *oints. The game starts immediately. -hen the game is finished$ we display GGame %verG message in the center of the window. =oard.rb
*56T7 1 0$$ 78527T 1 0$$ 6CT="5Z8 1 %$ (AA=6CT" 1 *56T7 W 78527T / :6CT="5Z8 W 6CT="5Z8< R(@6=>C" 1 #P 68A(L 1 %E$ B4 1 X$Y W (AA=6CT" By 1 X$Y W (AA=6CT" class Board ) Qt::*id+et de! initialize:parent< super:parent< setKocus>olicy Qt::"tron+Kocus init2a e end
);
de! init2a e Qle!t 1 !alse Qri+ht 1 true Qup 1 !alse Qdown 1 !alse Qin2a e 1 true Qdots 1 0 be+in Qball 1 Qt::5 a+e.new ,dot.pn+, Qapple 1 Qt::5 a+e.new ,apple.pn+, Qhead 1 Qt::5 a+e.new ,head.pn+, rescue puts ,cannot load i a+es, end !or i in :$..Qdots< B4XiY 1 -$ ; i W %$ ByXiY 1 -$ end locate(pple set"tyle"heet ,Q*id+et D bac9+round;color: #$$$$$$ F, Qti er 1 Qt::BasicTi er.new Qti er.start:%E$. sel!< end de! paint8/ent e/ent painter 1 Qt::>ainter.new painter.be+in sel! i! Qin2a e drawCbGects painter else +a eC/er painter end end painter.end
de! drawCbGects painter painter.draw5 a+e Qapple=4. Qapple=y. Qapple !or z in :$..Qdots< i! z 11 $ painter.draw5 a+e B4XzY. ByXzY. Qhead else painter.draw5 a+e B4XzY. ByXzY. Qball end end end de! +a eC/er painter
)<
s+ 1 ,2a e C/er, s all 1 Qt::Kont.new ,7el/etica,. %#. Qt::Kont::Bold./alue etr 1 Qt::KontMetrics.new s all te4t*idth 1 h 1 hei+ht w 1 width etr.width s+
painter.set>en Qt::Color.new Qt::white painter.setKont s all painter.translate Qt::>oint.new w/#. h/# painter.drawTe4t ;te4t*idth/#. $. s+ end de! chec9(pple i! B4X$Y 11 Qapple=4 and ByX$Y 11 Qapple=y Qdots 1 Qdots U % locate(pple end o/e z 1 Qdots while z V B4XzY ByXzY z 1 z end $ 1 B4X:z ; %<Y 1 ByX:z ; %<Y ; %
end de!
i! Qle!t B4X$Y ;1 6CT="5Z8 end i! Qri+ht B4X$Y U1 6CT="5Z8 end i! Qup ByX$Y ;1 6CT="5Z8 end i! Qdown ByX$Y U1 6CT="5Z8 end end de! chec9Collision z 1 Qdots while z V $ i! z V E and B4X$Y 11 B4XzY and ByX$Y 11 ByXzY Qin2a e 1 !alse
)(
end z 1 z ; % end i! ByX$Y V 78527T Qin2a e 1 !alse end i! ByX$Y ) $ Qin2a e 1 !alse end i! B4X$Y V *56T7 Qin2a e 1 !alse end i! B4X$Y ) $ Qin2a e 1 !alse end end de! locate(pple r 1 rand Qapple=4 r 1 rand Qapple=y R(@6=>C" 1 r W 6CT="5Z8 R(@6=>C" 1 r W 6CT="5Z8
end
de! ti er8/ent e/ent i! Qin2a e chec9(pple chec9Collision o/e else Qti er.stop end repaint end de! 9ey>ress8/ent e/ent 9ey 1 e/ent.9ey i! 9ey 11 Qle!t Qup 1 Qdown end Qt::Jey=Ae!t./alue and not Qri+ht 1 true !alse 1 !alse
i! 9ey 11 Qt::Jey=Ri+ht./alue and not Qle!t Qri+ht 1 true Qup 1 !alse Qdown 1 !alse end i! 9ey 11 Qt::Jey=Sp./alue and not Qdown
8:
end
i! 9ey 11 Qt::Jey=6own./alue and not Qup Qdown 1 true Qri+ht 1 !alse Qle!t 1 !alse end end end
0irst we will define some constants used in our game. The *56T7 and 78527T constants determine the si3e of the =oard. The 6CT="5Z8 is the si3e of the apple and the dot of the snake. The (AA=6CT" constant defines the ma+imum number of possible dots on the =oard. The R(@6=>C" constant is used to calculate a random position of an apple. The 68A(L constant determines the speed of the game.
B4 1 X$Y W (AA=6CT" By 1 X$Y W (AA=6CT"
These two arrays store +$ y coordinates of all possible *oints of a snake. The init2a e method initiali3es variables$ loads images and starts a timeout function.
i! Qin2a e drawCbGects painter else +a eC/er painter end
Inside the paint8/ent method$ we check the Qin2a e variable. If it is true$ we draw our ob*ects. The apple and the snake *oints. %therwise we display GGame overG te+t.
de! drawCbGects painter painter.draw5 a+e Qapple=4. Qapple=y. Qapple !or z in :$..Qdots< i! z 11 $ painter.draw5 a+e B4XzY. ByXzY. Qhead else painter.draw5 a+e B4XzY. ByXzY. Qball end end end
The drawCbGects method draws the apple and the *oints of the snake. The first *oint of a snake is its head$ which is represented by a red circle.
de! chec9(pple i! B4X$Y 11 Qapple=4 and ByX$Y 11 Qapple=y Qdots 1 Qdots U %
8'
end end
locate(pple
The chec9(pple method checks$ if the snake has hit the apple ob*ect. If so$ we add another snake *oint and call the locate(pple method$ which randomly places a new apple ob*ect. In the o/e method we have the key algorithm of the game. To understand it$ look at how the snake is moving. Bou control the head of the snake. Bou can change its direction with the cursor keys. The rest of the *oints move one position up the chain. The second *oint moves where the first was$ the third *oint where the second was etc.
while z V B4XzY ByXzY z 1 z end $ 1 B4X:z ; %<Y 1 ByX:z ; %<Y ; %
&ove the head to the left. In the chec9Collision method$ we determine if the snake has hit itself or one of the walls.
while z V $ i! z V E and B4X$Y 11 B4XzY and ByX$Y 11 ByXzY Qin2a e 1 !alse end z 1 z ; % end
0inish the game$ if the snake hits one of its *oints with the head.
i! ByX$Y V 78527T Qin2a e 1 !alse end
0inish the game$ if the snake hits the bottom of the =oard. The locate(pple method locates an apple randomly on the board.
r 1 rand R(@6=>C"
#very '5: ms$ the ti er8/ent method is called. If we are in the game$ we call three methods$ that build the logic of the game. %therwise we stop the timer. In the 9ey>ress8/ent method of the =oard class$ we determine the keys that were pressed.
i! 9ey 11 Qle!t Qup 1 Qdown end Qt::Jey=Ae!t./alue and not Qri+ht 1 true !alse 1 !alse
If we hit the left cursor key$ we set Qle!t variable to true. This variable is used in the o/e method to change coordinates of the snake ob*ect. >otice also$ that when the snake is heading to the right$ we cannot turn immediately to the left. >ibbles.rb
#!/usr/bin/ruby # # # # # # # # ZetCode Ruby Qt tutorial 5n this pro+ra . we create a @ibbles +a e clone. author: Jan Bodnar website: www.zetcode.co last odi!ied: "epte ber #$%#
re&uire 'Qt' re&uire 'Board' class Qt(pp ) Qt::Main*indow de! initialize super set*indowTitle ,@ibbles, setCentral*id+et Board.new:sel!< resize 0%$. 0%$ o/e 0$$. 0$$ end end app 1 Qt::(pplication.new (R23 Qt(pp.new app.e4ec show
82
0igure1 >ibbles This was the >ibbles computer game programmed with the Qt library and the Ruby programming language.
85