On Saturday 04 October 2003 11:17, Phil Thompson wrote:
> On Saturday 04 October 2003 12:56 am, Michael Andrews wrote:
> > I don't know if anyone else saw this article (I found the link
> > from the Python Daily URL):
> >
> > http://www.dalkescientific.com/writings/diary/archive/2003/09/27/
> >PythonCard .html
> >
> > Most of the article talks about wxWindows and concludes that "...
> > wxPython even now just aren't there yet."

Let me add, that I switched to PyQt after looking under the covers
of both projects. There, it's pretty apparent, which one is 
technologically vast superior ;-)

> > However, at the end of the article he mentions PyQt:
> >
> > "PyQt has its own set of problems, like the core dumps which
> > arise from deleting objects in the wrong order. (There was one
> > talk using Qt. The demos kept getting a core dump on exit because
> > the code didn't ensure qtApp was deleted last.)"
> >
> > I've seen problems with my apps compiled with Qt 3.2.x (I don't
> > even know if it is the same problem); but is this a wide spread
> > problem?  In other words, are other PyQt application developers
> > seeing these problems?
>
> The problem of ensuring qApp isn't deleted too soon was fixed on
> 14th April 2002. The first release after that was v3.2.

Well, maybe they're talking about the problem with qApp.quit() and 
overloaded event handlers under certain conditions (i.e. single 
module apps). Attached is a script to exploit the problem (after 
editing). Run it as python -v qt_dtor.py to explore the interaction 
with python.

Conclusion: beware from using qApp.quit(), or even sys.exit(0) without 
thinking twice. There are almost always better ways to close a PyQt 
application. Use them.

Pete
#!/usr/bin/python -v
# call python directly here, in order to provide -v flag
#!/usr/bin/env python
#
# qt_dtor.py v0.1: investigate PyQt dtor races
#
# Copyright 2002-2003 Hans-Peter Jansen <[EMAIL PROTECTED]>
#
# This program is placed under the GNU General Public License V.2

import sys
from qt import *

class _qtEvent:
    _qtEventDict = {
        0: "None",
        1: "Timer",
        2: "MouseButtonPress",
        3: "MouseButtonRelease",
        4: "MouseButtonDblClick",
        5: "MouseMove",
        6: "KeyPress",
        7: "KeyRelease",
        8: "FocusIn",
        9: "FocusOut",
        10: "Enter",
        11: "Leave",
        12: "Paint",
        13: "Move",
        14: "Resize",
        15: "Create",
        16: "Destroy",
        17: "Show",
        18: "Hide",
        19: "Close",
        20: "Quit",
        21: "Reparent",
        22: "ShowMinimized",
        23: "ShowNormal",
        24: "WindowActivate",
        25: "WindowDeactivate",
        26: "ShowToParent",
        27: "HideToParent",
        28: "ShowMaximized",
        29: "ShowFullScreen",
        30: "Accel",
        31: "Wheel",
        32: "AccelAvailable",
        33: "CaptionChange",
        34: "IconChange",
        35: "ParentFontChange",
        36: "ApplicationFontChange",
        37: "ParentPaletteChange",
        38: "ApplicationPaletteChange",
        39: "PaletteChange",
        40: "Clipboard",
        42: "Speech",
        50: "SockAct",
        51: "AccelOverride",
        52: "DeferredDelete",
        60: "DragEnter",
        61: "DragMove",
        62: "DragLeave",
        63: "Drop",
        64: "DragResponse",
        70: "ChildInserted",
        71: "ChildRemoved",
        72: "LayoutHint",
        73: "ShowWindowRequest",
        80: "ActivateControl",
        81: "DeactivateControl",
        82: "ContextMenu",
        83: "IMStart",
        84: "IMCompose",
        85: "IMEnd",
        86: "Accessibility",
        87: "Tablet"
    }

    def types(self):
        return self._qtEventDict.keys()

    def which(self, t):
        try:
            if t in self._qtEventDict.keys():
                return self._qtEventDict[t]
        except:
            return "Unknown";

qte = _qtEvent()

class PushButton(QPushButton):
    def __init__(self, text = None, parent = None, name = None):
        QPushButton.__init__(self, text, parent, name)

    def event(self, e):
        t = e.type()
        print "PushButton event:", t, qte.which(t)
        return QPushButton.event(self, e)

class qtTest1(QWidget):
    def __init__(self, parent = None, name = None, fl = 0):
        QWidget.__init__(self, parent, name, fl)
        self.setCaption("PyQt dtor testing v1")
        vbox = QVBoxLayout(self, 4, -1, "vbox")
        pb = PushButton("Quit", self, "pb")
        vbox.addWidget(pb)
        self.connect(pb, SIGNAL("clicked()"), self.close)

    def close(self, alsoDelete = 1):
        print "close", alsoDelete
        # calling qApp.quit() here seems to delay Qts event
        # distribution until after python cleaned up __main__
        # which triggers AttributeErrors from accessing qte
        # methods in the overloaded PushButton event handler
        #qApp.quit()
        # calling sys.exit(0) here works, but prevents 
        # a.exec_loop from returning and Qt from terminating
        # properly
        #sys.exit(0)
        # The savest method to savely terminate this module
        # without former mentioned problems
        return QWidget.close(self, alsoDelete)

class qtTest2(QWidget):
    def __init__(self, parent = None, name = None, fl = 0):
        QWidget.__init__(self, parent, name, fl)
        self.setCaption("PyQt dtor testing v2")
        vbox = QVBoxLayout(self, 4, -1, "vbox")
        pb = PushButton("Quit", self, "pb")
        vbox.addWidget(pb)
        self.connect(pb, SIGNAL("clicked()"), self.closeEvent)

    def closeEvent(self, e = None):
        print "closeEvent", e
        # calling qApp.quit() here seems to delay Qts event
        # distribution until after python cleaned up __main__
        # which triggers AttributeErrors from accessing qte
        # methods in the overloaded PushButton event handler
        #qApp.quit()
        # calling sys.exit(0) here works, but prevents 
        # a.exec_loop from returning and Qt from terminating
        # properly
        #sys.exit(0)
        # The savest method to savely terminate this module
        # without former mentioned problems in an overloaded
        # closeEvent (which is an Qt signal handler also)
        if e:
            e.accept()
        else:
            self.close()

if __name__ == "__main__":
    a = QApplication(sys.argv)
    if len(sys.argv) > 1 and sys.argv[1] == "2":
        w = qtTest2()
    else:
        w = qtTest1()
    w.resize(QSize(280, 20))
    a.setMainWidget(w)
    w.show()
    a.connect(qApp, SIGNAL("lastWindowClosed()"), SLOT("quit()"))
    ret = a.exec_loop()
    print "exec_loop:", ret

Reply via email to