On Saturday 25 January 2003 17:02, Phil Thompson wrote:
>
> Thanks for putting the effort into this - it was very helpful. The bug is
> that qspinbox.sip should say...
>
> bool eventFilter(QObject *,QEvent *);
>
> ...instead of...
>
> void eventFilter(QObject *,QEvent *);
>
> It will be fixed in tonight's snapshot.

Thanks. Well done. I feel better now. But please have another look into 
these two:

> > > qApp.quit(). Phil, it appears, that the QSpinBox base class disappears
> > > while subclassed SpinBox event() handler is active. This doesn't look
> > > right to me.
> >
> > While making both versions functional identical, I've rewritten the event
> > decoder qEvent(), but couldn't believe my eyes: during qApp.quit() the
> > value of the global defined qEventDict{} in the .py script is replaced
> > with a None value somewhere under the covers! Please remove the
> >
> > Something is definitely going wrong here.
>
> I think this is just Python and Qt racing each other to tidy up. As the
> behaviour of either isn't formally documented I think it's more a feature
> rather than a bug.

Well, I cannot see the feature aspect here. OTOH, this obfuscates the code, 
and it defies the principle of least surprise.

I digged into this a bit further and found a way to get around these problems
somehow:

1) The qEventDict does survive, if it is declared inside the qEvent function.

2) just keep a reference of QSpinBox, and call it, instead of the baseclass:

class SpinBox(QSpinBox):
    def __init__(self, minValue, maxValue, step = 1, parent = None, name = None):
        self.lastval = None
        QSpinBox.__init__(self, minValue, maxValue, step, parent, name)
        self.QSpinBox = QSpinBox

    def event(self, e):
        t = e.type()
        print "SpinBox event:", qEvent(t)
        return self.QSpinBox.event(self, e)

Funny side note: it was enough to fix one of both sub classes this way to 
prevent attribute errors here. This is pretty undeterministic, and that's 
exactly the reason, why I don't like this behaviour...

Phil, one would expect, that as long as a class exists, its baseclass should 
exist, either. The same goes for globals in module scope.

Note, that this happens, before dtor of QApplication aka PyQtDisownTopLevelWidgets(),
and even siplib:finalise() is called:

closeEvent
exec_loop: 0
PushButton event: WindowDeactivate
SpinBox event: WindowDeactivate
PushButton event: FocusOut
PushButton focusOutEvent
PushButton event: Hide
SpinBox event: Hide
PyQtDisownTopLevelWidgets
PyQtDisownTopLevelWidgets
finalise begin
finalise done

Is it possible to keep a reference on these internally and throw them away in
finalise()? For reference, current sbtest.py attached.

> Phil

Pete
#!/usr/bin/env python

# sbtest v0.1: investigate QSpinBox strangeness
#
# Copyright 2002 Hans-Peter Jansen <[EMAIL PROTECTED]>
#
# This program is placed under the GNU General Public License V.2

import sys
from qt import *

# Just swap the _ of both qEventDicts to suppress the attribute errors
qEventDict = {
    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 qEvent(t):
    _qEventDict = {
        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"
    }
    if t in qEventDict.keys():
        return qEventDict[t]
    return "Unknown";

probmsg = """\
Problem: reimplemented QSpinBox below
don't get focus events and doesn't behave
correctly on up/down cursor keys!\
"""

class SpinBox(QSpinBox):
    def __init__(self, minValue, maxValue, step = 1, parent = None, name = None):
        self.lastval = None
        QSpinBox.__init__(self, minValue, maxValue, step, parent, name)
        self.QSpinBox = QSpinBox

    def event(self, e):
        t = e.type()
        print "SpinBox event:", qEvent(t)
        return self.QSpinBox.event(self, e)
        # this seems to be necessary because of races with qApp.quit()
        #if QSpinBox:
        #    return QSpinBox.event(self, e)
        #else:
        #    return 0

    def focusInEvent(self, e):
        self.lastval = self.value()
        print "SpinBox focusInEvent", self.lastval
        QSpinBox.focusInEvent(self, e)

    def focusOutEvent(self, e):
        v = self.value()
        print "SpinBox focusOutEvent", v, self.lastval
        if self.lastval != v:
            emit(SIGNAL("valueChanged(int)"), (v))
        QSpinBox.focusOutEvent(self, e)

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:", qEvent(t)
        return QPushButton.event(self, e)
        # this seems to be necessary because of races with qApp.quit()
        #if QPushButton:
        #    return QPushButton.event(self, e)
        #else:
        #    return 0

    def focusInEvent(self, e):
        print "PushButton focusInEvent"
        return QPushButton.focusInEvent(self, e)

    def focusOutEvent(self, e):
        print "PushButton focusOutEvent"
        return QPushButton.focusOutEvent(self, e)

class sbTest(QWidget):
    def __init__(self, parent = None, name = None, fl = 0):
        QWidget.__init__(self, parent, name, fl)
        self.setCaption("QSpinBox test")
        self.value = 42
        vbox = QVBoxLayout(self, 4, -1, "vbox")
        qb = PushButton("Quit", self, "qb")
        vbox.addWidget(qb)
        l = QLabel(probmsg, self, "tl")
        vbox.addWidget(l)
        sb = SpinBox(1, 200, 1, self, "sb")
        sb.setValue(self.value)
        vbox.addWidget(sb)
        self.connect(sb, SIGNAL("valueChanged(int)"), self.changed)
        self.connect(qb, SIGNAL("clicked()"), self.closeEvent)

    def changed(self, v):
        print "sb changed:", v
        self.value = v

    def closeEvent(self, e = None):
        print "closeEvent"
        qApp.quit()

if __name__ == "__main__":
    a = QApplication(sys.argv)
    w = sbTest()
    a.setMainWidget(w)
    w.show()
    ret = a.exec_loop()
    print "exec_loop:", ret
    sys.exit(ret);

Reply via email to