My PyQt Scribbles (Python and Qt) #5: Event-Handling Mechanism (QEvent: moveEvent() and closeEvent())

6 03 2009

In this installment of My PyQt Scribbles we will have a look to the event-handling mechanism.

As I already mentioned it’s my custom to explore new concepts through examples. What I call ‘useful examples’ are the implementation of concepts in plausibly real situation. This means that I won’t just write an example by detaching a particular mechanism from the whole app. I will not write something which is too abstract or that does something that replicate an useless function. This scribbles of mine are mostly an exercise and a tool I exploit to study a subject I like. As far as I can I will implement all the concepts into the building of a specific application which will slowly grow and increase its functionality as I explore further subjects.

Today we will make our application more fashionable by replicating the transparency feature you can see on KDE (with composition manager enabled), Mac OSX and Vista. Basically, our app will get transparent when we move it around the screen. We will also implement a dialog widget which pops up when we try to close the application to ask us if we’re sure to quit or not.

Events are members of the QEvent class and a sort of low level objects that represent things that have happened either in the outside environment or inside the application. They’re processed at different level by the Qt application.
Events can be divided in three different types:

Spontaneous events à they originate outside the application (window system) and are queued and processed by the event loop
Posted events à they are generated by Qt or the application and are queued and processed by the event loop
Sent events à they are generated by Qt or the application but instead to be managed by the loop they’re sent directly to the target object

When an event happens, Qt generates a specific object to represent that specific event. This event is then shipped to the children/parents chain for handling and, if no Object handles it in some way the event object is just discarded.
A corollary to this is that we usually don’t need to send (sendEvent() )or post (postEvent() ) events explicitly because most events are generated automatically by Qt or by the window system when they happen. If you want to “manually” send an event, you can call high-level functions to do this (i.e. update() and repaint()).

event

Events in Qt can be processed on five different levels but the first two are the most common and needed. The last three are rarely used so you don’t need to go deeper in the concept related to them unless you’re a Qt guru (in this case you’re probably wasting your time reading this ‘scrible’).

• Reimplementing a specific event handler.
QObject and QWidget provide many specific event handlers for different types of events (for example, moveEvent() for handling the movements).
• Reimplementing QObject::event().
The event() function is the ancestor of all the object’s events. The default behaviour in QObject and QWidget simply forward the events to the specific event handlers.
• Installing an event filter on a QObject.
An event filter is an object that receives another object’s events before they reach the intended target.
• Installing an event filter on qApp. Exceptionally, an event filter on qApp monitors all events sent to all objects in the application.
• Reimplementing QApplication::notify(). Qt’s event loop and sendEvent() call this function to dispatch events. By reimplementing it, you get to see events before anybody else.

As I said before some type of events can be propagated to the children/parents chain. In this situation, if a target object doesn’t process the event, Qt passes the event to other receivers until reaching the top-level parent object.

This is a brief explanation about what events are and how they work. If you find it confusing just try to grab the basic concepts by studying the code below. One approach I find very useful is not just to copy and paste the code as it is but try to modify it in your own way. You can maybe try to reimplement the basic concept to explore different events or handling them in a different way.
If you want to increase your knowledge you can check the following links and read the articles.

http://doc.trolltech.com/4.4/eventsandfilters.html

http://doc.trolltech.com/qq/qq11-events.html

