6

我正在用 PyQt4 编写我的第一个 Python 应用程序。我有一个 MainWindow 和一个 Dialog 类,它是 MainWindow 类的一部分:

self.loginDialog = LoginDialog();

我使用插槽和信号。这是在 MainWindow 中建立的连接:

QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("aa(str)"), self.login)

我尝试在 Dialog 类中发出信号(我确定它已发出):

self.emit(QtCore.SIGNAL("aa"), "jacek")

不幸的是,插槽没有被调用。我也尝试了不带参数的不同风格的发射信号。代码中没有错误,没有警告。可能是什么问题?

4

7 回答 7

27

有一些概念需要澄清

【QT信号槽】VS【Python信号槽】

pyqt 提供的所有预定义信号和槽均由 QT 的 c++ 代码实现。每当您想在 Python 中自定义信号和槽时,它就是一个 Python 信号和槽。因此,有四种情况可以向插槽发出信号:

  • 从 QT 信号到 QT 槽
  • 从 QT 信号到 Python 插槽
  • 从 Python 信号到 QT 插槽
  • 从 Python 信号到 Python 插槽

下面的代码显示了如何连接这四个不同的 scnarios

    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *

    class Foo(QtCore.QObject):

        def __init__(self, parent=None):
            super(Foo, self).__init__(parent)
            dial = QDial()
            self.spinbox = QSpinbox()

            # --------------------------------------
            # QT signal & QT slot
            # --------------------------------------

            # option 1: more efficient 
            self.connect(self.spinbox, SIGNAL("valueChanged(int)"), 
                dial, SLOT("setValue(int)"))
            # option 2:
            self.connect(self.spinbox, SIGNAL("valueChanged(int)"), 
                dial.setValue)


            # --------------------------------------
            # QT signal & Python slot
            # --------------------------------------

            self.connect(self.spinbox, SIGNAL("valueChanged(int)"), 
                self.myValChanged)


            # --------------------------------------
            # Python signal & Qt slot
            # --------------------------------------

            # connect option 1: more efficient
            self.connect(self, SIGNAL("mysignal"), dial, 
                SLOT("setValue(int)"))

            # connect option 2:
            self.connect(self, SIGNAL("mysignal"), dial.setValue)

            # emit
            param = 100
            self.emit(SIGNAL("mysignal"), param)


            # --------------------------------------
            # Python signal & Python slot
            # --------------------------------------

            # connect
            self.connect(self, SIGNAL("mysignal"), self.myValChanged)

            # emit
            param = 100
            self.emit(SIGNAL("mysignal"), param)


    def myValChanged(self):
        print "New spin val entered {0}".format(self.spinbox.value())

结论是——

Python 信号的信号签名不同于 QT 信号的信号签名,因为它没有括号,并且在您发出它时可以传递任何 Python 数据类型。Python 信号是在您发出它时创建的。

对于 slot,存在三种形式的签名。

  • s.connect(w, SIGNAL("signalSignature"), functionName)
  • s.connect(w,SIGNAL("signalSignature"), instance.methodName)
  • s.connect(w,SIGNAL("signalSignature"), 实例, SLOT("slotSignature"))

1 号和 2 号可用于 Python 插槽,而 2 号和 3 号可用于 QT 插槽。很明显,除了 QT 预定义的槽外,任何 Python 可调用函数/方法都被限定为 Python 槽。

这些观点在Summerfield 关于 Signals and Slots 的文章中提出。

【老款qt信号&槽】VS【新款qt信号&槽】

好吧,上面所有的描述都是基于旧式的pyqt信号槽。正如@Idan K 所建议的那样,有一种替代的新风格来做这些事情,尤其是对于 Python 信号。请参阅此处了解更多信息。

于 2011-10-01T05:00:01.090 回答
12

发射和连接时,您不使用相同的信号。

QtCore.SIGNAL("aa(str)")不一样QtCore.SIGNAL("aa")。信号必须具有相同的签名。顺便说一句,如果您要定义自己的信号,请不要定义参数。只需写 SIGNAL('aa'),因为定义参数是 C++ 的事情,而 Python 版本的 Qt 不需要这个。

所以它应该是这样的:

QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("aa"), self.login)

如果您在 emit 中传递任何参数,您的登录方法必须接受这些参数。检查,如果这有帮助:-)

于 2010-01-12T11:44:46.657 回答
3

@bialix 的建议应该可行,但请尝试另一种连接方式:

class Foo(QtCore.QObject):
    mysignal = QtCore.pyqtSignal(str, name='mysignal')

    def connect_to_signal(self):
        # you can use this syntax instead of the 'old' one
        self.mysignal.connect(self.myslot)

        # but this will also work
        self.connect(self, QtCore.SIGNAL('mysignal(QString)'), self.myslot) 

        self.mysignal.emit("hello")

    def myslot(self, param):
        print "received %s" % param

有关信号/插槽如何在 PyQt 中工作的更详细说明,我建议您阅读它的文档,特别是本节

于 2010-01-12T20:55:53.507 回答
3

我检查了你的代码,看起来问题出在你连接信号的方式上

  1. 你在 Ui_Dialog 类中发出信号

    self.emit(QtCore.SIGNAL("aa()"))

  2. 您通过调用连接到 Ui_MainWindow 的 setupUi 方法中的信号

    QtCore.QObject.connect(self.loginDialog.ui, QtCore.SIGNAL("aa()"), self.login)

注意第一个参数更改为self.loginDialog.ui;您最初的连接调用使用的是 LoginDialog 类型的 self.loginDialog,而信号是由作为 LoginDialog 的 ui 属性的 Ui_Dialog 类发出的。在 Ui_MainWindow 的这个更改登录方法被调用之后

希望这会有所帮助,问候

于 2010-01-18T03:45:01.573 回答
1

正如 gruszczy 所指出的,您必须使用相同的 QtCore.SIGNAL('xxx') 来连接信号并发出它。另外我认为你应该在信号函数的参数列表中使用 Qt 类型。例如:

QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("aa(QString&)"), self.login)

然后发出:

self.emit(QtCore.SIGNAL("aa(QString&)"), "jacek")

有时将信号仅定义一次作为全局变量并在其他地方使用它是有意义的:

MYSIGNAL = QtCore.SIGNAL("aa(QString&)")
...
QtCore.QObject.connect(self.loginDialog, MYSIGNAL, self.login)
...
self.emit(MYSIGNAL, "jacek")
于 2010-01-12T12:23:07.360 回答
0

我没有使用 PyQT4,但请看这里

于 2010-01-12T10:33:38.640 回答
0

看起来您错过了连接呼叫中的“SLOT”部分。

这是一个例子:

QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("NotifyMySignal(int)"), QtCore.SLOT("onNotifyMySignal(int)"));

然后

self.emit(QtCore.SIGNAL('NotifyMySignal(1)'));

希望这可以帮助 !

于 2010-01-12T10:39:50.160 回答