PyQT: Getting Started

PyQT is used in Python for creating graphical user interfaces. This article gets you started with the basics of PyQT.

In the world of Windows and window managers, GUIs have become an inseparable component of an application. This directly translates into APIs and toolkits for building and integrating GUIs into the applications. Each language has its own set of APIs for the purpose of building the user interface. For Java it is AWT and Swing, for .Net it is Window Forms.

However, even in this area, it is the scripting languages that have the upper hand in terms of toolkits available for building GUIs. The best example is Python. It has bindings for nearly all the GUI toolkits: MFC on Windows, KDE APIs on Linux and even lesser known ones like the Fox Toolkit.

But the best of the lot is the bindings provided by QT. QT is the toolkit that has become the base for KDE. The QT bindings for Python are known as PyQT. In this discussion I will be focusing on the basics of PyQT. The first section will be about QT, the terminology of QT based development and how things are mapped in PyQT. The second section will discuss the steps required for PyQT application creation. The third section will be dedicated to the traditional hello world program, but with a twist. So let’s get started.

{mospagebreak title=PyQT: Understanding the Terminology}

The characteristic feature of any scripting language, including Python, is that it don’t have a native GUI interface. But this has, in a way, become an advantage. Any existing GUI toolkit can be wrapped up and used as a binding for the language. This is exactly what Phil Thompson did when he wrapped QT, thus producing PyQT. In essence, PyQT is still has QT as its foundation. Hence understanding the basics and terminology of QT must come first. The most obvious question from the uninitiated is, what is QT? That’s where I am going to begin.

What is QT?

By definition QT is “a multi-platform C++ application framework which can be used by developers to write single-source applications capable of running natively on Windows, Linux, UNIX, Mac OS X and embedded Linux.” In short, it means write once, compile anywhere. The reason for this is that QT APIs are the same for all platforms and produce native executables.

This brings out another point. Doesn’t Java promise the same thing? There is a big difference. Java achieves platform independence by means of a Virtual Machine, whereas in the case of QT, the source needs to be compiled for each of the target platforms. This helps keep it lightweight and significantly faster. 

Now that you know what QT is, the next important issue is understanding the types of Objects available on QT. There are two kinds of objects in QT, Visual Objects and Non-visual Objects.

Visual Objects includes menus, buttons, icons and so on. They are also known as Widgets. From here onwards  I will be referring to the Visual Objects as Widgets. All the Widgets are form objects.

Non-visual Objects are objects apart from Widgets that provide service but don’t have any visible shape, size or such properties. Timers, painters etc. form a part of such objects. Though, they don’t “exhibit” any visual properties, they are used on a par with Widgets. Timer (or QTimer) is the best example. It is not visible at runtime but almost all the multi-threaded applications use QTimer for their workings.

In a discussion on PyQT and for that matter QT, two terms figure prominently: Signals and Slots. These two represent the even-driven paradigm in the world of QT (and PyQT). I explain them in the next two paragraphs.

Signals are emitted by an object when its state changes. In other words, Signals are events that are generated when the internal properties of an object change. Whenever a Signal is emitted, the connected Slot is executed automatically, which is just like calling a function. The execution of Slots is independent of the GUI event loop. If a number of Slots are connected with a Signal, on the emitting of the Signals, these Slots are executed in an arbitrary manner.

Slots are simple functions that are called when a Signal is emitted. Though a Slot is a simple function, one feature makes it special: it can be connected to a signal. In other words, a Slot is a callback function. A Slot can be public, private, protected and even virtual (in terms of QT). The relationship between Signals and Slots is many-to-many.

That’s all there is to understand about the basic terminology of QT and PyQT. The next step is to understand how QT is mapped with PyQT. The best way to understand this is to understand the steps involved in creating a PyQT application. That is what next segment is about.

{mospagebreak title=Steps for PyQT Application Creation}

There are five main steps to create a simple PyQT application, which are:

1. Importing the required Packages.

2. Creating QApplication object.

3. Adding the required Widgets.

4. Setting up the Signal-Slot connection for the Widgets.

5. Starting the event loop.

Of these, the first, second and fifth are mandatory for even a simple application devoid of any Widgets and events. The whys and wherefores of all these steps are as follows:

Importing the required Packages

Though this is the preliminary step in any application creation, in this case it merits a special mention. The reason is dependency. To create any PyQT application the qt library has to be imported thus:

from qt import *

Apart from this, one more library is required; that is:

import sys

The qt library is dependent on the sys library because the command line parameters are read by the QApplication for which the sys library is required. The command line can contain options such as “-style=platinum” to have the Mac OS 8.5 look and feel. The point to be kept in mind is that advanced functionality such as the canvas have been divided into separate modules, like qtcanvas for QCanvas.

Creating QApplication object

Next is the QApplication object. It handles the dispatching of events generated by the keyboard and the mouse to the various widgets. In essence it is the QApplication object that controls the GUI’s control flow and main settings. It contains the main event loop. It is in the main event loop that all events from the window system and other sources are processed and dispatched. The initialization, finalization and session management for an application are managed by the QApplication object. Whatever be the number of windows, there will only be one QApplication object. For example, to create a QApplication object named app the statement would be:

app=QApplication(sys.argv)

In the above code the command line parameters are passed to the QApplication by using sys.argv.

Adding the required Widgets

