[PyKDE] Some fundamentals

Jim Bublitz jbublitz at nwinternet.com
Tue Feb 25 07:37:00 GMT 2003


On 25-Feb-03 Tom Chance wrote:
> I've only just started out with PyQt, so please bear with me as I
> ask some boring questions :)
> 
> I've been reading through the book "GUI Programming with Python:
> QT Edition" by Boudewijn Rempt online (the paper copy is just
> too expensive for a poorly  student like me :-), and though it
> covers a lot of ground, it's written in a very confusing order,
> jumping around between ideas. I'm getting a bit lost trying to
> write a fairly simple application. When I'm confident enough,
> and  I've finished my PyGame tutorial, I'll try my hand at
> writing a PyQt tutorial :)
> 
> Anyway, enough rambling. I'm using Qt Designer to create my GUI,
> and I'm then importing the class in my main program file. At
> the moment, the main program file contains one class that
> inherits the GUI class, and that contains all my functions. I'm
> sure this isn't the best way to do things - I'm used to creating
> multiple classes, each one for a different task, and it seems a 
> little messy having all my function code in one class. What's the
> best way of laying out the code?

Why, the way that works of course :)
 
> Also, I'm struggling with connecting signals and slots. I
> understand the principle, and I'm getting the hang of working
> wiht Qt Designer and my code to create empty functions in
> Designer, and then create the actual functions in my main code,
> but I don't really understand the signal parameter in a 
> connection.

The basic connect function looks like (see QObject::connect in the
Qt docs)

in C++: connect (q1, sig, q2, slot);

q1   = some QObject descendant (sender)
sig  = some signal emitted by q1
q2   = some other QObject descendant (receiver)
slot = some member function that can receive sig 

'sig' and 'slot' also have to agree on the number and type of
parameters being passed. q1 and q2 are pointers, sig and
slot are strings (char *). 'connect' is attached to some
QObject subclass instance, eg: someObject->connect (...)

in Python/PyQt:

    from qt import ..., SIGNAL, ... # DON'T FORGET THIS
    ...
        someObject.connect (q1, SIGNAL ("sig ()"), self.slot)

(note only 3 args instead of the 4 in C++)

Just like in C++, the signal name ("sig") needs to be a string, but
thanks to the magic of sip, you can simply specify the method that
receives the signal (the slot) as above. Usually it's in the
current class (hence the 'self') but doesn't have to be, and of
course it probably won't be named 'slot' either. And again,
'connect' is a method attached to some instance, eg:
someObject.connect (). 

> E.g. I can guess what "pressed(QListViewItem*)" means? But why
> the QListViewItem with an asterisk? And what really confuses me
> is the "int, const Qstring&" stuff. What do they signify, and
> why are they in the signal for a rightButtonClicked(), whilst
> clicked() has no parameters, and pressed only has QListViewItem?

The 'clicked()' signal doesn't pass any parameters to it's
corresponding slot(s), but 'pressed (QListViewItem *)' does (there
are also overloaded versions of 'pressed' that pass additional
parameters, so the argument keeps track of which 'pressed' signal
you're specifying too).

In the example above the signal/slot pair involves no argument
passing, so there's nothing inside the () after "sig". For

    "pressed (QListViewItem *)"

the 'pressed' signal passes a QListViewItem pointer (hence the '*')
in C++. In Python it will pass a QListViewItem instance (no
pointers in Python of course). In either case, the slot (which
you'll probably write) has to be of the form:

C++: SomeClass::slotPressed (QListViewItem *listViewItem);
Python: 
    class SomeClass:
        def slotPressed (self, listViewItem):

where 'listViewItem' expects a QListViewItem instance. In this case
it's the QListViewItem that was pressed, so you can identify what
the user clicked on; for a typical QPushButton press, you already
know that because the slot is connected to only one button. Some
of the other buttons (toolbar buttons for example) emit a 'clicked'
signal that passes an int which is the index of the button pressed,
so you can identify which button on the toolbar the user pressed.

In Python/PyQt you need the C++ notation in the 'connect' call
because Qt is written in C++, and that's where all of the actual
work gets done. You're communicating (through Python and sip) a
connection that's going to be implemented at the C++ level, and C++
cares whether it's a reference to a QListViewItem (no '*') or a
pointer to a QListViewItem (QListViewItem *). There's a little more
to it than that, but I'm far from an expert on the actual
machinery. If you don't know the difference between a reference and
a pointer: a reference is the actual object, a pointer is the
address of the actual object - C++ uses both, Python only uses
references (or instances).

So for any signal in the Qt docs, you just specify the signal's
declaration string, but drop any argument names or return type
(always 'void' anyway, I believe). For example, the Qt docs for
QListView show the signal 'pressed':

    void pressed (QListViewItem *item);

You drop the return type (void) and the argument name (item) and
are left with:

    pressed (QListViewItem *)

which you wrap as a string (inside '' or "") in a SIGNAL call as the
second parameter for 'connect'. The '*' (or an '&' which indicates
a reference) is part of the type, not part of the argument name, so

    QListViewItem* item

and

    QListViewItem *item

both specify an argument named 'item' whose type is
'QListViewItem*', or a pointer to a QListViewItem object. PyQt
(sip) automatically converts all C++ pointers-to-objects into
Python object instances for you.


Jim




More information about the PyQt mailing list