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);