PySide emit signal causes python to crash

2019-05-31 17:23发布

问题:

I am working through the book "Rapid Gui Programming with Python and Qt" and am having a problem on the signals/slots project. I have downloaded the authors code to compare against my own, and it all looks the same, however, when I emit a signal from a derived spin box class, python just crashes. Here is the entire code that I have:

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class ZeroSpinBox(QSpinBox):
    zeros = 0

    def __init__(self, parent=None):
        super(ZeroSpinBox, self).__init__(parent)
        self.connect(self, SIGNAL("valueChanged(int)"), self.checkzero)

    def checkzero(self):
        if self.value() == 0:
            self.zeros += 1
            self.emit(SIGNAL("atzero"), self.zeros)

class Form(QDialog):
    def __init__(self, parent= None):
        super(Form, self).__init__(parent)

        dial = QDial()
        dial.setNotchesVisible(True)
        spinbox = ZeroSpinBox()
        spinbox.setRange(0,200)
        dial.setRange(0,200)

        layout = QHBoxLayout()
        layout.addWidget(dial)
        layout.addWidget(spinbox)
        self.setLayout(layout)

        self.connect(dial, SIGNAL("valueChanged(int)"), spinbox, SLOT("setValue(int)"))
        self.connect(spinbox, SIGNAL("valueChanged(int)"), dial, SLOT("setValue(int)"))
        self.connect(spinbox, SIGNAL("atzero"), self.announce)

        self.setWindowTitle("Signals and Slots Part 2")

    def announce(self, zeros):
        print "ZeroSpinBox has been at zero %d times" % zeros


if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    app.exec_()

My problem occurs when the spinbox goes down to zero, the checkzero(self) method (of the ZeroSpinBox class) gets called, the self.zeros += 1 line is ok, then on the emit line windows reports that Python.exe has crashed. The error I get is "python.exe has stopped working" and the console reports "Process finished with exit code -1073741819"

Any idea why this is happening? This is Python 2.7.2 and PyQT4 w/PySide.

回答1:

Substitute SIGNAL("atzero") with SIGNAL("atzero(int)") both in checkzero and in Form.__init__, because the way you're declaring it, it carries no argument.

Edit: your code in the "new-style",

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class ZeroSpinBox(QSpinBox):
    zeros = 0

    def __init__(self, parent=None):
        super(ZeroSpinBox, self).__init__(parent)
        self.valueChanged.connect(self.checkzero)

    atzero = Signal(int)

    def checkzero(self):
        if self.value() == 0:
            self.zeros += 1
            self.atzero.emit(self.zeros)

class Form(QDialog):
    def __init__(self, parent= None):
        super(Form, self).__init__(parent)

        dial = QDial()
        dial.setNotchesVisible(True)
        spinbox = ZeroSpinBox()
        spinbox.setRange(0,200)
        dial.setRange(0,200)

        layout = QHBoxLayout()
        layout.addWidget(dial)
        layout.addWidget(spinbox)
        self.setLayout(layout)

        dial.valueChanged.connect(spinbox.setValue)
        spinbox.valueChanged.connect(dial.setValue)
        spinbox.atzero.connect(self.announce)

        self.setWindowTitle("Signals and Slots Part 2")

    @Slot(int)
    def announce(self, zeros):
        print "ZeroSpinBox has been at zero %d times" % zeros


if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    app.exec_()


回答2:

This due to a difference between PySide and PyQt4, which is documented here (actually, strictly speaking, this is a bug in PySide - using a unsupported form of signal syntax should produce an error, not crash the application).

The book you are using was written specifically for PyQt4, and so you probably need to be aware of the differences between PySide and PyQt4 when using it. See here, for example.

Note that the PyQt4 version of your script works fine, with or without the parenthesized portion of the signal - all that matters is that they are the same. However, this is only true for user-defined signals - for predefined Qt signals and slots, you must always include the parenthesized portion of the signature.

Another thing you should be aware of, is that the signal/slot syntax you are using has been superceeded by a much more pythonic new-style syntax. So, at some point, it would be worthwhile reading through the guidance found here, if your book doesn't cover it.