On Thursday 23 January 2003 19:46, me wrote:

> Problem: reimplemented QSpinBox don't get focus events and doesn't behave
> correctly on up/down cursor key events (value doesn't change).

Also, manually editing the QSpinBox value doesn't generate a valueChanged
signal, nor does it revert invalid values.

> Therefore, I'm going to translate this app to c++ in order
> to check this behaviour of Qt directly soon.

Done, attached. Looks like the c++ version doesn't generate focus events,
either, but behaves correctly on cursor keys and manual editing. Consequently 
both actions generate a valueChanged signal, unlike the py version.

> Interesting side note: I needed to prepare the event() handlers not to
> call the base class in order to avoid an attribute error during
> 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 try/except 
statement in qEvent, uncomment the print statement and look yourself:

close app
PushButton event: <type 'NoneType'>
Traceback (most recent call last):
  File "sbtest.py", line 121, in event
    print "PushButton event:", qEvent(t)
  File "sbtest.py", line 79, in qEvent
    if t in qEventDict.keys():
AttributeError: 'NoneType' object has no attribute 'keys'
SpinBox event: <type 'NoneType'>
Traceback (most recent call last):
  File "sbtest.py", line 96, in event
    print "SpinBox event:", qEvent(t)
  File "sbtest.py", line 79, in qEvent
    if t in qEventDict.keys():

Something is definitely going wrong here.

TIA,
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 *

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):
    try:
        if t in qEventDict.keys():
            return qEventDict[t]
    except:
        pass
    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)

    def event(self, e):
        t = e.type()
        print "SpinBox event:", qEvent(t)
        # 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)
        # 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 "close app"
        qApp.quit()
        #sys.exit(0)

if __name__ == "__main__":
    a = QApplication(sys.argv)

    QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()"))
    w = sbTest()
    a.setMainWidget(w)
    w.show()
    a.exec_loop()

/*
# 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
*/

#include <qapplication.h>
#include <qpushbutton.h>
#include <qspinbox.h>
#include <qwidget.h>
#include <qlayout.h>
#include <qlabel.h>

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

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

class SpinBox : public QSpinBox {
	Q_OBJECT
public:
	SpinBox(int minValue, int maxValue, int step = 1, QWidget *parent = 0, const char *name = 0)
		: QSpinBox(minValue, maxValue, step, parent, name) {
		lastval = -1;
	}
protected:
	bool event(QEvent *e) {
		int t = e->type();
		qDebug("SpinBox event: %s", qEvent(t));
		return QSpinBox::event(e);
	}

	void focusInEvent(QFocusEvent *e) {
		lastval = value();
		qDebug("SpinBox focusInEvent: %d", lastval);
		QSpinBox::focusInEvent(e);
	}

	void focusOutEvent(QFocusEvent *e) {
		int v = value();
		qDebug("SpinBox focusOutEvent: %d (%d)", v, lastval);
		QSpinBox::focusOutEvent(e);
	}
private:
	int lastval;
};

class PushButton : public QPushButton {
	Q_OBJECT
public:
	PushButton(const QString &text, QWidget *parent, const char *name = 0)
		: QPushButton(text, parent, name){};
protected:
	bool event(QEvent *e) {
		int t = e->type();
		qDebug("PushButton event: %s", qEvent(t));
		return QPushButton::event(e);
	}

	void focusInEvent(QFocusEvent *e) {
		qDebug("PushButton focusInEvent");
		QPushButton::focusInEvent(e);
	}

	void focusOutEvent(QFocusEvent *e) {
		qDebug("PushButton focusOutEvent");
		QPushButton::focusOutEvent(e);
	}
};

class sbTest : public QWidget {
	Q_OBJECT
public:
	sbTest(QWidget *parent = 0, const char *name = 0, WFlags f = 0)
		: QWidget(parent, name, f) {
		setCaption("QSpinBox test");
		value = 42;
		QVBoxLayout *vbox = new QVBoxLayout(this, 4, -1, "vbox");
		PushButton *qb = new PushButton("Quit", this, "qb");
		vbox->addWidget(qb);
		QLabel *l = new QLabel(probmsg, this, "tl");
		vbox->addWidget(l);
		SpinBox *sb = new SpinBox(1, 200, 1, this, "sb");
		sb->setValue(value);
		vbox->addWidget(sb);
		connect(sb, SIGNAL(valueChanged(int)), SLOT(changed(int)));
		connect(qb, SIGNAL(clicked()), SLOT(closeEvent()));
	}
public slots:
	void changed(int v) {
		qDebug("sb changed: %d", v);
		value = v;
	}

	void closeEvent() {
		qDebug("close app");
		qApp->quit();
	}

private:
	int value;
};

#include "sbtest.moc"

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	sbTest w;
	a.setMainWidget(&w);
	w.show();
	return a.exec();
}
######################################################################
# Automatically generated by qmake (1.03a) Fri Jan 24 12:40:01 2003
######################################################################

TEMPLATE = app
CONFIG -= moc
CONFIG += qt warn_on thread

# Input
SOURCES += sbtest.cpp

Reply via email to