So lets go on with the example.
As usual only the new parts are commented.

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class WizAndChipsCal(QWidget):

        def __init__(self, parent = None):
                QWidget.__init__(self)
                self.setWindowTitle("Wiz and Chips Calendar")
                self.setWindowIcon(QIcon("C:/Python26/PyQt/Icon/date.png"))
                self.setToolTip("Hello to this Wiz and Chips fancy calendar!")
                self.title = ("<font color=red size=3><b>"\
                              + "Wiz and Chips Pushable Calendar!"\
                              + "</b></font>")
                self.Label = QLabel(self.title)
                self.Label.setAlignment(Qt.AlignCenter | Qt.AlignJustify)

                self.calendar = QCalendarWidget()
                self.calendar.setGridVisible(1)
                self.calendar.setMinimumHeight(180)
                self.calendar.setMinimumWidth(110)

                self.check1 = QCheckBox("check1")
                self.check2 = QCheckBox("check2")
                self.TextBox = QTextEdit("type something here")
                self.TextBox.setMaximumHeight(50)

                self.dateLabel = QLabel("Date:")
                self.dateLabel.setMaximumWidth(80)
                CurrDate = QDate.currentDate()
                self.date = QDateEdit(CurrDate)
                self.date.setMaximumWidth(80)

                self.CloseButton = QPushButton("&Quit")
                self.CloseButton.setToolTip("<font color=red size=2><b>"\
                                            + "Press here to Quit"\
                                            + "</b></font>")
                self.CloseButton.setMaximumSize(50, 25)

                self.infobox = QGroupBox("Info Box")
                self.infobox.setCheckable(1)
                self.infobox.setChecked(0)

                dateLayout = QHBoxLayout()
                dateLayout.addWidget(self.dateLabel)
                dateLayout.addWidget(self.date)
                dateLayout.addSpacing(170)

                GBoxLayout = QVBoxLayout(self.infobox)
                GBoxLayout.setSpacing(1)

                GBoxLayout.addLayout(dateLayout)
                GBoxLayout.addWidget(self.check1)
                GBoxLayout.addWidget(self.check2)
                GBoxLayout.addWidget(self.TextBox)

                Layout = QGridLayout()
                Layout.addWidget(self.Label, 0, 0)
                Layout.addWidget(self.calendar, 1, 0)
                Layout.addWidget(self.CloseButton, 4, 0)
                Layout.addWidget(self.infobox, 3, 0)
                self.setLayout(Layout)

                self.connect(self.CloseButton,
                             SIGNAL("pressed()"),
                             self.close)
        def moveEvent(self, event):
                self.setWindowOpacity(0.7)
                QTimer.singleShot(50, self.opac)
        def opac(self):
                self.setWindowOpacity(1)

        def closeEvent(self, event):

                self.CloseDialog = QMessageBox.question(self, "The application is being closed",
                                                        "Do you really want to exit?",
                                                        QMessageBox.Save|QMessageBox.Yes|QMessageBox.Discard,
                                                        QMessageBox.Discard)
                if self.CloseDialog == QMessageBox.Yes:
                        event.accept()
                elif self.CloseDialog == QMessageBox.Save or QMessageBox.Discard:
                        event.ignore()

app = QApplication(sys.argv)
main_window = WizAndChipsCal()
main_window.show()
app.exec_()
def moveEvent(self, event):
self.setWindowOpacity(0.7)
QTimer.singleShot(50, self.opac)

Everytime the widget is moved (this includes the first time it’s painted on the screen) the function change the widget opacity to make it transparent.
moveEvent() event handler is implemented to receive widget move events which are passed in the event parameter. When the widget receives this event, it is already at the new position.
Once the movement is finished we call QTimer.singleShot which counts a certain number of milliseconds and then calls another function which sets the opacity to 1 thus making the widget opaque again. singleShot is needed to tell QTimer to count just one time. Otherwise the count is made at intervals

def opac(self):
self.setWindowOpacity(1)

setWindowOpacity(1) property holds the level of opacity for the window. The range is from 1.0 (completely opaque) to 0.0 (completely transparent).
Note: This feature is only available on Mac OS X, X11 platforms that support the Composite extension, and Windows 2000 and later.

         def closeEvent(self, event):
                self.CloseDialog = QMessageBox.question(self, "The application is being closed",
                                                        "Do you really want to exit?",
                                                        QMessageBox.Save|QMessageBox.Yes|QMessageBox.Discard,
                                                        QMessageBox.Discard)

This event handler is called with the given event when Qt receives a window close request for a top-level widget from the window system.
We create a dialog widget by implementing QmessageBox.question(). This class displays a dialog widget with an informative text for the user and provides standard buttons to enable the user to interact. By default QMessageBox support preformatted (layout, icons etc..) message boxes for questions (QMessageBox.question()), information (QMessageBox.information()), warning (QMessageBox.warning()) and critical (QMessageBox.critical()).

The configuration of our question box is: QMessageBox.question ( QWidget * parent, QString=title, Qstring=text, StandardButtons=buttons, StandardButton=defaultButton)
Our default button must be picked from the buttons already used, we pick discard in order to make our exit procedure safer. Note: save button will now have the same behaviour of ‘discard’. We will reserve the function for later usage.
There are several standard buttons already specified by the API.
For more information about message boxes see http://doc.trolltech.com/4.5/qmessagebox.html

         if self.CloseDialog == QMessageBox.Yes:
                        event.accept()
                elif self.CloseDialog == QMessageBox.Save or QMessageBox.Discard:
                        event.ignore()

By default, closeEvent eventt is accepted and the widget is closed. We instead reimplement this function to change the way the widget responds to the close request.
If the user press ‘Yes’ we call accept() and the window is closed. If the button pressed is ‘Save’ or ‘Discard’ we call ignore() and the event is thrown away.