This step varies according to the requirements. It can be as simple as a single button with no window to an MDI style widget placement. Whatever the case may be, there are three things to be done while adding the widgets. The first thing is the creation of the object. The second thing is adding the widgets to the containers. Sometimes the widgets themselves can act as containers. Finally, the third task is to make the widget visible. Taking the simplest case, to add a simple button named button the code would be:

button=QPushButton(“Hello World”, None)   

app.setMainWidget(button)
button.show()                 

Here, the button has no parent. Hence “None” is passed as the second parameter. Then the button object is set as the main widget by calling setMainWidget() on QApplication object with the button object. This tells app that button is the main widget. Next line makes the widget visible.

Setting up the Signal-Slot connection for the widgets

Once the widgets are added, next step is setting up the Signal-Slot connections for the added widgets. This is done using the connect() method of QApplication. The connect() method takes four parameters: first the object that sends the signal; second the Signal that is being emitted by the object passed as the first parameter; third the object that would be receiving the signal; and the final parameter is the Slot in which the Signal would be received. To put it in code:

app.connect(button, SIGNAL(“clicked()”),  app,   
            SLOT(“quit()”))

Let’s analyze this. The first parameter is the button object. Its “clicked” signal is being connected to the app’s quit Slot. In more general terms, when the button is clicked, the “clicked” Signal would be emitted and would be “sent” to the “quit” Slot, and the function defined for the Slot would be executed.

Setting up the event loop

Everything is set up. However, until the event loop is started, nothing will take place. As stated earlier, it is the event loop where the processing and dispatch of events takes place. To start the event loop, the exec_loop() of QApplication object is to be called. In code:

App.exec_loop()

These steps are the common steps taken when creating a PyQT application. Also these steps detail how QT is mapped with PyQT. However, unless a real world application is shown, theory is just theory. In the next section, I will be developing an application in which a slider’s movement will be translated into display of a text box. Though it is not a standard application, it will become a component in the future application that I will be developing as part of this series on PyQT.

{mospagebreak title=PyQT in the Real World}

In real world applications, there would be at least two classes, one that sub-classes a container class such as QDialog and a second that would inherit the first one and set up the QApplication object. For the sake of brevity, in this discussion only one class will be used, that will be derived from the QDialog class. So let’s get started.

First the imports:

import sys
from qt import *

Next the class that derives from QDialog. It is better to derive from QDialog if you require a lightweight application:

class Form1(QDialog):
:
:

Now the constructor for this class. The main parameters to look out for are the parent indicating the parent of the dialog, the name of the dialog and the flag indicating whether the dialog is modal or not.

class Form1(QDialog):
  def __init__(self,parent = None,name = None,modal =
0,fl = 0):
    QDialog.__init__(self,parent,name,modal,fl)
   :
   :

Next are the two components to be used, QLCDNumber and QSlider. Their objects are instantiated by passing their names and the equivalent of the “this” pointer of C++ – self. Then the geometry is set to set the boundaries:

class Form1(QDialog):
  def __init__(self,parent = None,name = None,modal = 0,fl = 0):
    QDialog.__init__(self,parent,name,modal,fl)
     self.lCDNumber1 = QLCDNumber(self,”lCDNumber1″)
 
   self.lCDNumber1.setGeometry(QRect(110,140,301,30))

     self.slider1 = QSlider(self,”slider1″)
     self.slider1.setGeometry(QRect(130,220,261,31))
     self.slider1.setOrientation(QSlider.Horizontal)                                           

     :
     :

Then connect the QLCDNumber and QSlider. The Signal is “valueChanged” and the slot is “display.” Since the display of the QLCDNumber is the receiver and the slot, they are not separately used.

class Form1(QDialog):
  def __init__(self,parent = None,name = None,modal = 0,fl = 0):
      QDialog.__init__(self,parent,name,modal,fl)
       self.lCDNumber1 = QLCDNumber(self,”lCDNumber1″)
       self.lCDNumber1.setGeometry(QRect(110,140,301,30))
             
       self.slider1 = QSlider(self,”slider1″)
       self.slider1.setGeometry(QRect(130,220,261,31))
       self.slider1.setOrientation(QSlider.Horizontal)

     
self.connect(self.slider1,SIGNAL(“valueChanged
(int)”),  
                   self.lCDNumber1.display)
      :
      :

Lastly, we have the main section where QApplication will be set up:

class Form1(QDialog):
  def __init__(self,parent = None,name = None,modal = 0,fl = 0):
    QDialog.__init__(self,parent,name,modal,fl)
     self.lCDNumber1 = QLCDNumber(self,”lCDNumber1″)
     self.lCDNumber1.setGeometry(QRect(110,140,301,30))

     self.slider1 = QSlider(self,”slider1″)
     self.slider1.setGeometry(QRect(130,220,261,31))
     self.slider1.setOrientation(QSlider.Horizontal)         

     self.connect(self.slider1,SIGNAL(“valueChanged(int)”),  
                     self.lCDNumber1.display)

if __name__ == “__main__”:
    a = QApplication(sys.argv)
    QObject.connect(a,SIGNAL(“lastWindowClosed()”),a,SLOT
(“quit()”))
    w = Form1()
    a.setMainWidget(w)
    a.exec_loop()

That’s all. Whenever the value of the slider changes, the new value is displayed in the  QLCDNumber.

That brings us to the end of this discussion. It should be evident from the above application how easy it is to develop applications using PyQT. But this is just the beginning. In the future, I will cover other aspects, including complex widgets such as qtcanvas. Till next time.

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort