Stepping along

If your application goes wrong in the initialization phase, then you might want to single step every statement until you arrive at the offending statement. Let's debug the same script as in the previous section, but altered slightly to introduce a pesky typo. If you can spot it from eyeballing the code alone, then you've probably skipped ahead to Chapter 7, on signals and slots.


#
# button2.py
#

from qt import *
import sys

class MainWindow(QMainWindow):

    def __init__(self, *args):
        apply(QMainWindow.__init__, (self,) + args)
        self.setCaption("Button")

        self.grid=QGrid(2, self)
        self.grid.setFrameShape(QFrame.StyledPanel)

        self.bn=QPushButton("Hello World", self.grid)
        self.bn.setDefault(1)

        self.connect(self.bn, SIGNAL("clicked()"),
                     self.slotSlot())

        self.setCentralWidget(self.grid)

    def slotSlot(self):
        i = 1/0

def main(args):
    app=QApplication(args)
    win=MainWindow()
    win.show()
    app.connect(app, SIGNAL("lastWindowClosed()"),
                app, SLOT("quit()"))
    app.exec_loop()

if __name__=="__main__":
    main(sys.argv)
    

Running this code won't place the window on screen. Instead, it ends with the following stacktrace:

Traceback (most recent call last):
  File "<stdin>", line 37, in ?
  File "<stdin>", line 30, in main
  File "<stdin>", line 21, in __init__
  File "<stdin>", line 26, in slotSlot
ZeroDivisionError: integer division or modulo by zero
    

If you single step this using BlackAdder you'll notice that directly after the line:

        self.connect(self.bn, SIGNAL("clicked()"),
                     self.slotSlot())
    

Python continues with:

    def slotSlot(self):
    

Accidentally stepping into a function.

Armed with this knowledge, it's easy to see what went wrong: we called the function in the connect line by adding the two brackets, passing the result of the slotSlot() function to the connect(), instead of giving the function object as a parameter to connect. Simply changing the line to:

        self.connect(self.bn, SIGNAL("clicked()"),
                     self.slotSlot)
    

And the bug is fixed! Incidentally, this also shows that you can create new signal/slot connections on the fly, from the output of a function—this is something to be aware of when creating a very dynamic application.