calendar2 calendar2kubu

calendar2_1 calendar2_1kubu





My PyQt Scribbles (Python and Qt) #4: Layout Managers (QGridLayout() and more)

5 02 2009

Last time I made a calendar, a quite convenient and clean app in just a few lines of code. Despite its elegant look and feel the code was very basic. By the way this isn’t something bad, however the widgets arrangement was inelegant and that’s something we’re going to fix in this installment.

As usual we’ll focus only on a few objects in order to get a glimpse of a certain subject without exploring it in depth. Our purpose, at the moment, is to understand the basic concept which enable us to create something functional. In particular we will work only on certain classes and certain members of those classes. After having absorbed the concepts, and with the class reference at hand, you can further experiment and refine the subject of your interest.
Lets then put our hands on the calendar and restructure the widgets arrangement.

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class WizAndChipsCal(QWidget):

        def __init__(self, parent = None):
                QWidget.__init__(self)
                self.setWindowTitle("Wiz and Chips Calendar")
                self.setWindowIcon(QIcon("C:/Python26/PyQt/Icon/date.png"))
                self.setToolTip("Hello to this Wiz and Chips fancy calendar!")                

                self.title = ("<font color=red size=3><b>"+\
                             "Wiz and Chips Pushable Calendar!"+\
                             "</font></b>")
                self.Label = QLabel(self.title)
                self.Label.setAlignment(Qt.AlignCenter | Qt.AlignJustify)

                self.calendar = QCalendarWidget()
                self.calendar.setGridVisible(1)
                self.calendar.setMinimumHeight(180)
                self.calendar.setMinimumWidth(110)

                self.check1 = QCheckBox("check1")
                self.check2 = QCheckBox("check2")
                self.TextBox = QTextEdit("type something here")
                self.TextBox.setMaximumHeight(50)

                self.dateLabel = QLabel("Date:")
                self.dateLabel.setMaximumWidth(80)
                CurrDate = QDate.currentDate()
                self.date = QDateEdit(CurrDate)
                self.date.setMaximumWidth(80)

                self.CloseButton.setToolTip("<font color=red size=2><b>"+\
                                            "Press here to Quit"+\
                                            "</font></b>")
                self.CloseButton.setMaximumSize(50, 25)

                self.infobox = QGroupBox("Info Box")
                self.infobox.setCheckable(1)
                self.infobox.setChecked(0)

                dateLayout = QHBoxLayout()
                dateLayout.addWidget(self.dateLabel)
                dateLayout.addWidget(self.date)
                dateLayout.addSpacing(170)

                GBoxLayout = QVBoxLayout(self.infobox)
                GBoxLayout.setSpacing(1)
                GBoxLayout.addLayout(dateLayout)
                GBoxLayout.addWidget(self.check1)
                GBoxLayout.addWidget(self.check2)
                GBoxLayout.addWidget(self.TextBox)

                Layout = QGridLayout()
                Layout.addWidget(self.Label, 0, 0)
                Layout.addWidget(self.calendar, 1, 0)
                Layout.addWidget(self.CloseButton, 4, 0)
                Layout.addWidget(self.infobox, 3, 0)
                self.setLayout(Layout)
                self.connect(self.CloseButton,
                             SIGNAL("pressed()"),
                             self.close) 

app = QApplication(sys.argv)
main_window = WizAndChipsCal()
main_window.show()
app.exec_()

Now we comment the most important passsages.

class WizAndChipsCal(QWidget):

QWidget() is the base class of all user interface objects. QWidget is the core of the user interface: all the other widget or window classes inherit from it.

self.calendar = QCalendarWidget()
self.calendar.setGridVisible(1)
self.calendar.setMinimumHeight(180)
self.calendar.setMinimumWidth(110)

We begin by creating all the various widgets we need to compose our GUI.
We use the .setMinimumHeight and .setMinimumWidth methods to fix the minimum dimensions that we desire for our calendar widget. These method can hold integers.

self.check1 = QCheckBox("check1")
self.check2 = QCheckBox("check2")
self.TextBox = QTextEdit("type something here")
self.TextBox.setMaximumHeight(50)

We create two check boxes with QcheckBox() class to use them later. We create a box which can be filled of text by the user with QTextEdit() class. For layout convenience we fix the edit box’s maximum height with .setMaximumHeight method.

self.dateLabel = QLabel("Date:")
self.dateLabel.setMaximumWidth(80)
CurrDate = QDate.currentDate()
self.date = QDateEdit(CurrDate)
self.date.setMaximumWidth(80)

