Saturday, November 6, 2010

Getting Interactive With PyQt

One of the cooler features with PyQt (IMHO) is the possibility to write Qt code interactively. It isn't actually something new and I'm sure it's been there for a while but some of you might not be aware of it. I find it very useful when I want to learn new things in Qt, so without further ado, here's a short introduction on using it.

Start an interactive python session by executing python in a shell:
$> python
Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
Let's create a simle top-level window (I wont add the '>>>' in case you would like to copy/paste the code):
from PyQt4.QtCore import *
from PyQt4.QtGui import *
app = QApplication([])
window = QWidget()
window.resize(400, 300)
window.show()
Now you should have a window similar to the screen shot below:

Ok, let's create a push button:
button = QPushButton("Click Me!", window)
Hmm, no button shows up... Why? Well, that's because we need to make it visible after we have added it to the window:
button.show()
Ahh, sweet! We have added the button to the window interactively:
Let's put the button at the center of the window by using a layout manager:

layout = QHBoxLayout(window)
layout.addWidget(button)


And finally, let's see how 'layout.addStretch()' affects the layout:
layout.addStretch()

You can easily add a slot to the button's clicked signal:
def mySlot():
    print "Button Clicked"
button.clicked.connect(mySlot)
As you can see, it's an easy way to try out thing in Qt.

Thanks for reading!

Monday, September 27, 2010

Qt DevDays 2010

I'm attending Qt DevDays 2010 and really looking forward to it.

I haven't decided yet which tracks I'll attend, there are so many interesting but I definitely go for some Quick-talks. I believe I'll have a great time.

And that's not all, in November I'll also attend a two day Mobile Qt course at Öredev with topics such as Qt Mobility API, Gesture framework, Hybrid JavaScript apps and last but not least Quick. Looks very promising.

Saturday, September 11, 2010

PyQt and Signal overloads

I almost spent half an hour trying to figure out why my code didn't work.

I used a QSignalMapper to connect a couple of clickable widgets to emit just one signal, widgetClicked(int index), instead of having multiple signals, one for each widget. I connected the widgetClicked signal to the mapped signal of the QSignalMapper class and did the required set up for the signal mapper, something like the following snippet:
self._signalMapper = QSignalMapper(self)
self._signalMapper.mapped.connect(self.widgetClicked)

for index, widget in enumerate(buttons):
    widget.clicked.connect(self._signalMapper.map)
    self._signalMapper.setMapping(widget, index)

Everything worked fine until I changed the signature of widgetClicked to pass a string instead of an int, it didn't work anymore. I only got the following print out: TypeError: connect() failed between 'mapped' and 'widgetClicked' and had no clue why because the mapped signal has a couple of overloads:
void mapped(int i)
void mapped(const QString & text)
void mapped(QWidget * widget)
void mapped(QObject * object)
I did also try changing widgetClicked to not receive any arguments and that worked, which was expected because the receiver is not required to match all arguments of a signal. Of course, it also worked if I changed back to int...

What the #@! is going on? Naturally, I had no option of searching for answers since I was sitting on the train back home from work and had no Internet connection.

Then it come to me, Python is not aware of the C++ signature overload. Python doesn't support overloading. Python/PyQt can't set up the right connection between widgetClicked and mapped. But how do you specify which of the overloads you want to connect to? By indexing:
# This connects your slot/signal to the string-overload
signalMapper.mapped[str].connect(...)
The int overload will be used default by PyQt, that's why my code worked when I connected widgetClicked to mapped w/o specifying which overload I wanted.