You are on page 1of 69

Introduction to PyQt4 toolkit

About this tutorial


This is an introductory PyQt4 tutorial. The purpose of this tutorial is to get
you started with the PyQt4 toolkit. The tutorial has been created and tested on
Linux.
About PyQt
PyQt is a toolkit for creating GI applications. It is a blending of python
progra!!ing language and the successfull Qt library. Qt library is one of the
!ost powerful libraries on this planet. If not the !ost powerful. The official
ho!e site for PyQt is on www.ri"erbankco!puting.co.uk It was de"eloped by Phil
Tho!pson.
PyQt is i!ple!ented as a set of python !odules. It has o"er #$$ classes and
al!ost %$$$ functions and !ethods. It is a !ultiplatfor! toolkit. It runs on all
!a&or operating syste!s. Including nix' (indows and )ac. PyQt is dual licenced.
*e"elopers can choose between GPL and co!!ercial licence. Pre"iously' GPL
"ersion was a"ailable only on nix. +tarting fro! PyQt "ersion 4' GPL licence is
a"ailable on all supported platfor!s.
,ecause there are a lot of classes a"ailable' they ha"e been di"ided into
se"eral !odules.

-igure. PyQt4 )odules
The Qt/ore !odule contains the core non0gui functionality. This !odule is used
for working with ti!e' files and directories' "arious data types' strea!s' urls'
!i!e types' threads or processes. The QtGui !odule contains the graphical
co!ponents and related classes. These include for exa!ple buttons' windows'
status bars' toolbars' sliders' bit!aps' colors' fonts etc. The Qt1etwork
!odule contains the classes for network progra!!ing. These classes allow to
write T/P2IP and *P clients and ser"ers. They !ake the network progra!!ing
easier and !ore portable. The Qt3!l contains classes for working with x!l
files. This !odule pro"ides i!ple!entation for both +A3 and *4) APIs. The Qt+"g
!odule pro"ides classes for displaying the contents of +5G files. +calable
5ector Graphics 6+5G7 is a language for describing two0di!ensional graphics and
graphical applications in 3)L. The Qt4penGL !odule is used for rendering #*
and 8* graphics using the 4penGL library. The !odule enables sea!less
integration of the Qt GI libary and the 4penGL library. The Qt+9l !odule
pro"ides classes for working with databases.
Python
Python is a successful scripting language. It was initially
de"eloped by Guido "an :ossu!. It was first released in
;<<;. Python was inspired by A,/ and =askell progra!!ing
languages. Python is a high le"el' general purpose'
!ultiplatfor!' interpreted language. +o!e prefer to call it a
dyna!ic language. It is easy to learn. Python is a
!ini!alistic language. 4ne of it>s !ost "isible features is
that it does not use se!icolons nor brackets. Python uses
intendation instead. The !ost recent "ersion of python is 8.?' which was
released in +epte!ber 8$$%. Today' Python is !aintained by a large group of
"olunteers worldwide.
The TI4,@ Progra!!ing /o!!unity Index gi"es us a theoretical usage of "arious
progra!!ing languages. Aa"a rules. The /BB language is detroned. ,ut /BB will
continue to be used in it>s footholds for the co!ing decades and ther see!s to
be no real threat for it. (e can clearly see specialiCation a!ong progra!!ing
languages. Aa"a is used !ainly in enterprise pro&ects and portables' / is the
king in syste! progra!!ing 64+' de"ice dri"ers' s!all apps7' P=P rules a!ong
s!all to !ediu! siCe web sites' Aa"asript is used on the client site of a web
application.
Position Language :atings
; Aa"a 8;.DE
8 / ;4.<E
# 5isual ,asic ;$.DE
4 P=P ;$.8E
? /BB <.<E
% Perl ?.4E
D /F #.4E
G Python #.$E
< Aa"a+cript 8.DE
;$ :uby 8.$E
Python is currently nu!ber G. The :uby language has !ade into the toplist. The
closest co!petitors to Python are :uby and Perl.
Python toolkits
-or creating graphical user interfaces' python progra!!ers can choose a!ong
three decent options. PyGTH' wxPython and PyQt. (hich toolkit to choose' depends
on the circu!stances. There is also another IoptionI' called TkInter. A"oid.
-irst progra!s in PyQt4 toolkit
In this part of the PyQt4 tutorial we will learn so!e basic functionality. The
explanation will be slow' as if we would talk to a child. The first steps of a
child are awkward' so are the "ery first atte!pts of a newbie progra!!er.
:e!e!ber' there are no stupid people. There are only laCy people and people'
that are not persistent enough.
+i!ple exa!ple
The code exa!ple is "ery si!plistic. It only shows a s!all window. Jet we can do
a lot with this window. (e can resiCe it. )axi!iCe it. )ini!iCe it. This
re9uires a lot of coding. +o!eone already coded this functionality. ,ecause it
repeats in !ost applications' there is no need to code it o"er again +o it has
been hidden fro! a progra!!er. PyQt is a high le"el toolkit. If we would code in
a lower le"el toolkit' the following code exa!ple could easily ha"e doCens of
lines.
#!/usr/bin/python
# simple.py
import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv
!i"get = QtGui.Q#i"get(
!i"get.resi$e(%&'( )&'
!i"get.set#in"o!*itle(+simple+
!i"get.sho!(
sys.e,it(app.e,ec-(
import sys
from PyQt4 import QtGui
=ere we pro"ide the necessary i!ports. The basic GI widgets are located in
QtGui !odule.
app = QtGui.QApplication(sys.argv
@"ery PyQt4 application !ust create an application ob&ect. The application
ob&ect is located in the QtGui !odule. The sys.arg" para!eter is a list of
argu!ents fro! the co!!and line. Python scripts can be run fro! the shell. It is
a way' how we can control the startup of our scripts.
!i"get = QtGui.Q#i"get(
The Q(idget widget is the base class of all user interface ob&ects in PyQt4. (e
pro"ide the default constructor for Q(idget. The default constructor has no
parent. A widget with no parent is called a window.
!i"get.resi$e(%&'( )&'
The resiCe67 !ethod resiCes the widget. It is 8?$px wide and ;?$px high.
!i"get.set#in"o!*itle(+simple+
=ere we set the title for our window. The title is shown in the titlebar.
!i"get.sho!(
The show67 !ethod displays the widget on the screen.
sys.e,it(app.e,ec-(
-inally' we enter the !ainloop of the application. The e"ent handling starts
fro! this point. The !ainloop recei"es e"ents fro! the window syste! and
dispatches the! to the application widgets. The !ainloop ends' if we call the
exit67 !ethod or the !ain widget is destroyed. The sys.exit67 !ethod ensures a
clean exit. The en"iron!ent will be infor!ed' how the application ended.
Jou wonder why the execK67 !ethod has the underscoreL @"erything has a !eaning.
This is ob"iously because the exec is a python keyword. And thus' execK67 was
used instead.

-igure. +i!ple
An application icon
The application icon is a s!all i!age' which is usually displayed in the top
left corner of the titlebar. In the following exa!ple we will show' how we do it
in PyQt4. (e will also introduce so!e new !ethods.
#!/usr/bin/python
# icon.py
import sys
from PyQt4 import QtGui
class .con(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+.con+
self.set#in"o!.con(QtGui.Q.con(+icons/!eb.png+
app = QtGui.QApplication(sys.argv
icon = .con(
icon.sho!(
sys.e,it(app.e,ec-(
The pre"ious exa!ple was coded in a procedural style. Python progra!!ing
language supports both procedural and ob&ect oriented progra!!ing styles.
Progra!!ing in PyQt4 !eans progra!!ing in 44P.
class .con(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
The three !ost i!portant things in ob&ect oriented progra!!ing are classes' data
and !ethods. =ere we create a new class called Icon. The Icon class inherits
fro! QtGui.Q(idget class. This !eans' that we !ust call two constructors. The
first one for the Icon class and the second one for the inherited class.
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+.con+
self.set#in"o!.con(QtGui.Q.con(+icons/!eb.png+
All three classes ha"e been inherited fro! the QtGui.Q(idget class. The
setGeo!etry67 does two things. It locates the window on the screen and sets the
siCe of the window. The first two para!eters are the x and y positions of the
window. The third is the width and the fourth is the height of the window. The
last !ethod sets the application icon. To do this' we ha"e created a QIcon
ob&ect. The QIcon recei"es the path to our icon to be displayed.

-igure. Icon
+howing a tooltip
(e can pro"ide a balloon help for any of our widgets.
#!/usr/bin/python
# tooltip.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class *ooltip(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+*ooltip+
self.set*ool*ip(+*his is a 3b4Q#i"get3/b4 !i"get+
QtGui.Q*ool*ip.set5ont(QtGui.Q5ont(+6l"7nglish+( )'
app = QtGui.QApplication(sys.argv
tooltip = *ooltip(
tooltip.sho!(
sys.e,it(app.e,ec-(
In this exa!ple' we show a tooltip for a Q(idget widget.
self.set*ool*ip(+*his is a 3b4Q#i"get3/b4 !i"get+
To create a tooltip' we call the setTooltip67 !ethod. (e can use rich text
for!atting.
QtGui.Q*ool*ip.set5ont(QtGui.Q5ont(+6l"7nglish+( )'
,ecause the default QToolTip font looks bad' we change it.

-igure. Tooltip
/losing a window
The ob"ious way to how to close a window is to click on the x !ark on the
titlebar. In the next exa!ple' we will show' how we can progra!atically close
our window. (e will briefly touch signals and slots.
The following is the constructor of a QPush,utton' that we will use in our
exa!ple.
QPush8utton(string te,t( Q#i"get parent = 0one
The text para!eter is a text that will be displayed on the button. The parent is
the ancestor' onto which we place our button. In our case it is Q(idget.
#!/usr/bin/python
# 9uitbutton.py
import sys
from PyQt4 import QtGui( Qt2ore
class Quit8utton(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+.con+
9uit = QtGui.QPush8utton(+2lose+( self
9uit.setGeometry()'( )'( :'( 1&
self.connect(9uit( Qt2ore.;.G0A<(+clic=e"(+(
QtGui.9App( Qt2ore.;<6*(+9uit(+
app = QtGui.QApplication(sys.argv
9b = Quit8utton(
9b.sho!(
sys.e,it(app.e,ec-(
9uit = QtGui.QPush8utton(+2lose+( self
9uit.setGeometry()'( )'( :'( 1&
(e create a push button and position it on the Q(idget &ust like we ha"e
positioned the Q(idget on the screen.
self.connect(9uit( Qt2ore.;.G0A<(+clic=e"(+(
QtGui.9App( Qt2ore.;<6*(+9uit(+
The e"ent processing syste! in PyQt4 is built with the signal M slot !echanis!.
If we click on the button' the signal clicked67 is e!itted. The slot can be a
PyQt slot or any python callable. The Qt/ore.Q4b&ect.connect67 !ethod connects
signals with slots. In our case the slot is a predefined PyQt 9uit67 slot. The
co!!unication is done between two ob&ects. The sender and the recei"er. The
sender is the push button' the recei"er is the application ob&ect.

-igure. 9uit button
)essage ,ox
,y default' if we click on the x button on the titlebar' the Q(idget is closed.
+o!eti!es we want to !odify this default beha"iour. -or exa!ple' if we ha"e a
file opened in an editor to which we did so!e changes. (e show a !essage box to
confir! the action.
#!/usr/bin/python
# messagebo,.py
import sys
from PyQt4 import QtGui
class >essage8o,(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+message bo,+
"ef close7vent(self( event/
reply = QtGui.Q>essage8o,.9uestion(self( +>essage+(
?Are you sure to 9uit@?( QtGui.Q>essage8o,.Aes(
QtGui.Q>essage8o,.0o
if reply == QtGui.Q>essage8o,.Aes/
event.accept(
else/
event.ignore(
app = QtGui.QApplication(sys.argv
9b = >essage8o,(
9b.sho!(
sys.e,it(app.e,ec-(
If we close the Q(idget' the Q/lose@"ent is generated. To !odify the widget
beha"iour we need to rei!ple!ent the close@"ent67 e"ent handler.
reply = QtGui.Q>essage8o,.9uestion(self( +>essage+(
?Are you sure to 9uit@?( QtGui.Q>essage8o,.Aes( QtGui.Q>essage8o,.0o
(e show a !essage box with two buttons. Jes and 1o. The first string appears on
the titlebar. The second string is the !essage text displayed by the dialog. The
return "alue is stored in the reply "ariable.
if reply == QtGui.Q>essage8o,.Aes/
event.accept(
else/
event.ignore(
=ere we test the return "alue. If we clicked Jes button' we accept the e"ent
which leads to the closure of the widget and to the ter!ination of the
application. 4therwise we ignore the close e"ent.

-igure. !essage box
/entering window on the screen
The following script shows' how we can center a window on the desktop screen.
#!/usr/bin/python
# center.py
import sys
from PyQt4 import QtGui
class 2enter(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+center+
self.resi$e(%&'( )&'
self.center(
"ef center(self/
screen = QtGui.QBes=top#i"get(.screenGeometry(
si$e = self.geometry(
self.move((screen.!i"th(Csi$e.!i"th(/%( (screen.height(C
si$e.height(/%
app = QtGui.QApplication(sys.argv
9b = 2enter(
9b.sho!(
sys.e,it(app.e,ec-(
self.resi$e(%&'( )&'
=ere we resiCe the Q(idget to be 8?$px wide and ;?$px heigh.
screen = QtGui.QBes=top#i"get(.screenGeometry(
(e figure out the screen resolution of our !onitor.
si$e = self.geometry(
=ere we get the siCe of our Q(idget.
self.move((screen.!i"th(Csi$e.!i"th(/%( (screen.height(Csi$e.height(/%
=ere we !o"e the window to the center of the screen.
)enus and Toolbars in PyQt4
)ain (indow
The Q)ain(indow class pro"ides a !ain application window. This enables to create
the classic application skeleton with a statusbar' toolbars and a !enubar.
+tatusbar
The statusbar is a widget that si used for displaying status infor!ation.
#!/usr/bin/python
# statusbar.py
import sys
from PyQt4 import QtGui
class >ain#in"o!(QtGui.Q>ain#in"o!/
"ef --init--(self/
QtGui.Q>ain#in"o!.--init--(self
self.resi$e(%&'( )&'
self.set#in"o!*itle(+statusbar+
self.status8ar(.sho!>essage(+Dea"y+
app = QtGui.QApplication(sys.argv
main = >ain#in"o!(
main.sho!(
sys.e,it(app.e,ec-(
self.status8ar(.sho!>essage(+Dea"y+
To get the statusbar' we call the status,ar67 !ethod of the QApplication class.
The show)essage67 displays !essage on the statusbar.
)enubar
A !enubar is one of the !ost "isible parts of the GI application. It is a group
of co!!ands located in "arious !enus. (hile in console applications you had to
re!e!ber all those arcane co!!ands' here we ha"e !ost of the co!!ands grouped
into logical parts. There are accepted standards that further reduce the a!ount
of ti!e spending to learn a new application.
#!/usr/bin/python
# menubar.py
import sys
from PyQt4 import QtGui( Qt2ore
class >ain#in"o!(QtGui.Q>ain#in"o!/
"ef --init--(self/
QtGui.Q>ain#in"o!.--init--(self
self.resi$e(%&'( )&'
self.set#in"o!*itle(+menubar+
e,it = QtGui.QAction(QtGui.Q.con(+icons/e,it.png+( +7,it+( self
e,it.set;hortcut(+2trlEQ+
e,it.set;tatus*ip(+7,it application+
self.connect(e,it( Qt2ore.;.G0A<(+triggere"(+( Qt2ore.;<6*(+close(+
self.status8ar(
menubar = self.menu8ar(
file = menubar.a"">enu(+F5ile+
file.a""Action(e,it
app = QtGui.QApplication(sys.argv
main = >ain#in"o!(
main.sho!(
sys.e,it(app.e,ec-(
menubar = self.menu8ar(
file = menubar.a"">enu(+F5ile+
file.a""Action(e,it
-irst we create a !enubar with the !enu,ar67 !ethod of the Q)ain(indow class.
Then we add a !enu with the Add)enu67 !ethod. In the end we plug the action
ob&ect into the file !enu.
Toolbar
)enus group all co!!ands that we can use in an application. Toolbars pro"ide a
9uick access to the !ost fre9uently used co!!ands.
#!/usr/bin/python
# toolbar.py
import sys
from PyQt4 import QtGui( Qt2ore
class >ain#in"o!(QtGui.Q>ain#in"o!/
"ef --init--(self/
QtGui.Q>ain#in"o!.--init--(self
self.resi$e(%&'( )&'
self.set#in"o!*itle(+toolbar+
self.e,it = QtGui.QAction(QtGui.Q.con(+icons/e,it.png+( +7,it+( self
self.e,it.set;hortcut(+2trlEQ+
self.connect(self.e,it( Qt2ore.;.G0A<(+triggere"(+(
Qt2ore.;<6*(+close(+
self.toolbar = self.a""*ool8ar(+7,it+
self.toolbar.a""Action(self.e,it
app = QtGui.QApplication(sys.argv
main = >ain#in"o!(
main.sho!(
sys.e,it(app.e,ec-(
self.e,it = QtGui.QAction(QtGui.Q.con(+icons/e,it.png+( +7,it+( self
self.e,it.set;hortcut(+2trlEQ+
GI applications are controlled with co!!ands. These co!!ands can be launched
fro! a !enu' a context !enu' a toolbar or with a shortcut. PyQt si!plifies
de"elop!ent with the introduction of actions. An action ob&ect can ha"e !enu
text' an icon' a shortcut' status text' I(hat>s ThisLI text and a tooltip. In
our exa!ple' we define an action ob&ect with an icon' a tooltip and a shortcut.
self.connect(self.e,it( Qt2ore.;.G0A<(+triggere"(+( Qt2ore.;<6*(+close(+
=ere we connect the action>s triggered67 signal to the predefined close67
signal.
self.toolbar = self.a""*ool8ar(+7,it+
self.toolbar.a""Action(self.e,it
=ere we create a toolbar and plug and action ob&ect into it.

-igure. toolbar
Putting it together
In the last exa!ple of this section' we will create a !enubar' toolbar and a
statusbar. (e will also create a central widget.
#!/usr/bin/python
# main!in"o!.py
import sys
from PyQt4 import QtGui( Qt2ore
class >ain#in"o!(QtGui.Q>ain#in"o!/
"ef --init--(self/
QtGui.Q>ain#in"o!.--init--(self
self.resi$e(1&'( %&'
self.set#in"o!*itle(+main!in"o!+
te,t7"it = QtGui.Q*e,t7"it(
self.set2entral#i"get(te,t7"it
e,it = QtGui.QAction(QtGui.Q.con(+icons/e,it.png+( +7,it+( self
e,it.set;hortcut(+2trlEQ+
e,it.set;tatus*ip(+7,it application+
self.connect(e,it( Qt2ore.;.G0A<(+triggere"(+( Qt2ore.;<6*(+close(+
self.status8ar(
menubar = self.menu8ar(
file = menubar.a"">enu(+F5ile+
file.a""Action(e,it
toolbar = self.a""*ool8ar(+7,it+
toolbar.a""Action(e,it
app = QtGui.QApplication(sys.argv
main = >ain#in"o!(
main.sho!(
sys.e,it(app.e,ec-(
te,t7"it = QtGui.Q*e,t7"it(
self.set2entral#i"get(te,t7"it
=ere we create a text edit widget. (e set it to be the central widget of the
Q)ain(indow. The central widget will occupy all space that is left.

-igure. !ainwindow
Layout !anage!ent in PyQt4
I!portant thing in progra!!ing is the layout !anage!ent. Layout !anage!ent is
the way how we place the widgets on the window. The !anage!ent can be done in
two ways. (e can use absolute positioning or layout classes.
Absolute positioning
The progra!!er specifies the position and the siCe of each widget in pixels.
(hen you use absolute positioning' you ha"e to understand se"eral things.
the siCe and the position of a widget do not change' if you resiCe a
window
applications !ight look different on "arious platfor!s
changing fonts in your application !ight spoil the layout
if you decide to change your layout' you !ust co!pletely redo your layout'
which is tedious and ti!e consu!ing
#!/usr/bin/python
# absolute.py
import sys
from PyQt4 import QtGui
class Absolute(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+2ommunication+
label = QtGui.Q<abel(+2oul"nG+t+( self
label.move()&( )'
label = QtGui.Q<abel(+care+( self
label.move(1&( 4'
label = QtGui.Q<abel(+less+( self
label.move(&&( :&
label = QtGui.Q<abel(+An"+( self
label.move())&( :&
label = QtGui.Q<abel(+then+( self
label.move()1&( 4&
label = QtGui.Q<abel(+you+( self
label.move())&( %&
label = QtGui.Q<abel(+=isse"+( self
label.move()4&( )'
label = QtGui.Q<abel(+me+( self
label.move(%)&( )'
self.resi$e(%&'( )&'
app = QtGui.QApplication(sys.argv
9b = Absolute(
9b.sho!(
sys.e,it(app.e,ec-(
(e si!ply call the !o"e67 !ethod to position our widgets. In our case QLabel0s.
(e position the! by pro"iding the x and the y coordinates. The beginning of the
coordinate syste! is at the left top corner. The x "alues grow fro! left to
right. The y "alues grow fro! top to botto!.

-igure. absolute positioning
,ox Layout
Layout !anage!ent with layout classes is !uch !ore flexible and practical. It is
the preferred way to place widgets on a window. The basic layout classes are
Q=,oxLayout and Q5,oxLayout. They line up widgets horiContally and
"ertically.
I!agine that we wanted to place two buttons in the right botto! corner. To
create such a layout' we will use one horiContal and one "ertical box. To create
the neccessary space' we will add a stretch factor.
#!/usr/bin/python
# bo,layout.py
import sys
from PyQt4 import QtGui
class 8o,<ayout(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+bo, layout+
o= = QtGui.QPush8utton(?6H?
cancel = QtGui.QPush8utton(?2ancel?
hbo, = QtGui.QI8o,<ayout(
hbo,.a"";tretch()
hbo,.a""#i"get(o=
hbo,.a""#i"get(cancel
vbo, = QtGui.QJ8o,<ayout(
vbo,.a"";tretch()
vbo,.a""<ayout(hbo,
self.set<ayout(vbo,
self.resi$e(1''( )&'
app = QtGui.QApplication(sys.argv
9b = 8o,<ayout(
9b.sho!(
sys.e,it(app.e,ec-(
o= = QtGui.QPush8utton(?6H?
cancel = QtGui.QPush8utton(?2ancel?
=ere we create two push buttons.
hbo, = QtGui.QI8o,<ayout(
hbo,.a"";tretch()
hbo,.a""#i"get(o=
hbo,.a""#i"get(cancel
(e create a horiContal box layout. Add a stretch factor and both buttons.
vbo, = QtGui.QJ8o,<ayout(
vbo,.a"";tretch()
vbo,.a""<ayout(hbo,
To create the necessary layout' we put a horiContal lauout into a "ertical one.
self.set<ayout(vbo,
-inally' we set the !ain layout of the window.

-igure. box layout
QGridLayout
The !ost uni"ersal layout class is the grid layout. This layout di"ides the
space into rows and colu!ns. To create a grid layout' we use the QGridLayout
class.
#!/usr/bin/python
# gri"layout.py
import sys
from PyQt4 import QtGui
class Gri"<ayout(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+gri" layout+
names = K+2ls+( +8c=+( ++( +2lose+( +L+( +M+( +N+( +/+(
+4+( +&+( +:+( +O+( +)+( +%+( +1+( +C+(
+'+( +.+( +=+( +E+P
gri" = QtGui.QGri"<ayout(
Q = '
pos = K('( '( ('( )( ('( %( ('( 1(
()( '( ()( )( ()( %( ()( 1(
(%( '( (%( )( (%( %( (%( 1(
(1( '( (1( )( (1( %( (1( 1 (
(4( '( (4( )( (4( %( (4( 1P
for i in names/
button = QtGui.QPush8utton(i
if Q == %/
gri".a""#i"get(QtGui.Q<abel(++( '( %
else/ gri".a""#i"get(button( posKQPK'P( posKQPK)P
Q = Q E )
self.set<ayout(gri"
app = QtGui.QApplication(sys.argv
9b = Gri"<ayout(
9b.sho!(
sys.e,it(app.e,ec-(
In our exa!ple' we create a grid of buttons. To fill one gap' we add one QLabel
widget.
gri" = QtGui.QGri"<ayout(
=ere we create a grid layout.
if Q == %/
gri".a""#i"get(QtGui.Q<abel(++( '( %
else/ gri".a""#i"get(button( posKQPK'P( posKQPK)P
To add a widget to a grid' we call the add(idget67 !ethod. The argu!ents are the
widget' the row and the colu!n nu!ber.

-igure. grid layout
(idgets can span !ultiple colu!ns or rows in a grid. In the next exa!ple we
illustrate this.
#!/usr/bin/python
# gri"layout%.py
import sys
from PyQt4 import QtGui
class Gri"<ayout%(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+gri" layout+
title = QtGui.Q<abel(+*itle+
author = QtGui.Q<abel(+Author+
revie! = QtGui.Q<abel(+Devie!+
title7"it = QtGui.Q<ine7"it(
author7"it = QtGui.Q<ine7"it(
revie!7"it = QtGui.Q*e,t7"it(
gri" = QtGui.QGri"<ayout(
gri".set;pacing()'
gri".a""#i"get(title( )( '
gri".a""#i"get(title7"it( )( )
gri".a""#i"get(author( %( '
gri".a""#i"get(author7"it( %( )
gri".a""#i"get(revie!( 1( '
gri".a""#i"get(revie!7"it( 1( )( &( )
self.set<ayout(gri"
self.resi$e(1&'( 1''
app = QtGui.QApplication(sys.argv
9b = Gri"<ayout%(
9b.sho!(
sys.e,it(app.e,ec-(
gri" = QtGui.QGri"<ayout(
gri".set;pacing()'
(e create a grid layout and set spacing between widgets.
gri".a""#i"get(revie!7"it( 1( )( &( )
If we add a widget to a grid' we can pro"ide row span and colu!n span of the
widget. In our case' we !ake the re"iew@dit widget span ? rows.
@"ents and +ignals in PyQt4
In this part of the PyQt4 progra!!ing tutorial' we will explore e"ents and
singnals occuring in applications.
@"ents
@"ents are an i!portant part in any GI progra!. @"ents are generated by users
or by the syste!. (hen we call the application>s execK67 !ethod' the application
enters the !ain loop. The !ain loop fetches e"ents and sends the! to the
ob&ects. Trolltech has introduced a uni9ue signal and slot !echanis!.
+ignals M +lots
+ignals are e!itted' when users click on the button' drag a slider etc. +ignals
can be e!itted also by the en"iron!ent. -or exa!ple' when a clock ticks. A slot
is a !ethod' that reacts to a signal. In python' a slot can be any python
callable.
#!/usr/bin/python
# sigslot.py
import sys
from PyQt4 import QtGui( Qt2ore
class ;ig;lot(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+signal F slot+
lc" = QtGui.Q<2B0umber(self
sli"er = QtGui.Q;li"er(Qt2ore.Qt.Iori$ontal( self
vbo, = QtGui.QJ8o,<ayout(
vbo,.a""#i"get(lc"
vbo,.a""#i"get(sli"er
self.set<ayout(vbo,
self.connect(sli"er( Qt2ore.;.G0A<(+value2hange"(int+( lc"(
Qt2ore.;<6*(+"isplay(int+
self.resi$e(%&'( )&'
app = QtGui.QApplication(sys.argv
9b = ;ig;lot(
9b.sho!(
sys.e,it(app.e,ec-(
In our exa!ple' we display an lcd nu!ber and a slider. (e change the lcd nu!ber
by dragging the slider.
self.connect(sli"er( Qt2ore.;.G0A<(+value2hange"(int+( lc"(
Qt2ore.;<6*(+"isplay(int+
=ere we connect a "alue/hanged67 signal of the slider to the display67 slot of
the lcd nu!ber.
The connect !ethod has four para!eters. The sender is an ob&ect that sends a
signal. The signal is the signal' which is e!itted. The recei"er is the
ob&ect' that recei"es the signal. -inally the slot is the !ethod' that reacts
to the signal.

-igure. signal M slot
:ei!ple!enting e"ent handler
@"ents in PyQt are processed !ainly by rei!ple!enting e"ent handlers .
#!/usr/bin/python
# escape.py
import sys
from PyQt4 import QtGui( Qt2ore
class 7scape(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+escape+
self.resi$e(%&'( )&'
self.connect(self( Qt2ore.;.G0A<(+close7mitApp(+(
Qt2ore.;<6*(+close(+
"ef =eyPress7vent(self( event/
if event.=ey( == Qt2ore.Qt.Hey-7scape/
self.close(
app = QtGui.QApplication(sys.argv
9b = 7scape(
9b.sho!(
sys.e,it(app.e,ec-(
In our exa!ple' we rei!ple!ent the keyPress@"ent67 e"ent handler.
"ef =eyPress7vent(self( event/
if event.=ey( == Qt2ore.Qt.Hey-7scape/
self.close(
If we click the escape button' we close the application.
@!itting signals
4b&ects created fro! Qt/ore.Q4b&ect can e!it signals. If we click on the button'
a clicked67 signal is generated. In the following exa!ple we will see' how we
can e!it signals.
#!/usr/bin/python
# emit.py
import sys
from PyQt4 import QtGui( Qt2ore
class 7mit(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+emit+
self.resi$e(%&'( )&'
self.connect(self( Qt2ore.;.G0A<(+close7mitApp(+(
Qt2ore.;<6*(+close(+
"ef mousePress7vent(self( event/
self.emit(Qt2ore.;.G0A<(+close7mitApp(+
app = QtGui.QApplication(sys.argv
9b = 7mit(
9b.sho!(
sys.e,it(app.e,ec-(
(e create a new signal called close@!itApp67. This signal is e!itted' during a
!ouse press e"ent.
"ef mousePress7vent(self( event/
self.emit(Qt2ore.;.G0A<(+close7mitApp(+
@!itting a signal with the e!it67 !ethod.
self.connect(self( Qt2ore.;.G0A<(+close7mitApp(+( Qt2ore.;<6*(+close(+
=ere we connect the !anually created close@!itApp67 signal with the close67
slot.

-igure. grid layout8
@"ents and +ignals in PyQt4
In this part of the PyQt4 progra!!ing tutorial' we will explore e"ents and
singnals occuring in applications.
@"ents
@"ents are an i!portant part in any GI progra!. @"ents are generated by users
or by the syste!. (hen we call the application>s execK67 !ethod' the application
enters the !ain loop. The !ain loop fetches e"ents and sends the! to the
ob&ects. Trolltech has introduced a uni9ue signal and slot !echanis!.
+ignals M +lots
+ignals are e!itted' when users click on the button' drag a slider etc. +ignals
can be e!itted also by the en"iron!ent. -or exa!ple' when a clock ticks. A slot
is a !ethod' that reacts to a signal. In python' a slot can be any python
callable.
#!/usr/bin/python
# sigslot.py
import sys
from PyQt4 import QtGui( Qt2ore
class ;ig;lot(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+signal F slot+
lc" = QtGui.Q<2B0umber(self
sli"er = QtGui.Q;li"er(Qt2ore.Qt.Iori$ontal( self
vbo, = QtGui.QJ8o,<ayout(
vbo,.a""#i"get(lc"
vbo,.a""#i"get(sli"er
self.set<ayout(vbo,
self.connect(sli"er( Qt2ore.;.G0A<(+value2hange"(int+( lc"(
Qt2ore.;<6*(+"isplay(int+
self.resi$e(%&'( )&'
app = QtGui.QApplication(sys.argv
9b = ;ig;lot(
9b.sho!(
sys.e,it(app.e,ec-(
In our exa!ple' we display an lcd nu!ber and a slider. (e change the lcd nu!ber
by dragging the slider.
self.connect(sli"er( Qt2ore.;.G0A<(+value2hange"(int+( lc"(
Qt2ore.;<6*(+"isplay(int+
=ere we connect a "alue/hanged67 signal of the slider to the display67 slot of
the lcd nu!ber.
The connect !ethod has four para!eters. The sender is an ob&ect that sends a
signal. The signal is the signal' which is e!itted. The recei"er is the
ob&ect' that recei"es the signal. -inally the slot is the !ethod' that reacts
to the signal.

-igure. signal M slot
:ei!ple!enting e"ent handler
@"ents in PyQt are processed !ainly by rei!ple!enting e"ent handlers .
#!/usr/bin/python
# escape.py
import sys
from PyQt4 import QtGui( Qt2ore
class 7scape(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+escape+
self.resi$e(%&'( )&'
self.connect(self( Qt2ore.;.G0A<(+close7mitApp(+(
Qt2ore.;<6*(+close(+
"ef =eyPress7vent(self( event/
if event.=ey( == Qt2ore.Qt.Hey-7scape/
self.close(
app = QtGui.QApplication(sys.argv
9b = 7scape(
9b.sho!(
sys.e,it(app.e,ec-(
In our exa!ple' we rei!ple!ent the keyPress@"ent67 e"ent handler.
"ef =eyPress7vent(self( event/
if event.=ey( == Qt2ore.Qt.Hey-7scape/
self.close(
If we click the escape button' we close the application.
@!itting signals
4b&ects created fro! Qt/ore.Q4b&ect can e!it signals. If we click on the button'
a clicked67 signal is generated. In the following exa!ple we will see' how we
can e!it signals.
#!/usr/bin/python
# emit.py
import sys
from PyQt4 import QtGui( Qt2ore
class 7mit(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.set#in"o!*itle(+emit+
self.resi$e(%&'( )&'
self.connect(self( Qt2ore.;.G0A<(+close7mitApp(+(
Qt2ore.;<6*(+close(+
"ef mousePress7vent(self( event/
self.emit(Qt2ore.;.G0A<(+close7mitApp(+
app = QtGui.QApplication(sys.argv
9b = 7mit(
9b.sho!(
sys.e,it(app.e,ec-(
(e create a new signal called close@!itApp67. This signal is e!itted' during a
!ouse press e"ent.
"ef mousePress7vent(self( event/
self.emit(Qt2ore.;.G0A<(+close7mitApp(+
@!itting a signal with the e!it67 !ethod.
self.connect(self( Qt2ore.;.G0A<(+close7mitApp(+( Qt2ore.;<6*(+close(+
=ere we connect the !anually created close@!itApp67 signal with the close67
slot.
*ialogs in PyQt4
*ialog windows or dialogs are an indispensable part of !ost !odern GI
applications. A dialog is defined as a con"ersation between two or !ore persons.
In a co!puter application a dialog is a window which is used to ItalkI to the
application. A dialog is used to input data' !odify data' change the application
settings etc. *ialogs are i!portant !eans of co!!unication between a user and a
co!puter progra!.
There are essentially two types of dialogs. Predefined dialogs and custo!
dialogs.
Predefined *ialogs
QInput*ialog
The QInput*ialog pro"ides a si!ple con"enience dialog to get a single "alue fro!
the user. The input "alue can be a string' a nu!ber or an ite! fro! a list.
#!/usr/bin/python
# input"ialog.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class .nputBialog(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( 1&'( M'
self.set#in"o!*itle(+.nputBialog+
self.button = QtGui.QPush8utton(+Bialog+( self
self.button.set5ocusPolicy(Qt2ore.Qt.0o5ocus
self.button.move(%'( %'
self.connect(self.button( Qt2ore.;.G0A<(+clic=e"(+( self.sho!Bialog
self.set5ocus(
self.label = QtGui.Q<ine7"it(self
self.label.move()1'( %%
"ef sho!Bialog(self/
te,t( o= = QtGui.Q.nputBialog.get*e,t(self( +.nput Bialog+( +7nter your
name/+
if o=/
self.label.set*e,t(unico"e(te,t
app = QtGui.QApplication(sys.argv
icon = .nputBialog(
icon.sho!(
app.e,ec-(
The exa!ple has a button and a line edit widget. The button shows the input
dialog for getting text "alues. The entered text will be displayed in the line
edit widget.
te,t( o= = QtGui.Q.nputBialog.get*e,t(self( +.nput Bialog+( +7nter your name/+
This line displays the input dialog. The first string is a dialog title' the
second one is a !essage within the dialog. The dialog returns the entered text
and a boolean "alue. If we clicked ok button' the boolean "alue is true'
otherwise false.

-igure. Input *ialog
Q/olor*ialog
The Q/olor*ialog pro"ides a dialog widget for specifying colors.
#!/usr/bin/python
# color"ialog.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class 2olorBialog(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
color = QtGui.Q2olor('( '( '
self.setGeometry(1''( 1''( %&'( )M'
self.set#in"o!*itle(+2olorBialog+
self.button = QtGui.QPush8utton(+Bialog+( self
self.button.set5ocusPolicy(Qt2ore.Qt.0o5ocus
self.button.move(%'( %'
self.connect(self.button( Qt2ore.;.G0A<(+clic=e"(+( self.sho!Bialog
self.set5ocus(
self.!i"get = QtGui.Q#i"get(self
self.!i"get.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T?
S color.name(
self.!i"get.setGeometry()1'( %%( )''( )''
"ef sho!Bialog(self/
col = QtGui.Q2olorBialog.get2olor(
if col.isJali"(/
self.!i"get.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T?
S col.name(
app = QtGui.QApplication(sys.argv
c" = 2olorBialog(
c".sho!(
app.e,ec-(
The application exa!ple shows a push button and a Q(idget. The widget background
is set to black color. sing the Q/olor*ialog' we can change its background.
color = QtGui.Q2olorBialog.get2olor(
This line will pop up the Q/olor*ialog.
if col.isJali"(/
self.!i"get.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T?
S col.name(
(e check if the color is "alid. If we click on the cancel button' no "alid color
is returned. If the color is "alid' we change the background color using
stylesheets.

-igure. /olor dialog
Q-ont*ialog
The Q-ont*ialog is a dialog widget for selecting font.
#!/usr/bin/python
# font"ialog.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class 5ontBialog(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
hbo, = QtGui.QI8o,<ayout(
self.setGeometry(1''( 1''( %&'( ))'
self.set#in"o!*itle(+5ontBialog+
button = QtGui.QPush8utton(+Bialog+( self
button.set5ocusPolicy(Qt2ore.Qt.0o5ocus
button.move(%'( %'
hbo,.a""#i"get(button
self.connect(button( Qt2ore.;.G0A<(+clic=e"(+( self.sho!Bialog
self.label = QtGui.Q<abel(+Hno!le"ge only matters+( self
self.label.move()1'( %'
hbo,.a""#i"get(self.label( )
self.set<ayout(hbo,
"ef sho!Bialog(self/
font( o= = QtGui.Q5ontBialog.get5ont(
if o=/
self.label.set5ont(font
app = QtGui.QApplication(sys.argv
c" = 5ontBialog(
c".sho!(
app.e,ec-(
In our exa!ple' we ha"e a button and a label. (ith Q-ont*ialog' we change the
font of the label.
hbo,.a""#i"get(self.label( )
(e !ake the label resiCable. It is necessary' because when we select a different
font' the text !ay beco!e larger. 4therwise the label !ight not be fully
"isible.
font( o= = QtGui.Q5ontBialog.get5ont(
=ere we pop up the font dialog.
if o=/
self.label.set5ont(font
If we clicked ok' the font of the label was changed.

-igure. -ont dialog
Q-ile*ialog
The Q-ile*ialog is a dialog that allows users to select files or directories.
The files can be selected for both opening a sa"ing.
#!/usr/bin/python
# openfile"ialog.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class 6pen5ile(QtGui.Q>ain#in"o!/
"ef --init--(self( parent=0one/
QtGui.Q>ain#in"o!.--init--(self( parent
self.setGeometry(1''( 1''( 1&'( 1''
self.set#in"o!*itle(+6pen5ile+
self.te,t7"it = QtGui.Q*e,t7"it(
self.set2entral#i"get(self.te,t7"it
self.status8ar(
self.set5ocus(
e,it = QtGui.QAction(QtGui.Q.con(+open.png+( +6pen+( self
e,it.set;hortcut(+2trlE6+
e,it.set;tatus*ip(+6pen ne! 5ile+
self.connect(e,it( Qt2ore.;.G0A<(+triggere"(+( self.sho!Bialog
menubar = self.menu8ar(
file = menubar.a"">enu(+F5ile+
file.a""Action(e,it
"ef sho!Bialog(self/
filename = QtGui.Q5ileBialog.get6pen5ile0ame(self( +6pen file+(
+/home+
file=open(filename
"ata = file.rea"(
self.te,t7"it.set*e,t("ata
app = QtGui.QApplication(sys.argv
c" = 6pen5ile(
c".sho!(
app.e,ec-(
The exa!ple shows a !enubar' centrally set text edit widget and a statusbar. The
statusbar is shown only for desing purposes. The the !enu ite! shows the
Q-ile*ialog which is used to select a file. The contents of the file are loaded
into the text edit widget.
class 6pen5ile(QtGui.Q>ain#in"o!/
...
self.te,t7"it = QtGui.Q*e,t7"it(
self.set2entral#i"get(self.te,t7"it
The exa!ple is based on the Q)ain(indow widget' because we centrally set the
text edit widget. This is easily done with the Q)ain(indow widget' without
resorting to layouts.
filename = QtGui.Q5ileBialog.get6pen5ile0ame(self( +6pen file+(
+/home+
(e pop up the Q-ile*ialog. The first string in the get4pen-ile1a!e !ethod is the
caption. The second string specifies the dialog working directory. ,y default'
the file filter is set to All files 6N7.
file=open(filename
"ata = file.rea"(
self.te,t7"it.set*e,t("ata
The selected file na!e is read and the contents of the file are set to the text
edit widget.

-igure. -ile dialog
PyQt4 (idgets
(idgets are basic building blocks of an application. The PyQt4 progra!!ing
toolkit has a wide range of "arious widgets. ,uttons' check boxes' sliders' list
boxes etc. @"erything a progra!!er needs for his &ob. In this section of the
tutorial' we will describe se"eral useful widgets.
Q/heck,ox
Q/heck,ox is a widget that has two states. 4n and 4ff. It is a box with a label.
(hene"er a checkbox is checked or cleared it e!its the signal state/hanged67.
#!/usr/bin/python
# chec=bo,.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class 2hec=8o,(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+2hec=bo,+
self.cb = QtGui.Q2hec=8o,(+;ho! title+( self
self.cb.set5ocusPolicy(Qt2ore.Qt.0o5ocus
self.cb.move()'( )'
self.cb.toggle(U
self.connect(self.cb( Qt2ore.;.G0A<(+state2hange"(int+(
self.change*itle
"ef change*itle(self( value/
if self.cb.is2hec=e"(/
self.set#in"o!*itle(+2hec=bo,+
else/
self.set#in"o!*itle(++
app = QtGui.QApplication(sys.argv
icon = 2hec=8o,(
icon.sho!(
app.e,ec-(
In our exa!ple' we will create a checkbox that will toggle the window title.
self.cb = QtGui.Q2hec=8o,(+;ho! title+( self
This is the Q/heck,ox constructor.
self.cb.set5ocusPolicy(Qt2ore.Qt.0o5ocus
(e connect the user defined changeTitle67 !ethod to the state/hanged67 signal.
The changeTitle67 !ethod will toggle the window title.
self.connect(self.cb( Qt2ore.;.G0A<(+state2hange"(int+( self.change*itle
,y default' the Q/heck,ox accepts focus. It is represented by a thin rectangle
o"er the checkbox label. The rectangle looks awful' so I disable it by setting
the widget focus policy to Qt.1o-ocus.
self.cb.toggle(U
(e set the window title' so we !ust also check the checkbox. ,y default' the
window title is not set and the check box is unchecked.

-igure. Q/heck,ox
Toggle,utton
PyQt4 has no widget for a Toggle,utton. To create a Toggle,utton' we use a
QPush,utton in a special !ode. Toggle,utton is a button that has two states.
Pressed and not pressed. Jou toggle between these two states by clicking on it.
There are situations where this functionality fits well.
#!/usr/bin/python
# togglebutton.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class *oggle8utton(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.color = QtGui.Q2olor('( '( '
self.setGeometry(1''( 1''( %M'( )L'
self.set#in"o!*itle(+*oggle8utton+
self.re" = QtGui.QPush8utton(+De"+( self
self.re".set2hec=able(*rue
self.re".move()'( )'
self.connect(self.re"( Qt2ore.;.G0A<(+clic=e"(+( self.setDe"
self.green = QtGui.QPush8utton(+Green+( self
self.green.set2hec=able(*rue
self.green.move()'( :'
self.connect(self.green( Qt2ore.;.G0A<(+clic=e"(+( self.setGreen
self.blue = QtGui.QPush8utton(+8lue+( self
self.blue.set2hec=able(*rue
self.blue.move()'( ))'
self.connect(self.blue( Qt2ore.;.G0A<(+clic=e"(+( self.set8lue
self.s9uare = QtGui.Q#i"get(self
self.s9uare.setGeometry()&'( %'( )''( )''
self.s9uare.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T? S
self.color.name(
QtGui.QApplication.set;tyle(QtGui.Q;tyle5actory.create(+cleanloo=s+
"ef setDe"(self/
if self.re".is2hec=e"(/
self.color.setDe"(%&&
else/ self.color.setDe"('
self.s9uare.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T? S
self.color.name(
"ef setGreen(self/
if self.green.is2hec=e"(/
self.color.setGreen(%&&
else/ self.color.setGreen('
self.s9uare.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T? S
self.color.name(
"ef set8lue(self/
if self.blue.is2hec=e"(/
self.color.set8lue(%&&
else/ self.color.set8lue('
self.s9uare.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T? S
self.color.name(
app = QtGui.QApplication(sys.argv
tb = *oggle8utton(
tb.sho!(
app.e,ec-(
In our exa!ple' we create three Toggle,uttons. (e also create a Q(idget. (e set
the background color of the Q(idget to black. The togglebuttons will toggle the
red' green and blue parts of the color "alue. The background color will depend
on which togglebuttons we ha"e pressed.
self.color = QtGui.Q2olor('( '( '
This is the initial color "alue. 1o red' green and blue e9uals to black.
Theoretically speaking' black is not a color after all.
self.re" = QtGui.QPush8utton(+De"+( self
self.re".set2hec=able(*rue
To create a Toggle,utton' we create a QPush,utton and !ake it checkable by
calling set/heckable67 !ethod.
self.connect(self.re"( Qt2ore.;.G0A<(+clic=e"(+( self.setDe"
(e connect a clicked67 signal to our user defined !ethod.
QtGui.QApplication.set;tyle(QtGui.Q;tyle5actory.create(+cleanloo=s+
I ha"e set the style of the application to cleanlooks. I did it' because the
default style for linux' plasti9ue has a design bug. Jou cannot easily tell
whether the Toggle,utton is pressed or not. /leanLooks style is better.
if self.re".is2hec=e"(/
self.color.setDe"(%&&
else/ self.color.setDe"('
(e check' whether the button is pressed and change the color "alue accordingly.
self.s9uare.set;tyle;heet(?Q#i"get R bac=groun"Ccolor/ Ss T? S
self.color.name(
To change the background color' we use stylesheets.

-igure. Toggle,utton
Q+lider' QLabel
Q+lider is a widget that has a si!ple handle. This handle can be pulled back and
forth. This way we are choosing a "alue for a specific task. +o!eti!es using a
slider is !ore natural' than si!ply pro"iding a nu!ber or using a spin box.
QLabel displays text or i!age.
In our exa!ple we will show one slider and one label. This ti!e' the label will
display an i!age. The slider will control the label.
#!/usr/bin/python
# sli"erClabel.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class ;li"er<abel(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+;li"er<abel+
self.sli"er = QtGui.Q;li"er(Qt2ore.Qt.Iori$ontal( self
self.sli"er.set5ocusPolicy(Qt2ore.Qt.0o5ocus
self.sli"er.setGeometry(1'( 4'( )''( 1'
self.connect(self.sli"er( Qt2ore.;.G0A<(+value2hange"(int+(
self.changeJalue
self.label = QtGui.Q<abel(self
self.label.setPi,map(QtGui.QPi,map(+mute.png+
self.label.setGeometry():'( 4'( M'( 1'
"ef changeJalue(self( value/
pos = self.sli"er.value(
if pos == '/
self.label.setPi,map(QtGui.QPi,map(+mute.png+
elif pos 4 ' an" pos 3= 1'/
self.label.setPi,map(QtGui.QPi,map(+min.png+
elif pos 4 1' an" pos 3 M'/
self.label.setPi,map(QtGui.QPi,map(+me".png+
else/
self.label.setPi,map(QtGui.QPi,map(+ma,.png+
app = QtGui.QApplication(sys.argv
icon = ;li"er<abel(
icon.sho!(
app.e,ec-(
In our exa!ple we si!ulate a "olu!e control. ,y dragging the handle of a slider'
we change a i!age on the label.
self.sli"er = QtGui.Q;li"er(Qt2ore.Qt.Iori$ontal( self
=ere we create a horiContal Q+lider.
self.label = QtGui.Q<abel(self
self.label.setPi,map(QtGui.QPi,map(+mute.png+
(e create a Qlabel. And set an initial !ute i!age to it.
self.connect(self.sli"er( Qt2ore.;.G0A<(+value2hange"(int+( self.changeJalue
(e connect the "alue/hanged signal to the user defined change5alue67 !ethod.
pos = self.sli"er.value(
(e get the position of the slider by calling the "alue67 !ethod. (e change the
i!age on the label accordingly.

-igure. +lider and Label
QProgress,ar
A progress bar is a widget that is used' when we process lengthy tasks. It is
ani!ated so that the user knows' that our task is progressing. The QProgress,ar
widget pro"ides a horiContal or "ertical progress bar in PyQt4 toolkit. The task
is di"ided into steps. The progra!!er can set the !ini!u! and !axi!u! "alues for
the progress bar. The default "alues are $' <<.
#!/usr/bin/python
# progressbar.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class Progress8ar(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+Progress8ar+
self.pbar = QtGui.QProgress8ar(self
self.pbar.setGeometry(1'( 4'( %''( %&
self.button = QtGui.QPush8utton(+;tart+( self
self.button.set5ocusPolicy(Qt2ore.Qt.0o5ocus
self.button.move(4'( M'
self.connect(self.button( Qt2ore.;.G0A<(+clic=e"(+( self.on;tart
self.timer = Qt2ore.Q8asic*imer(
self.step = 'U
"ef timer7vent(self( event/
if self.step 4= )''/
self.timer.stop(
return
self.step = self.step E )
self.pbar.setJalue(self.step
"ef on;tart(self/
if self.timer.isActive(/
self.timer.stop(
self.button.set*e,t(+;tart+
else/
self.timer.start()''( self
self.button.set*e,t(+;top+
app = QtGui.QApplication(sys.argv
icon = Progress8ar(
icon.sho!(
app.e,ec-(
In our exa!ple we ha"e a horiContal progress bar and a push button. The push
button starts and stops the progress bar.
self.pbar = QtGui.QProgress8ar(self
QProgress,ar constructor.
self.timer = Qt2ore.Q8asic*imer(
To acti"ate the progress bar' we use the ti!er ob&ect.
self.timer.start()''( self
To launch the ti!er e"ents' we call the start67 !ethod. This !ethod has two
para!eters. The ti!eout and the ob&ect' which will recei"e the e"ents.
"ef timer7vent(self( event/
if self.step 4= )''/
self.timer.stop(
return
self.step = self.step E )
self.pbar.setJalue(self.step
@ach Q4b&ect and its descendants has a Q4b&ect.ti!er@"ent e"ent handler. In
order to react to ti!er e"ents' we rei!ple!ent the e"ent handler.

-igure. Progress,ar
Q/alendar(idget
The Q/alendar(idget pro"ides a !onthly based calendar widget. It allows a user
to select a date in a si!ple and intuiti"e way.
#!/usr/bin/python
# calen"ar.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class 2alen"ar(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( 1&'( 1''
self.set#in"o!*itle(+2alen"ar+
self.cal = QtGui.Q2alen"ar#i"get(self
self.cal.setGri"Jisible(*rue
self.cal.move(%'( %'
self.connect(self.cal( Qt2ore.;.G0A<(+selection2hange"(+(
self.sho!Bate
self.label = QtGui.Q<abel(self
"ate = self.cal.selecte"Bate(
self.label.set*e,t(str("ate.toPyBate(
self.label.move()1'( %:'
"ef sho!Bate(self/
"ate = self.cal.selecte"Bate(
self.label.set*e,t(str("ate.toPyBate(
app = QtGui.QApplication(sys.argv
icon = 2alen"ar(
icon.sho!(
app.e,ec-(
The exa!ple has a calendar widget and a label widget. The currently selected
date is displayed in the label widget.
self.cal = QtGui.Q2alen"ar#i"get(self
(e construct a calendar widget.
self.connect(self.cal( Qt2ore.;.G0A<(+selection2hange"(+( self.sho!Bate
If we select a date fro! the widget' a selection/hanged67 signal is e!itted. (e
connect this !ethod to the user defined show*ate67 !ethod.
"ef sho!Bate(self/
"ate = self.cal.selecte"Bate(
self.label.set*e,t(str("ate.toPyBate(
(e retrie"e the selected date calling the selected*ate67 !ethod. Then we
transfor! the date ob&ect into string and set it to the label widget.

-igure. /alendar widget
*rag and *rop in PyQt4
In this part of the PyQt4 tutorial' we will talk about drag M drop operations.
In co!puter graphical user interfaces' drag0and0drop is the action of 6or
support for the action of7 clicking on a "irtual ob&ect and dragging it to a
different location or onto another "irtual ob&ect. In general' it can be used to
in"oke !any kinds of actions' or create "arious types of associations between
two abstract ob&ects. 6(ikipedia7
*rag and drop functionality is one of the !ost "isible aspects of the graphical
user interface. *rag and drop operation enables users to do co!plex things
intuiti"ely.
sually' we can drag and drop two things. *ata or so!e graphical ob&ects. If we
drag an i!age fro! one application to another' we drag and drop binary data. If
we drag a tab in -irefox and !o"e it to another place' we drag and drop a
graphical co!ponent.
+i!ple *rag and *rop
In the first exa!ple' we will ha"e a QLine@dit and a QPush,utton. (e will
drag plain text fro! the line edit widget and drop it onto the button widget.
#!/usr/bin/python
# "rag"rop.py
import sys
from PyQt4 import QtGui
class 8utton(QtGui.QPush8utton/
"ef --init--(self( title( parent/
QtGui.QPush8utton.--init--(self( title( parent
self.setAcceptBrops(*rue
"ef "rag7nter7vent(self( event/
if event.mimeBata(.has5ormat(+te,t/plain+/
event.accept(
else/
event.ignore(
"ef "rop7vent(self( event/
self.set*e,t(event.mimeBata(.te,t(
class BragBrop(QtGui.QBialog/
"ef --init--(self( parent=0one/
QtGui.QBialog.--init--(self( parent
self.resi$e(%M'( )&'
self.set#in"o!*itle(+;imple Brag F Brop+
e"it = QtGui.Q<ine7"it(++( self
e"it.setBrag7nable"(*rue
e"it.move(1'( :&
button = 8utton(?8utton?( self
button.move()L'( :&
screen = QtGui.QBes=top#i"get(.screenGeometry(
si$e = self.geometry(
self.move((screen.!i"th(Csi$e.!i"th(/%(
(screen.height(Csi$e.height(/%
app = QtGui.QApplication(sys.argv
icon = BragBrop(
icon.sho!(
app.e,ec-(
+i!ple drag M drop operation.
class 8utton(QtGui.QPush8utton/
"ef --init--(self( title( parent/
QtGui.QPush8utton.--init--(self( title( parent
In order to drop text on the QPush,utton widget' we !ust rei!ple!ent so!e
!ethods. +o we create our own ,utton class' which will inherit fro! the
QPush,utton class.
self.setAcceptBrops(*rue
(e enable drop e"ents for the widget.
"ef "rag7nter7vent(self( event/
if event.mimeBata(.has5ormat(+te,t/plain+/
event.accept(
else/
event.ignore(
-irst we rei!ple!ent the drag@nter@"ent67 !ethod. (e infor! about the data type'
we will accept. In our case it is plain text.
"ef "rop7vent(self( event/
self.set*e,t(event.mimeBata(.te,t(
,y rei!ple!enting the drop@"ent67 !ethod' we will define' what we will do upon
the drop e"ent. =ere we change the text of the button widget.
e"it = QtGui.Q<ine7"it(++( self
e"it.setBrag7nable"(*rue
The QLine@dit widget has a built0in support for drag operations. All we need
to do is to call set*rag@nabled67 !ethod to acti"ate it.

-igure. +i!ple *rag M *rop
*rag M drop a button widget
In the following exa!ple' we will de!onstrate' how to drag M drop a button
widget.
#!/usr/bin/python
# "ragbutton.py
import sys
from PyQt4 import QtGui
from PyQt4 import Qt2ore
class 8utton(QtGui.QPush8utton/
"ef --init--(self( title( parent/
QtGui.QPush8utton.--init--(self( title( parent
"ef mouse>ove7vent(self( event/
if event.buttons( != Qt2ore.Qt.Dight8utton/
return
mimeBata = Qt2ore.Q>imeBata(
"rag = QtGui.QBrag(self
"rag.set>imeBata(mimeBata
"rag.setIot;pot(event.pos( C self.rect(.top<eft(
"ropAction = "rag.start(Qt2ore.Qt.>oveAction
if "ropAction == Qt2ore.Qt.>oveAction/
self.close(
"ef mousePress7vent(self( event/
QtGui.QPush8utton.mousePress7vent(self( event
if event.button( == Qt2ore.Qt.<eft8utton/
print +press+
class Brag8utton(QtGui.QBialog/
"ef --init--(self( parent=0one/
QtGui.QBialog.--init--(self( parent
self.resi$e(%M'( )&'
self.set#in"o!*itle(+2lic= or >ove+
self.setAcceptBrops(*rue
self.button = 8utton(+8utton+( self
self.button.move()''( :&
screen = QtGui.QBes=top#i"get(.screenGeometry(
si$e = self.geometry(
self.move((screen.!i"th(Csi$e.!i"th(/%(
(screen.height(Csi$e.height(/%
"ef "rag7nter7vent(self( event/
event.accept(
"ef "rop7vent(self( event/
position = event.pos(
button = 8utton(+8utton+( self

button.move(position
button.sho!(
event.setBropAction(Qt2ore.Qt.>oveAction
event.accept(
app = QtGui.QApplication(sys.argv
"b = Brag8utton(
"b.sho!(
app.e,ec-(
In our code exa!ple' we ha"e a QPush,utton on the window. If we click on the
button with a left !ouse button' we print >press> to the console. ,y right
clicking and !o"ing the button' we perfor! a drag M drop operation on the button
widget.
class 8utton(QtGui.QPush8utton/
"ef --init--(self( title( parent/
QtGui.QPush8utton.--init--(self( title( parent
(e create a ,utton class' which will deri"e fro! the QPush,utton. (e also
rei!ple!ent two !ethods of the QPush,utton. !ouse)o"e@"ent67 and
!ousePress@"ent67. The !ouse)o"e@"ent67 !ethod is the place' where the drag M
drop operation begins.
if event.buttons( != Qt2ore.Qt.Dight8utton/
return
=ere we decide' that we can perfor! drag M drop only with a right !ouse button.
The left !ouse button is reser"ed for clicking on the button.
mimeBata = Qt2ore.Q>imeBata(
"rag = QtGui.QBrag(self
"rag.set>imeBata(mimeBata
"rag.setIot;pot(event.pos( C self.rect(.top<eft(
=ere we create a Q*rag ob&ect.
"ropAction = "rag.start(Qt2ore.Qt.>oveAction
if "ropAction == Qt2ore.Qt.>oveAction/
self.close(
The start67 !ethod of the drag ob&ect starts the drag M drop operation. If we
perfor! a !o"e drop action' we destroy the button widget. Technically' we
destroy a widget on the current position and recreate it on a new one.
"ef mousePress7vent(self( event/
QtGui.QPush8utton.mousePress7vent(self( event
if event.button( == Qt2ore.Qt.<eft8utton/
print +press+
(e print >press> to the console' if we left click on the button with the !ouse.
1otice that we call !ousePress@"ent67 !ethod on the parent as well. 4therwise we
would not see the button being pushed.
position = event.pos(
button = 8utton(+2lose+( self
button.move(position
button.sho!(
In the drop@"ent67 !ethod we code' what happens after we release the !ouse
button and finish the drop operation. In our exa!ple' we create a new ,utton
widget at the current position of the !ouse pointer.
event.setBropAction(Qt2ore.Qt.>oveAction
event.accept(
(e specify the type of the drop action. In our case it is a !o"e action.
*rawing in PyQt4
*rawing is used' when we want to change or enhance an existing widget. 4r if we
are creating a custo! widget fro! scratch. To do the drawing' we use the drawing
API pro"ided by the PyQt4 toolkit.
The drawing is done within the paint@"ent67 !ethod. The drawing code is placed
between the begin67 and end67 !ethods of the QPainter ob&ect.
*rawing text
(e begin with drawing so!e unicode text onto the window client area.
#!/usr/bin/python
# "ra!te,t.py
import sys
from PyQt4 import QtGui( Qt2ore
class Bra!*e,t(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+Bra! *e,t+
self.te,t = u+Gu'4)bGu'41&Gu'41% Gu'4)"Gu'41MGu'41aGu'41eGu'41bGu'41'G
Gu'41&Gu'41%Gu'41MGu'44L Gu'4%%Gu'41eGu'41bGu'44)Gu'44%Gu'41eGu'41N/ GnG
Gu'4)'Gu'41"Gu'41"Gu'41' Gu'4)aGu'41'Gu'44'Gu'41&Gu'41"Gu'41MGu'41"Gu'41'+
"ef paint7vent(self( event/
paint = QtGui.QPainter(
paint.begin(self
paint.setPen(QtGui.Q2olor():M( 14( 1
paint.set5ont(QtGui.Q5ont(+Becorative+( )'
paint."ra!*e,t(event.rect(( Qt2ore.Qt.Align2enter( self.te,t
paint.en"(
app = QtGui.QApplication(sys.argv
"t = Bra!*e,t(
"t.sho!(
app.e,ec-(
In our exa!ple' we draw so!e text in aCbuka. The text is "ertically and
horiContally aligned.
"ef paint7vent(self( event/
*rawing is done within a paint e"ent.
paint = QtGui.QPainter(
paint.begin(self
...
paint.en"(
The QPainter class is responsible for all the low0le"el painting. All the
painting !ethods go between begin67 and end67 !ethods.
paint.setPen(QtGui.Q2olor():M( 14( 1
paint.set5ont(QtGui.Q5ont(+Becorative+( )'
=ere we define pen and font' which we use to draw the text.
paint."ra!*e,t(event.rect(( Qt2ore.Qt.Align2enter( self.te,t
The drawText67 !ethod actually draws text on the window.

-igure. *rawing Text
*rawing points
A point is the !ost si!ple graphics ob&ect' that can be drawn. It is a s!all
spot on the window.
#!/usr/bin/python
# points.py
import sys( ran"om
from PyQt4 import QtGui( Qt2ore
class Points(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %&'( )&'
self.set#in"o!*itle(+Points+
"ef paint7vent(self( event/
paint = QtGui.QPainter(
paint.begin(self
paint.setPen(Qt2ore.Qt.re"
si$e = self.si$e(
for i in range()'''/
, = ran"om.ran"int()( si$e.!i"th(C)
y = ran"om.ran"int()( si$e.height(C)
paint."ra!Point(,( y
paint.en"(
app = QtGui.QApplication(sys.argv
"t = Points(
"t.sho!(
app.e,ec-(
In our exa!ple' we draw rando!ly ;$$$ red points on the client area.
paint.setPen(Qt2ore.Qt.re"
(e set the pen to red color. (e use a predefined color constant.
si$e = self.si$e(
@ach ti!e we resiCe the window' a paint e"ent is generated. (e get the current
siCe of the window with the siCe67 !ethod.
paint."ra!Point(,( y
(e draw the point with the drawPoint67 !ethod.

-igure. Points
/olors
A color is an ob&ect representing a co!bination of :ed' Green' and ,lue 6:G,7
intensity "alues. 5alid :G, "alues are in the range $ to 8??. (e can define a
color in "arious ways. The !ost co!!on are :G, deci!al "alues or hexadeci!al
"alues. (e can also use an :G,A "alue' which stands for :ed' Green' ,lue' Alpha.
=ere we add so!e extra infor!ation' regarding transparency. Alpha "alue of 8??
defines full opacity' $ is for full transparency' eg the color is in"isible.
#!/usr/bin/python
# colors.py
import sys( ran"om
from PyQt4 import QtGui( Qt2ore
class 2olors(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( 1&'( %M'
self.set#in"o!*itle(+2olors+
"ef paint7vent(self( event/
paint = QtGui.QPainter(
paint.begin(self
color = QtGui.Q2olor('( '( '
color.set0ame"2olor(+#"4"4"4+
paint.setPen(color
paint.set8rush(QtGui.Q2olor(%&&( '( '( M'
paint."ra!Dect()'( )&( N'( :'
paint.set8rush(QtGui.Q2olor(%&&( '( '( ):'
paint."ra!Dect()1'( )&( N'( :'
paint.set8rush(QtGui.Q2olor(%&&( '( '( %&&
paint."ra!Dect(%&'( )&( N'( :'
paint.set8rush(QtGui.Q2olor()'( ):1( %( &&
paint."ra!Dect()'( )'&( N'( :'
paint.set8rush(QtGui.Q2olor():'( )''( '( %&&
paint."ra!Dect()1'( )'&( N'( :'
paint.set8rush(QtGui.Q2olor(:'( )''( :'( %&&
paint."ra!Dect(%&'( )'&( N'( :'
paint.set8rush(QtGui.Q2olor(&'( &'( &'( %&&
paint."ra!Dect()'( )N&( N'( :'
paint.set8rush(QtGui.Q2olor(&'( )&'( &'( %&&
paint."ra!Dect()1'( )N&( N'( :'
paint.set8rush(QtGui.Q2olor(%%1( )1&( )N( %&&
paint."ra!Dect(%&'( )N&( N'( :'
paint.en"(
app = QtGui.QApplication(sys.argv
"t = 2olors(
"t.sho!(
app.e,ec-(
In our exa!ple' we draw < colored rectangles. The first row shows a red color'
with different alpha "alues.
color = QtGui.Q2olor('( '( '
color.set0ame"2olor(+#"4"4"4+
=ere we define a color using hexadeci!al notation.
paint.set8rush(QtGui.Q2olor(%&&( '( '( M'U
paint."ra!Dect()'( )&( N'( :'
=ere we define a brush and draw a rectangle. A brush is an ele!entary graphics
ob&ect' which is used to draw the background of a shape. The draw:ect67 !ethod
accepts four para!eter. The first two are x' y "alues on the axis. The third and
fourth para!eters are width and height of the rectangle. The !ethod draws a
rectangle using current pen and current brush.

-igure. /olors
QPen
QPen is an ele!entary graphics ob&ect. It is used to draw lines' cur"es and
outlines of rectangles' ellipses' polygons or other shapes.
#!/usr/bin/python
# penstyles.py
import sys
from PyQt4 import QtGui( Qt2ore
class Pen;tyles(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( %M'( %L'
self.set#in"o!*itle(+penstyles+
"ef paint7vent(self( event/
paint = QtGui.QPainter(
paint.begin(self
pen = QtGui.QPen(Qt2ore.Qt.blac=( %( Qt2ore.Qt.;oli"<ine
paint.setPen(pen
paint."ra!<ine(%'( 4'( %&'( 4'
pen.set;tyle(Qt2ore.Qt.Bash<ine
paint.setPen(pen
paint."ra!<ine(%'( M'( %&'( M'
pen.set;tyle(Qt2ore.Qt.BashBot<ine
paint.setPen(pen
paint."ra!<ine(%'( )%'( %&'( )%'
pen.set;tyle(Qt2ore.Qt.Bot<ine
paint.setPen(pen
paint."ra!<ine(%'( ):'( %&'( ):'
pen.set;tyle(Qt2ore.Qt.BashBotBot<ine
paint.setPen(pen
paint."ra!<ine(%'( %''( %&'( %''
pen.set;tyle(Qt2ore.Qt.2ustomBash<ine
pen.setBashPattern(K)( 4( &( 4P
paint.setPen(pen
paint."ra!<ine(%'( %4'( %&'( %4'
paint.en"(
app = QtGui.QApplication(sys.argv
"t = Pen;tyles(
"t.sho!(
app.e,ec-(
In our exa!ple' we draw six lines. The lines are drawn in six different pen
styles. There are fi"e predefined pen styles. (e can create also custo! pen
styles. The last line is drawn using custo! pen style.
pen = QtGui.QPen(Qt2ore.Qt.blac=( %( Qt2ore.Qt.;oli"<ine
(e create a QPen ob&ect. The color is black. The width is set to 8 pixels' so
that we can see the differences between the pen styles. The Qt/ore.Qt.+olidLine
is one of the predefined pen styles.
pen.set;tyle(Qt2ore.Qt.2ustomBash<ine
pen.setBashPattern(K)( 4( &( 4P
paint.setPen(pen
=ere we define a custo! pen style. (e set a Qt/ore.Qt./usto!*ashLine pen style
and call a set*ashPattern67 !ethod. The list of nu!bers defines a style. There
!ust be an e"en nu!ber of nu!bers. 4dd nu!bers define a dash' e"en nu!bers
space. The greater the nu!ber' the greater the space or the dash. 4ur pattern is
;px dash 4px space ?px dash 4px space etc.

-igure. Pen +tyles
Q,rush
Q,rush is an ele!entary graphics ob&ect. It is used to paint the background of
graphics shapes' such as rectangles' ellipses or polygons. A brush can be of
three different types. A predefined brush a gradien or a texture pattern.
#!/usr/bin/python
# brushes.py
import sys
from PyQt4 import QtGui( Qt2ore
class 8rushes(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.setGeometry(1''( 1''( 1&&( %M'
self.set#in"o!*itle(+8rushes+
"ef paint7vent(self( event/
paint = QtGui.QPainter(
paint.begin(self
brush = QtGui.Q8rush(Qt2ore.Qt.;oli"Pattern
paint.set8rush(brush
paint."ra!Dect()'( )&( N'( :'
brush.set;tyle(Qt2ore.Qt.Bense)Pattern
paint.set8rush(brush
paint."ra!Dect()1'( )&( N'( :'
brush.set;tyle(Qt2ore.Qt.Bense%Pattern
paint.set8rush(brush
paint."ra!Dect(%&'( )&( N'( :'
brush.set;tyle(Qt2ore.Qt.Bense1Pattern
paint.set8rush(brush
paint."ra!Dect()'( )'&( N'( :'
brush.set;tyle(Qt2ore.Qt.Biag2rossPattern
paint.set8rush(brush
paint."ra!Dect()'( )'&( N'( :'
brush.set;tyle(Qt2ore.Qt.Bense&Pattern
paint.set8rush(brush
paint."ra!Dect()1'( )'&( N'( :'
brush.set;tyle(Qt2ore.Qt.Bense:Pattern
paint.set8rush(brush
paint."ra!Dect(%&'( )'&( N'( :'
brush.set;tyle(Qt2ore.Qt.IorPattern
paint.set8rush(brush
paint."ra!Dect()'( )N&( N'( :'
brush.set;tyle(Qt2ore.Qt.JerPattern
paint.set8rush(brush
paint."ra!Dect()1'( )N&( N'( :'
brush.set;tyle(Qt2ore.Qt.8BiagPattern
paint.set8rush(brush
paint."ra!Dect(%&'( )N&( N'( :'
paint.en"(
app = QtGui.QApplication(sys.argv
"t = 8rushes(
"t.sho!(
app.e,ec-(
In our exa!ple' we draw six different rectangles.
brush = QtGui.Q8rush(Qt2ore.Qt.;oli"Pattern
paint.set8rush(brush
paint."ra!Dect()'( )&( N'( :'
(e define a brush ob&ect. +et it to the painter ob&ect. And draw the rectangle
calling the draw:ect67 !ethod.

-igure. ,rushes
/usto! (idgets in PyQt4
=a"e you e"er looked at an application and wondered' how a particular gui ite!
was createdL Probably e"ery wannabe progra!!er has. Then you were looking at a
list of widgets pro"ided by your fa"ourite gui library. ,ut you couldn>t find
it. Toolkits usually pro"ide only the !ost co!!on widgets like buttons' text
widgets' sliders etc. 1o toolkit can pro"ide all possible widgets.
There are actually two kinds of toolkits. +partan toolkits and hea"y weight
toolkits. The -LTH toolkit is a kind of a spartan toolkit. It pro"ides only the
"ery basic widgets and assu!es' that the progra!e!er will create the !ore
co!plicated ones hi!self. PyQt4 is a hea"y weight one. It has lots of widgets.
Jet it does not pro"ide the !ore specialiCed widgets. -or exa!ple a speed !eter
widget' a widget that !easures the capacity of a /* to be burned 6found e.g. in
nero7. Toolkits also don>t ha"e usually charts.
Progra!!ers !ust create such widgets by the!sel"es. They do it by using the
drawing tools pro"ided by the toolkit. There are two possibilities. A progra!!er
can !odify or enhance an existing widget. 4r he can create a custo! widget fro!
scratch.
,urning widget
This is a widget that we can see in 1ero' H#, or other /*2*5* burning software.
#!/usr/bin/python
# burning.py
import sys
from PyQt4 import QtGui( Qt2ore
class #i"get(QtGui.Q<abel/
"ef --init--(self( parent/
QtGui.Q<abel.--init--(self( parent
self.set>inimum;i$e()( 1'
self.parent = parent
self.num = KL&( )&'( %%&( 1''( 1L&( 4&'( &%&( :''( :L&P
"ef paint7vent(self( event/
paint = QtGui.QPainter(
paint.begin(self
font = QtGui.Q5ont(+;erif+( L( QtGui.Q5ont.<ight
paint.set5ont(font
si$e = self.si$e(
! = si$e.!i"th(
h = si$e.height(
c! = self.parent.c!
step = int(roun"(! / )'.'
till = int(((! / L&'.' O c!
full = int(((! / L&'.' O L''
if c! 4= L''/
paint.setPen(QtGui.Q2olor(%&&( %&&( %&&
paint.set8rush(QtGui.Q2olor(%&&( %&&( )M4
paint."ra!Dect('( '( full( h
paint.setPen(QtGui.Q2olor(%&&( )L&( )L&
paint.set8rush(QtGui.Q2olor(%&&( )L&( )L&
paint."ra!Dect(full( '( tillCfull( h
else/
paint.setPen(QtGui.Q2olor(%&&( %&&( %&&
paint.set8rush(QtGui.Q2olor(%&&( %&&( )M4
paint."ra!Dect('( '( till( h
pen = QtGui.QPen(QtGui.Q2olor(%'( %'( %'( )( Qt2ore.Qt.;oli"<ine
paint.setPen(pen
paint.set8rush(Qt2ore.Qt.0o8rush
paint."ra!Dect('( '( !C)( hC)
Q = '
for i in range(step( )'Ostep( step/
paint."ra!<ine(i( '( i( &
metrics = paint.font>etrics(
f! = metrics.!i"th(str(self.numKQP
paint."ra!*e,t(iCf!/%( h/%( str(self.numKQP
Q = Q E )
paint.en"(
class 8urning(QtGui.Q#i"get/
"ef --init--(self( parent=0one/
QtGui.Q#i"get.--init--(self( parent
self.c! = L&
self.sli"er = QtGui.Q;li"er(Qt2ore.Qt.Iori$ontal( self
self.sli"er.set5ocusPolicy(Qt2ore.Qt.0o5ocus
self.sli"er.setDange()( L&'
self.sli"er.setJalue(L&
self.sli"er.setGeometry(1'( 4'( )&'( 1'
self.!i" = #i"get(self
self.connect(self.sli"er( Qt2ore.;.G0A<(+value2hange"(int+(
self.changeJalue
hbo, = QtGui.QI8o,<ayout(
hbo,.a""#i"get(self.!i"
vbo, = QtGui.QJ8o,<ayout(
vbo,.a"";tretch()
vbo,.a""<ayout(hbo,
self.set<ayout(vbo,
self.setGeometry(1''( 1''( 1''( %%'
self.set#in"o!*itle(+8urning+
"ef changeJalue(self( event/
self.c! = self.sli"er.value(
self.!i".repaint(
app = QtGui.QApplication(sys.argv
"t = 8urning(
"t.sho!(
app.e,ec-(
In our exa!ple' we ha"e a Q+lider and a custo! widget. The slider controls the
custo! widget. This widget shows graphically the total capacity of a !ediu! and
the free space a"ailable to us. The !ini!u! "alue of our custo! widget is ;' the
!axi!u! is D?$. If we reach "alue D$$' we begin drawing in red colour. This
nor!ally indicates o"erburning.
The burning widget is placed at the botto! of the window. This is achie"ed using
one Q=,oxLayout and one Q5,oxLayout
class #i"get(QtGui.Q<abel/
"ef --init--(self( parent/
QtGui.Q<abel.--init--(self( parent
The burning widget it based on the QLabel widget.
self.set>inimum;i$e()( 1'
(e change the !ini!u! siCe 6height7 of the widget. The default "alue is a bit
s!all for us.
font = QtGui.Q5ont(+;erif+( L( QtGui.Q5ont.<ight
paint.set5ont(font
(e use a s!aller font than the default one. That better suits our needs.
si$e = self.si$e(
! = si$e.!i"th(
h = si$e.height(
c! = self.parent.c!
step = int(roun"(! / )'.'
till = int(((! / L&'.' O c!
full = int(((! / L&'.' O L''
(e draw the widget dyna!ically. The greater the window' the greater the burning
widget. And "ice "ersa. That is why we !ust calculate the siCe of the widget
onto which we draw the custo! widget. The till para!eter deter!ines the total
siCe to be drawn. This "alue co!es fro! the slider widget. It is a proportion of
the whole area. The full para!eter deter!ines the point' where we begin to draw
in red color. 1otice the use of floating point arith!etics. This is to achie"e
greater precision.
The actual drawing consists of three steps. (e draw the yellow or red and yellow
rectangle. Then we draw the "ertical lines' which di"ide the widget into se"eral
parts. -inally' we draw the nu!bers' which indicate the capacity of the !ediu!.
metrics = paint.font>etrics(
f! = metrics.!i"th(str(self.numKQP
paint."ra!*e,t(iCf!/%( h/%( str(self.numKQP
(e use font !etrics to draw the text. (e !ust know the width of the text in
order to center it around the "ertical line.

-igure. The burning widget
The Tetris ga!e in PyQt4
/reating a co!puter ga!e is "ery challenging. +ooner or later' a progra!!er will
want to create a co!puter ga!e one day. In fact' !any people beca!e interested
in progra!!ing' because they played ga!es and wanted to create their own.
/reating a co!puter ga!e will "astly help i!pro"ing your progra!!ing skills.
Tetris
The tetris ga!e is one of the !ost popular co!puter ga!es e"er created. The
original ga!e was designed and progra!!ed by a russian progra!!er Alexey
Pa&itno" in ;<G?. +ince then' tetris is a"ailable on al!ost e"ery co!puter
platfor! in lots of "ariations. @"en !y !obile phone has a !odified "ersion of
the tetris ga!e.
Tetris is called a falling block puCCle ga!e. In this ga!e' we ha"e se"en
different shapes called tetro!inoes. +0shape' O0shape' T0shape' L0shape' Line0
shape' )irroredL0shape and a +9uare0shape. @ach of these shapes is for!ed with
four s9uares. The shapes are falling down the board. The ob&ect of the tetris
ga!e is to !o"e and rotate the shapes' so that they fit as !uch as possible. If
we !anage to for! a row' the row is destroyed and we score. (e play the tetris
ga!e until we top out.

-igure. Tetro!inoes
PyQt4 is a toolkit designed to create applications. There are other libraries
which are targeted at creating co!puter ga!es. 1e"ertheless' PyQt4 and other
application toolkits can be used to create ga!es.
The following exa!ple is a !odified "ersion of the tetris ga!e' a"ailable with
PyQt4 installation files.
The de"elop!ent
(e do not ha"e i!ages for our tetris ga!e' we draw the tetro!inoes using the
drawing API a"ailable in the PyQt4 progra!!ing toolkit. ,ehind e"ery co!puter
ga!e' there is a !athe!atical !odel. +o it is in tetris.
+o!e ideas behind the ga!e.
(e use Qt/ore.Q,asicTi!er67 to create a ga!e cycle
The tetro!inoes are drawn
The shapes !o"e on a s9uare by s9uare basis 6not pixel by pixel7
)athe!atically a board is a si!ple list of nu!bers
#!/usr/bin/python
# tetris.py
import sys
import ran"om
from PyQt4 import Qt2ore( QtGui
class *etris(QtGui.Q>ain#in"o!/
"ef --init--(self/
QtGui.Q>ain#in"o!.--init--(self
self.setGeometry(1''( 1''( )M'( 1M'
self.set#in"o!*itle(+*etris+
self.tetrisboar" = 8oar"(self
self.set2entral#i"get(self.tetrisboar"
self.statusbar = self.status8ar(
self.connect(self.tetrisboar"(
Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?(
self.statusbar( Qt2ore.;<6*(?sho!>essage(Q;tring?
self.tetrisboar".start(
self.center(
"ef center(self/
screen = QtGui.QBes=top#i"get(.screenGeometry(
si$e = self.geometry(
self.move((screen.!i"th(Csi$e.!i"th(/%(
(screen.height(Csi$e.height(/%
class 8oar"(QtGui.Q5rame/
8oar"#i"th = )'
8oar"Ieight = %%
;pee" = 1''
"ef --init--(self( parent/
QtGui.Q5rame.--init--(self( parent
self.timer = Qt2ore.Q8asic*imer(
self.is#aitingAfter<ine = 5alse
self.curPiece = ;hape(
self.ne,tPiece = ;hape(
self.curV = '
self.curA = '
self.num<inesDemove" = '
self.boar" = KP
self.set5ocusPolicy(Qt2ore.Qt.;trong5ocus
self.is;tarte" = 5alse
self.isPause" = 5alse
self.clear8oar"(
self.ne,tPiece.setDan"om;hape(
"ef shapeAt(self( ,( y/
return self.boar"K(y O 8oar".8oar"#i"th E ,P
"ef set;hapeAt(self( ,( y( shape/
self.boar"K(y O 8oar".8oar"#i"th E ,P = shape
"ef s9uare#i"th(self/
return self.contentsDect(.!i"th( / 8oar".8oar"#i"th
"ef s9uareIeight(self/
return self.contentsDect(.height( / 8oar".8oar"Ieight
"ef start(self/
if self.isPause"/
return
self.is;tarte" = *rue
self.is#aitingAfter<ine = 5alse
self.num<inesDemove" = '
self.clear8oar"(
self.emit(Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?(
str(self.num<inesDemove"
self.ne!Piece(
self.timer.start(8oar".;pee"( self
"ef pause(self/
if not self.is;tarte"/
return
self.isPause" = not self.isPause"
if self.isPause"/
self.timer.stop(
self.emit(Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?( ?pause"?
else/
self.timer.start(8oar".;pee"( self
self.emit(Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?(
str(self.num<inesDemove"
self.up"ate(
"ef paint7vent(self( event/
painter = QtGui.QPainter(self
rect = self.contentsDect(
boar"*op = rect.bottom( C 8oar".8oar"Ieight O self.s9uareIeight(
for i in range(8oar".8oar"Ieight/
for Q in range(8oar".8oar"#i"th/
shape = self.shapeAt(Q( 8oar".8oar"Ieight C i C )
if shape != *etrominoes.0o;hape/
self."ra!;9uare(painter(
rect.left( E Q O self.s9uare#i"th((
boar"*op E i O self.s9uareIeight(( shape
if self.curPiece.shape( != *etrominoes.0o;hape/
for i in range(4/
, = self.curV E self.curPiece.,(i
y = self.curA C self.curPiece.y(i
self."ra!;9uare(painter( rect.left( E , O self.s9uare#i"th((
boar"*op E (8oar".8oar"Ieight C y C ) O
self.s9uareIeight((
self.curPiece.shape(
"ef =eyPress7vent(self( event/
if not self.is;tarte" or self.curPiece.shape( == *etrominoes.0o;hape/
QtGui.Q#i"get.=eyPress7vent(self( event
return
=ey = event.=ey(
if =ey == Qt2ore.Qt.Hey-P/
self.pause(
return
if self.isPause"/
return
elif =ey == Qt2ore.Qt.Hey-<eft/
self.try>ove(self.curPiece( self.curV C )( self.curA
elif =ey == Qt2ore.Qt.Hey-Dight/
self.try>ove(self.curPiece( self.curV E )( self.curA
elif =ey == Qt2ore.Qt.Hey-Bo!n/
self.try>ove(self.curPiece.rotate"Dight(( self.curV( self.curA
elif =ey == Qt2ore.Qt.Hey-Wp/
self.try>ove(self.curPiece.rotate"<eft(( self.curV( self.curA
elif =ey == Qt2ore.Qt.Hey-;pace/
self."ropBo!n(
elif =ey == Qt2ore.Qt.Hey-B/
self.one<ineBo!n(
else/
QtGui.Q#i"get.=eyPress7vent(self( event
"ef timer7vent(self( event/
if event.timer."( == self.timer.timer."(/
if self.is#aitingAfter<ine/
self.is#aitingAfter<ine = 5alse
self.ne!Piece(
else/
self.one<ineBo!n(
else/
QtGui.Q5rame.timer7vent(self( event
"ef clear8oar"(self/
for i in range(8oar".8oar"Ieight O 8oar".8oar"#i"th/
self.boar".appen"(*etrominoes.0o;hape
"ef "ropBo!n(self/
ne!A = self.curA
!hile ne!A 4 '/
if not self.try>ove(self.curPiece( self.curV( ne!A C )/
brea=
ne!A C= )
self.pieceBroppe"(
"ef one<ineBo!n(self/
if not self.try>ove(self.curPiece( self.curV( self.curA C )/
self.pieceBroppe"(
"ef pieceBroppe"(self/
for i in range(4/
, = self.curV E self.curPiece.,(i
y = self.curA C self.curPiece.y(i
self.set;hapeAt(,( y( self.curPiece.shape(
self.remove5ull<ines(
if not self.is#aitingAfter<ine/
self.ne!Piece(
"ef remove5ull<ines(self/
num5ull<ines = '
ro!s*oDemove = KP
for i in range(8oar".8oar"Ieight/
n = '
for Q in range(8oar".8oar"#i"th/
if not self.shapeAt(Q( i == *etrominoes.0o;hape/
n = n E )
if n == )'/
ro!s*oDemove.appen"(i
ro!s*oDemove.reverse(
for m in ro!s*oDemove/
for = in range(m( 8oar".8oar"Ieight/
for l in range(8oar".8oar"#i"th/
self.set;hapeAt(l( =( self.shapeAt(l( = E )
num5ull<ines = num5ull<ines E len(ro!s*oDemove
if num5ull<ines 4 '/
self.num<inesDemove" = self.num<inesDemove" E num5ull<ines
self.emit(Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?(
str(self.num<inesDemove"
self.is#aitingAfter<ine = *rue
self.curPiece.set;hape(*etrominoes.0o;hape
self.up"ate(
"ef ne!Piece(self/
self.curPiece = self.ne,tPiece
self.ne,tPiece.setDan"om;hape(
self.curV = 8oar".8oar"#i"th / % E )
self.curA = 8oar".8oar"Ieight C ) E self.curPiece.minA(
if not self.try>ove(self.curPiece( self.curV( self.curA/
self.curPiece.set;hape(*etrominoes.0o;hape
self.timer.stop(
self.is;tarte" = 5alse
self.emit(Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?( ?Game over?
"ef try>ove(self( ne!Piece( ne!V( ne!A/
for i in range(4/
, = ne!V E ne!Piece.,(i
y = ne!A C ne!Piece.y(i
if , 3 ' or , 4= 8oar".8oar"#i"th or y 3 ' or y 4=
8oar".8oar"Ieight/
return 5alse
if self.shapeAt(,( y != *etrominoes.0o;hape/
return 5alse
self.curPiece = ne!Piece
self.curV = ne!V
self.curA = ne!A
self.up"ate(
return *rue
"ef "ra!;9uare(self( painter( ,( y( shape/
color*able = K',''''''( ',22::::( ',::22::( ',::::22(
',2222::( ',22::22( ',::2222( ',BAAA''P
color = QtGui.Q2olor(color*ableKshapeP
painter.fillDect(, E )( y E )( self.s9uare#i"th( C %(
self.s9uareIeight( C %( color
painter.setPen(color.light(
painter."ra!<ine(,( y E self.s9uareIeight( C )( ,( y
painter."ra!<ine(,( y( , E self.s9uare#i"th( C )( y
painter.setPen(color."ar=(
painter."ra!<ine(, E )( y E self.s9uareIeight( C )(
, E self.s9uare#i"th( C )( y E self.s9uareIeight( C )
painter."ra!<ine(, E self.s9uare#i"th( C )(
y E self.s9uareIeight( C )( , E self.s9uare#i"th( C )( y E )
class *etrominoes(obQect/
0o;hape = '
X;hape = )
;;hape = %
<ine;hape = 1
*;hape = 4
;9uare;hape = &
<;hape = :
>irrore"<;hape = L
class ;hape(obQect/
coor"s*able = (
(('( '( ('( '( ('( '( ('( '(
(('( C)( ('( '( (C)( '( (C)( )(
(('( C)( ('( '( ()( '( ()( )(
(('( C)( ('( '( ('( )( ('( %(
((C)( '( ('( '( ()( '( ('( )(
(('( '( ()( '( ('( )( ()( )(
((C)( C)( ('( C)( ('( '( ('( )(
(()( C)( ('( C)( ('( '( ('( )

"ef --init--(self/
self.coor"s = KK'('P for i in range(4P
self.piece;hape = *etrominoes.0o;hape
self.set;hape(*etrominoes.0o;hape
"ef shape(self/
return self.piece;hape
"ef set;hape(self( shape/
table = ;hape.coor"s*ableKshapeP
for i in range(4/
for Q in range(%/
self.coor"sKiPKQP = tableKiPKQP
self.piece;hape = shape
"ef setDan"om;hape(self/
self.set;hape(ran"om.ran"int()( L
"ef ,(self( in"e,/
return self.coor"sKin"e,PK'P
"ef y(self( in"e,/
return self.coor"sKin"e,PK)P
"ef setV(self( in"e,( ,/
self.coor"sKin"e,PK'P = ,
"ef setA(self( in"e,( y/
self.coor"sKin"e,PK)P = y
"ef minV(self/
m = self.coor"sK'PK'P
for i in range(4/
m = min(m( self.coor"sKiPK'P
return m
"ef ma,V(self/
m = self.coor"sK'PK'P
for i in range(4/
m = ma,(m( self.coor"sKiPK'P
return m
"ef minA(self/
m = self.coor"sK'PK)P
for i in range(4/
m = min(m( self.coor"sKiPK)P
return m
"ef ma,A(self/
m = self.coor"sK'PK)P
for i in range(4/
m = ma,(m( self.coor"sKiPK)P
return m
"ef rotate"<eft(self/
if self.piece;hape == *etrominoes.;9uare;hape/
return self
result = ;hape(
result.piece;hape = self.piece;hape
for i in range(4/
result.setV(i( self.y(i
result.setA(i( Cself.,(i
return result
"ef rotate"Dight(self/
if self.piece;hape == *etrominoes.;9uare;hape/
return self
result = ;hape(
result.piece;hape = self.piece;hape
for i in range(4/
result.setV(i( Cself.y(i
result.setA(i( self.,(i
return result
app = QtGui.QApplication(sys.argv
tetris = *etris(
tetris.sho!(
sys.e,it(app.e,ec-(
I ha"e si!plified the ga!e a bit' so that it is easier to understand. The ga!e
starts i!!ediately' after it is launched. (e can pause the ga!e by pressing the
p key. The space key will drop the tetris piece i!!ediately to the botto!. The
ga!e goes at constant speed' no acceleration is i!ple!ented. The score is the
nu!ber of lines' that we ha"e re!o"ed.
self.statusbar = self.status8ar(
self.connect(self.tetrisboar"( Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?(
self.statusbar( Qt2ore.;<6*(?sho!>essage(Q;tring?
(e create a statusbar' where we will display !essages. (e will display three
possible !essages. The nu!ber of lines alredy re!o"ed. The paused !essage and
the ga!e o"er !essage.
...
self.curV = '
self.curA = '
self.num<inesDemove" = '
self.boar" = KP
...
,efore we start the ga!e cycle' we initialiCe so!e i!portant "ariables. The
self.board "ariable is a list of nu!bers fro! $ ... D. It represents the
position of "arious shapes and re!ains of the shapes on the board.
for Q in range(8oar".8oar"#i"th/
shape = self.shapeAt(Q( 8oar".8oar"Ieight C i C )
if shape != *etrominoes.0o;hape/
self."ra!;9uare(painter(
rect.left( E Q O self.s9uare#i"th((
boar"*op E i O self.s9uareIeight(( shape
The painting of the ga!e is di"ided into two steps. In the first step' we draw
all the shapes' or re!ains of the shapes' that ha"e been dropped to the botto!
of the board. All the s9uares are re!e!berd in the self.board list "ariable.
(e access it using the shapeAt67 !ethod.
if self.curPiece.shape( != *etrominoes.0o;hape/
for i in range(4/
, = self.curV E self.curPiece.,(i
y = self.curA C self.curPiece.y(i
self."ra!;9uare(painter( rect.left( E , O self.s9uare#i"th((
boar"*op E (8oar".8oar"Ieight C y C ) O self.s9uareIeight((
self.curPiece.shape(
The next step is drawing of the actual piece' that is falling down.
elif =ey == Qt2ore.Qt.Hey-<eft/
self.try>ove(self.curPiece( self.curV C )( self.curA
elif =ey == Qt2ore.Qt.Hey-Dight/
self.try>ove(self.curPiece( self.curV E )( self.curA
In the keyPress@"ent we check for pressed keys. If we press the right arrow
key' we try to !o"e the piece to the right. (e say try' because the piece !ight
not be able to !o"e.
"ef try>ove(self( ne!Piece( ne!V( ne!A/
for i in range(4/
, = ne!V E ne!Piece.,(i
y = ne!A C ne!Piece.y(i
if , 3 ' or , 4= 8oar".8oar"#i"th or y 3 ' or y 4= 8oar".8oar"Ieight/
return 5alse
if self.shapeAt(,( y != *etrominoes.0o;hape/
return 5alse
self.curPiece = ne!Piece
self.curV = ne!V
self.curA = ne!A
self.up"ate(
return *rue
In the try)o"e67 !ethod we try to !o"e our shapes. If the shape is at the edge
of the board or is ad&acent to so!e other piece' we return false. 4therwise we
place the current falling piece to a new position.
"ef timer7vent(self( event/
if event.timer."( == self.timer.timer."(/
if self.is#aitingAfter<ine/
self.is#aitingAfter<ine = 5alse
self.ne!Piece(
else/
self.one<ineBo!n(
else/
QtGui.Q5rame.timer7vent(self( event
In the ti!er e"ent' we either create a new piece' after the pre"ious one was
dropped to the botto!' or we !o"e a falling piece one line down.
"ef remove5ull<ines(self/
num5ull<ines = '
ro!s*oDemove = KP
for i in range(8oar".8oar"Ieight/
n = '
for Q in range(8oar".8oar"#i"th/
if not self.shapeAt(Q( i == *etrominoes.0o;hape/
n = n E )
if n == )'/
ro!s*oDemove.appen"(i
ro!s*oDemove.reverse(
for m in ro!s*oDemove/
for = in range(m( 8oar".8oar"Ieight/
for l in range(8oar".8oar"#i"th/
self.set;hapeAt(l( =( self.shapeAt(l( = E )
...
If the piece hits the botto!' we call the re!o"e-ullLines67 !ethod. -irst we
find out all full lines. And we re!o"e the!. (e do it by !o"ing all lines abo"e
the current full line to be re!o"ed one line down. 1otice' that we re"erse the
order of the lines to be re!o"ed. 4therwise' it would not work correctly. In our
case we use a nai"e gra"ity. This !eans' that the pieces !ay be floating abo"e
e!pty gaps.
"ef ne!Piece(self/
self.curPiece = self.ne,tPiece
self.ne,tPiece.setDan"om;hape(
self.curV = 8oar".8oar"#i"th / % E )
self.curA = 8oar".8oar"Ieight C ) E self.curPiece.minA(
if not self.try>ove(self.curPiece( self.curV( self.curA/
self.curPiece.set;hape(*etrominoes.0o;hape
self.timer.stop(
self.is;tarte" = 5alse
self.emit(Qt2ore.;.G0A<(?message*o;tatusbar(Q;tring?( ?Game over?
The newPiece67 !ethod creates rando!ly a new tetris piece. If the piece cannot
go into it>s initial position' the ga!e is o"er.
The +hape class sa"es infor!ation about the tetris piece.
self.coor"s = KK'('P for i in range(4P
pon creation we create an e!pty coordinates list. The list will sa"e the
coordinates of the tetris piece. -or exa!ple' these tuples 6$' 0;7' 6$' $7' 6;'
$7' 6;' ;7 represent a rotated +0shape. The following diagra! illustrates the
shape.

-igure. /oordinates
(hen we draw the current falling piece' we draw it at self.cur3' self.curJ
position. Then we look at the coordinates table and draw all the four s9uares.

-igure. Tetris

You might also like