Now we create a plain label with QLabel() class and set the label maximum width. At this point we wanna create a date spinbox, an object which shows the date, in a certain format, and that can be managed by the user. The first thing we do is to create an object to hold the current date. .currentDate method, which belong to QDate() class,  gets the current date from the system clock.
Having done this we create the date spinbox with the QDateEdit() class and pass it the current date container we created before as argument of the class. At this point we begin to take care of the arrangement of the various widgets inside the parent QWidget window. To reach this general purpose we focus on the layout. In PyQt there are various classes which takes care of laying out the widgets. For exploration’s sake we’ll use three of them here.

self.infobox = QGroupBox("Info Box")
self.infobox.setCheckable(1)
self.infobox.setChecked(0)

QGroupBox class provides a box which contains child widgets. It’s an elegant way to organise the space inside a GUI. We call the .setCheckable and set it to true to turn the info box title in a check box. In this way the child widgets are accessible only if the QGroupBox is checked otherwise they’re greyed and inaccessible. By default checkable QgroupBox are checked. We don’t want it to be in this state thus we set the boolean parameter of .setChecked method to false.

dateLayout = QHBoxLayout()
dateLayout.addWidget(self.dateLabel)
dateLayout.addWidget(self.date)
dateLayout.addSpacing(170)

We use a specific layout manager to arrange the widgets relevant to the date subject. We want the date spinbox to have a label on its left. This is an horizontal arrangement so we call the QHBoxLayout() class which inherits from QBoxLayout().

qhboxlayout1

We add first the label widget then the date spinbox widget and finally a spacer, by means of .addSpacing method, and givie it a dimension in pixel. We need this spacer because the general layout of the GUI –which we will take care of very soon- will force this widgets to position themselves so to get all the space pre-sized for them by the largest widget in the GUI –which in our case is the calendar itself. The spacer is basically an invisible widget which we can comfortably use to obtain our desired arrangement.

GBoxLayout = QVBoxLayout(self.infobox)
GBoxLayout.setSpacing(1)
GBoxLayout.addLayout(dateLayout)
GBoxLayout.addWidget(self.check1)
GBoxLayout.addWidget(self.check2)
GBoxLayout.addWidget(self.TextBox)

At this point we arrange the full content of the QgroupBox. At first we create a layout and since we want to arrange all the widget vertically we now use the QVBoxLayout. Being a brother or sister of QHBoxLayout, QVBoxLayout provides a vertical layout arrangement for the contained objects.
qvboxlayout
We want the widgets to occupy the fewest possible space so we call the .setSpacing method set the vertical space between the widgets to the value of 1. Before adding widgets to the layout we add a complete layout. In this way we can nest the horizontal layout which we create before, into the vertical layout. Then we add the remaining widgets to the vertical layout container.

Layout = QGridLayout()
Layout.addWidget(self.Label, 0, 0)
Layout.addWidget(self.calendar, 1, 0)
Layout.addWidget(self.CloseButton, 4, 0)
Layout.addWidget(self.infobox, 3, 0)
self.setLayout(Layout)

At this point we take care of the general GUI layout (without mentioning the underlying main window). To to this we use the QGridLayout() class. QGridLayout() is a class meant to lay out widgets in a grid. It inherits from QLayout class which is the abstract base class of geometry managers. QGridLayout gets the available space (the parent layout or parent widget) and slice it in columns and rows thus forming cells. We can then easily place our widgets in the desired cells in order to structure our GUI space.

qgridlayout1

After creating the layout we call the .addWidget method to add the widgets to the grid at the desired row and column position. The first parameter of the method is the widget (or layout also) to be added, then we specify the column and row by means of integer numbers. After having finished to position the widgets we call .setLayout with our layout as argument to set the general layout to the parent widget. Here below you can see the result both in Windows XP and in Kubuntu 8.10 with KDE 4.2.

calendar1 calendar1kubu

calendar1_11 calendar1_1kubu2





My PyQt Scribbles (Python and Qt) #3: A calendar in 30 or so lines

14 12 2008

I often amuse myself exploring APIs and experiment classes and functions which seem attractive or curious.
I’ve always thought that experimenting is a much more interesting and effective way to learn something than merely theoretical study.

By messing around with PyQt classes I stumbled upon the QCalendarWidget class and I had a sparkle.

Being a project manager I happen to use calendars quite much for scheduling and I always find those I use rather uncomfortable. MS Outlook calendar is a mess and for some reason (at least that installed on my office pc) it doesn’t shows week numbers. The “Date&Time” XP app (the one appearing by double clicking the time displayed in the right corner of the systray) doesn’t show the week numbers and the navigation of months and years is rather uncomfortable. The big company calendar pinned on the wall is fine but during the last 2 or 3 months of each year we reach that “dark zone” where there’s me that must schedule activities in the first months of the new year and the huge calendar shows only the month of January(NewYear).
So I thought that this PyQt calendar could be a nice season-so experiment for my journey into PyQt.

I coded a bit and realised that the result was far more better than all the calendars surrounding me. No special functionality for the moment but it’s small, fast, simple, clean, easy to navigate and shows the week numbers. Yippee!!

I started from the first gui created in the previous installment so I won’t comment the parts already seen last time.

here we go:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class WizAndChipsCal(QMainWindow):
        def __init__(self, parent = None):
            QMainWindow.__init__(self, parent)
            self.setWindowTitle("Wiz and Chips Calendar")
            self.setGeometry(300,300,300,220)
            self.setWindowIcon(QIcon("C:/Python26/PyQt/Icon/date.png"))
            #self.setWindowIcon(QIcon("/home/MY_USR/PyQt/Icon/date.png")) - on Linux
            self.setToolTip("Hello to this Wiz and Chips fancy calendar!")

            self.CloseButton = QPushButton("&Close", self)
            self.CloseButton.setGeometry(26, 190, 50, 25)
            self.CloseButton.setToolTip("<font color=red size=2><b>" + "Press here to Quit" + "</font></b>")

            self.title = ("<font color=red size=4><b>" + "Wiz and Chips Pushable Calendar!" + "</font></b>")
            self.Label = QLabel(self.title, self)
            self.Label.setGeometry(45, 5, 250, 15)

            self.calendar = QCalendarWidget(self)
            self.calendar.setGridVisible(1)
            self.calendar.setGeometry(26, 30, 250, 150)

            self.connect(self.CloseButton,
                         SIGNAL("pressed()"),
                         self.close)

app = QApplication(sys.argv)
main_window = WizAndChipsCal()
main_window.show()
app.exec_()
# the underscore is used to avoid confusion with pyhton built-in exec()

And now some notes about the new parts:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

This time I decided to import all the classes from the modules I need so to avoid using module prefix every time I need a module object (i.e. avoid -> QtGui.QIcon)

self.CloseButton = QPushButton("&Close", self)
self.CloseButton.setGeometry(26, 190, 50, 25)
self.CloseButton.setToolTip("<font color=red size=2><b>" + "Press here to Quit" + "</font></b>")

Here comes a new object: a push button. QPushButton is the class we need to create the button. The arguments are the button label and the parent where the button is placed.The ampersand before the “C” provides ALT+C to activate the button.One more time the setGeometry method sets the relative position(x,y) onto the screen and the size (w,h) of the Button.

We use setToolTip method we used before but we specify it for our button (self.CloseButton).
setToolTip accepts HTML tags so we can fancily specify size, colors and more if we want

self.title = ("<font color=red size=4><b>" + "Wiz and Chips Pushable Calendar!" + "</font></b>")
self.Label = QLabel(self.title, self)
self.Label.setGeometry(45, 5, 250, 15)

I want to create a title, within the widget, for our tiny app, so I create a label using the QLabel class.
Since I don’t want to put the label raw text directly as the label argument, I create instead a “title” object just to specify the text and then assign it to the label object.
QLabel accepts HTML tags so we can fancily specify size, colors and more if we want.

self.calendar = QCalendarWidget(self)
self.calendar.setGridVisible(1)
self.calendar.setGeometry(26, 30, 250, 150)

Here comes the funny part. PyQt QCalendarWidget() class provides a nice calendar which perfectly suits my purpose. setGridVisible() method creates a grid for the calendar once it’s set to 1

self.connect(self.CloseButton,
SIGNAL("pressed()"),
self.close)

Before we created a button but now we need to write some code to make that button actually perform an action.
This is somewhat tricky in PyQt (at least for me at the moment and compared to what I remembered of Tkinter). Anyway, we need to invoke the connect function* and tell it 3 things:
1- the emitter (the button in our case)
2- the signal to connect (SIGNAL(“pressed()”)
3- the function called to perform the action

* connect inherits from QObject class of QtCore module

Here below how the calendar looks in Kubuntu 8.10 (with KDE 4.1 and Oxygen theme) and MS Windows XP.

calendarkubu calendarwin1

There are two things to be noticed about the final product. The first thing is that the calendar is quite functional and the second one is that, despite it’s apparent smoothness and functionality, the code is rather primitive and not so elegant. For example we haven’t used any layout manager to arrange our widget so we better remedy to this point later on.

Note for Windows users. If you save your calendar file with .pyw extension you will be able to open it smoothly avoiding python console to pop up.





Who’s scared of Python 3.0?

6 12 2008

Python 3.0 (a.k.a Pyhon 3000, a.k.a. Py3K) is the new release of the most wonderful (in my biased opinion) language in the coding world.

python-logo-master-v3-tm1This is a M-major release which, as the title of this post suggest, contains a glimpse of gloom inside it -at least for someone-.

The fact is that Python 3.0 happens to be incompatible with the 2.x releases. The language of course is the same but there are significant differences that make most of the scripts written say with 2.5 stop running if passed to a python 3.0 interpreter.

On December 4th Guido Van Rossum, the creator of Python, drew up a What’s new in Python 3.0 document to be found here.

Since I’ve no intention to go through every detail of the changelog I’ll limit myself to tell just the most relevant change (or those that seems that to me).

- print statement becomes a function (and that’s one of the biggest pain in the ass for code written with previous releases).
before we used to write:
>> print “Wiz and Chips rocks!”
now we must call the function:
>> print (“Wiz and Chips rocks!”)
there are however many more and less trivial effects on the print statement (ehm.. function) to impact the new coding style.

- The ordering comparison operators (<, <=, >=, >) raise a TypeError exception when the operands can’t be naturally compared one another. Expressions like 1 < “”, 0 > None or len <= len are no longer valid. This however doesn’t apply to == and != operators.

- long int type disappears. There’s just one integer type int which essentially behave like the old long.

- An expression like 75/27 now returns a float. To get truncated value just use 75//27.

- The repr() of a long integer doesn’t inlude the L character at the end of the representation. So if you have code that cut off that character by default it will now cut the last digit instead.

- Unicode strings and 8-bits string system is suppressed and changed by Python 3.0 with the concepts of text and binary data. The type used to store text is str and the type used to store data is bytes. Any attempts to mix text and data in Python 3.0 will raise a TypeError. This is a useful rationalisation as the previous system was inelegant and prone to generate flocks of bugs. This new concept however will certainly create lots of incompatibilities with codes out there which include both encoded and unencoded text. As str and bytes types can’t be mixed they must explicitly converted (str.encode() –> str to bytes – bytes.decode() –> bytes to str). Bytes is immutable but there’s a mutable form called bytearray.

- as and with are reserved words in Python 3.0 (but they were introduced in 2.6)

- List comprehensions no longer support the syntactic form  for x in item1, item2, …, we must use instead for x in (item1, item2, …).

- The from MODULE import * syntax is only allowed at the module level, no longer inside functions.

- There’s a new system for the string formating operations that replaces % operator. Thank God % it’s still supported in 3.0 but will be deprecated by 3.1 and removed some time later. If you’re interested in the new formatting system here’s an extensive documentation about it.

- raw_input() is replaced by input() which also means that 3.0 input() isn’t the same as 2.x input()

These are the main points that caught my superficial attention. I don’t plan switching to 3.0 in the immediate future. My bet is that Python 3.0 usage path will be that of a flat curve. My concern in this field is about modules and extensions. Python has simply tons of them which enable you to pursue plainly every kind of activity you have in mind. Despite the release builtin modules I can’t conceive an app written in python which doesn’t rely on third part modules. Well, let alone the enterprise developed and supported libraries (i.e. reportlab which currently doesn’t support 3.0 anyway), the scenario of small and often very useful libraries to be converted to Python 3.0 is not so happy in my mind. It will take time and maybe some crucial library will maybe remain relegated to the 2.x version of the language for God knows how many months / years.

The good news with this respect is that a 2to3 source-to-source translator is provided to be run on your source code. This tool should do most of the works to translate your code to be Python 3.0 compliant. The bugs remaining after a run under 3.0 must be however be fixed manually. For more information regarding this tool please read this page.

A last concern regards performance. They say that Python 3.0 runs the pystone benchmark around 10% slower than Python 2.5.  They say there’s room for improvement, however this is not so encouraging given that python’s not known to be a fast language.

Python 3.0 is clearly a milestone release which main aim’s that of rationalise and clean the language builtins. We will see if this release will improve the already boosting success of this wonderful language.





My PyQt Scribbles (Python and Qt) #2: a plain window in PyQt

30 11 2008

Today we will create a main window, set a window title, an icon and a tooltip related to the window.

First of all let’s check that our PyQt is well installed and working. To do this just type: import PyQt4 from IDLE and press enter. If nothing happens we’re fine. If it shows an error message like “ImportError: No module named PyQt4″, try to check your installation (see My PyQt scribbles #1).

If everything is fine we can start.

I will first present the code as a whole and then proceed through it to analyse the various parts.

import sys
from PyQt4 import QtGui

class HelloWorldWindow(QtGui.QMainWindow):
        def __init__(self, parent = None):
                QtGui.QMainWindow.__init__(self, parent)
                self.setWindowTitle("My First Qt Window")
                self.setGeometry(300,300,250,150)
                self.setWindowIcon(QtGui.QIcon("C:/Python26/PyQt/Icon/gadu.png"))
                self.setToolTip("Hello to this Wiz and Chips example!")

app = QtGui.QApplication(sys.argv)
main_window = HelloWorldWindow()
main_window.show()
app.exec_()

We begin importing the needed modules.

import sys
from PyQt4 import QtGui

Sys is needed to initialise the QApplication class. This class manages the application control flow and the main settings. QApplication contains the main event loop (where all events from the window system and other sources are processed and dispatched), the application initialisation and finalization. For any GUI application based on Qt there must be one QApplication object, no matter how many windows are displayed.

QtGui is the module which contains the GUI classes. As a matter of fact extends the QtCore module with GUI functionality

We now create a main class:

class HelloWorldWindow(QtGui.QMainWindow):

The argument of our window class refers to another class, QMainWindow, which supplies a main application window.

main
The layout has a center widget area where any kind of widget can be placed. You can add QToolBars, QDockWidgets, a QMenuBar, and a QStatusBar. It’s not currently possible to create a main window without a central widget. You must have a central widget even if it is just a placeholder.

Now we create a function to initialise the class

def __init__(self, parent = None):
            QtGui.QMainWindow.__init__(self, parent)

this is to initialise the main window. __init__ is a special function in python which is used to set up the object using the arguments to make variables for the object. __init__ is called upon the object creation.

Now it’s time to shape a bit our window.

self.setWindowTitle(“My First Qt Window”)

The setWindowTitle() method sets the window title

self.setGeometry(300,300,250,150)

The setGeometry method sets the relative position (x,y) on the screen and the size (w,h) of the window

self.setWindowIcon(QtGui.QIcon(“C:/Python26/PyQt/Icon/gadu.png”))

This method sets the window icon. For my test I have used a crystal clear project icon (http://www.everaldo.com/crystal/). For windows user be sure to use “/” as folder separator instead of “\”. The latter is used for escapes in python.

self.setToolTip(“Hello to this Wiz and Chips example!”)

With this method we specify a tooltip related to our present object: the main window

app = QtGui.QApplication(sys.argv)

QApplication class manages the GUI control flow and main settings

main_window = HelloWorldWindow()
main_window.show()

The show() method displays the widget on the screen

app.exec_()

This is to enter the main loop

Here below you can see the result: a window with all the accessories we have defined both in Windows XP and Linux Kubuntu 8.10 KDE 4.1 fashion.

1stcode 1stcodekubu1

Pretty neat result isn’t it? And without too much effort also! At this very early point PyQt seems quite cool and easy to me. Let’s see what we can pull out of it.

As always.. stay tuned folks!

Disclaimer: I’m not a prefessional python programmer nor I pretend to be. I am just an amateur willing to learn and share its by-no-means-guarantee-as-it know-how with the reader. I nevertheless hope you will enjoy my scribbles and maybe find them somewhat stimulating and helpful.





My PyQt Scribbles (Python and Qt) #1

26 11 2008

In this first installment of My PyQt Scribbles I will briefly introduce the Qt (PyQt) framework.

We will work with PyQt4 and Python 2.6. I will try as much as possible to test the code either on Linux (Kubuntu 8.10 currently) or Windows XP.

Let’s start with a note on the installation.

For Windows users it’s quite trivial (as usual) to download the binary from this page of Riverbank website. If you intend to use same tools I’m using then be sure of downloading the package for Python 2.6 (PyQt-Py2.6-gpl-4.4.4-2.exe). For Linux unfortunately there’s no binary available but only the source for you to compile. My advice is to install the packages through Synaptict or Adept. Just look for python-qt4 in the repository.

PyQt, as binding of Nokia (former Trolltech) Qt, is a very complete library whose classes have been split is several extension modules.

The most important ones are the following:

modules

And directly from the PyQt reference guide…

QtGui module: This contains the majority of the GUI classes.

QtCore module: This contains the core non-GUI classes, including the event loop and Qt’s signal and slot mechanism. It also includes platform independent abstractions for Unicode, threads, mapped files, shared memory, regular expressions, and user and application settings.

QtNetwork module: This module contains classes for writing UDP and TCP clients and servers. It includes classes that implement FTP and HTTP clients and support DNS lookups.

QtXml module: This module contains classes that implement SAX and DOM interfaces to Qt’s XML parser.

QtSvg module: This module contains classes for displaying the contents of SVG files.

QtOpenGL module: This module contains classes that enable the use of OpenGL in rendering 3D graphics in PyQt applications.

QtSql module: This module contains classes that integrate with SQL databases. It includes editable data models for database tables that can be used with GUI classes. It also includes an implementation of SQLite.

phonon module: This module contains classes that implement a cross-platform multimedia framework that enables the use of audio and video content in PyQt applications.

Qt module: This module consolidates the classes contained in all of the modules described above into a single module. This has the advantage that you don’t have to worry about which underlying module contains a particular class. It has the disadvantage that it loads the whole of the Qt framework, thereby increasing the memory footprint of an application. Whether you use this consolidated module, or the individual component modules is down to personal taste.

We will begin referencing to QtGui directly -thus not calling PyQt directly-. As it happens to many voyages also my journey into PyQt has not an established trail or end. This means we will implement features together and possibly refer to many of the modules later.

As I always say, stay tuned folks!





The essence of Python

19 11 2008

python

That’s brilliant and a picture of why Python’s so cool!

Follow the XKCD webcomic for more comics about romance, sarcasm, math and language.

XKCD updates every Monday, Wednesday and Friday





My PyQt Scribbles (Python and Qt) #0

13 11 2008

My intention is to write a series of posts discussing practical ways of working with PyQt. I’ve recently thought about the fact that blog posts can be a formidable way to note down things I may need to refer to someday in the future. This is a sorta rediscovering the meaning of a journal: an organic (or not) bunch of entries and annotations which, by growing in time, become a precious reference for the writer.

This thought of mine got stuck to another mental post-it I had about learning PyQt which eventually lead me to shape this column.

qt_logostrap_cmykQt is an application development framework mostly used to create graphical applications (and also non GUI apps). It’s created and maintained by Qt Software (formerly Trolltech), a Norwegian company acquired by Nokia since June 2007. Qt is know to be a cutting edge library designed to supply advanced features which can be implemented with flashy code and deployed on several platforms like Linux, Windows, Mac OS, Windows CE and Embedded Linux. Qt has been used to create well-known apps like KDE, GoogleEarth, VLC, Skype, Photoshop Elements, Qtopia, Virtual Box, etc…

PyQt is the Python binding of the very famous library Qt and it’s created and maintained by the British company Riverbank.

python-logo-master-v3-tmPython is a high level, interpreted, object oriented (even if it supports other types of programming paradigms), open source programming language. It’s a fairly young language which is getting more and more consensus among the developers  mainly thanks to some features which makes Python the most desirable choice for a wide range of tasks. Python focuses on simplicity and elegance; the syntax and semantics are minimalistic: something which lead to an increased productivity and a less painful code maintenance. Python gets rid of twisted structure and useless fripperies like brackets, thus enhancing readability. Despite its minimalism Python offers a huge standard library.

Beyond all this it’s worth saying that Python’s also my favourite programming language.

For sure Python hasn’t the power, in terms of CPU squeezing, of languages like C or C++, but unless you are developing the engine for a real time 3D graphics application, like a cutting edge video game, then my opinion is that for 90% of your needs Python is simply unbeatable.

Stay tuned on this channel to read the first installment of My Journey Into PyQt

Note on licensing:

The Open Source Editions of Qt is freely available for the development of Open Source software governed by the GNU General Public License (GPL). For more information…

PyQt v4 is available on all platforms under a variety of licenses including the GNU GPL (v2 and v3). If your use of PyQt is compatible with the GPL then you do not need to buy a commercial PyQt license. Similarly you do not need to buy a commercial Qt license. For more information…

Python is licensed under The Python Software Foundation License (PSFL) which is a BSD-style, permissive free software license compatible with the GNU General Public License (GPL). For more information…





That’s a Python_ic irony!

22 10 2008

While discussing a thread called “Should I study Python” in the Python section of the software development forum in DaniWeb, Ene Uran said:

Python? That is for children. A Klingon Warrior uses only machine code, keyed in on the front panel switches in raw binary.

That’s the blazing irony I’d like to read!