PyQt4 信号与槽

6 投票
7 回答
30880 浏览
提问于 2025-04-15 17:55

我正在用PyQt4写我的第一个Python应用程序。我有一个主窗口(MainWindow)和一个对话框类(Dialog),这个对话框是主窗口类的一部分:

self.loginDialog = LoginDialog();

我使用了槽(slots)和信号(signals)。这是在主窗口中建立的连接:

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

然后我尝试在对话框类中发出信号(我确定信号是发出的):

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

可惜的是,槽没有被调用。我也尝试过不带参数的方式,以及不同的发信号的方式。代码中没有错误,也没有警告。可能是什么问题呢?

7 个回答

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; 你原来的连接调用是用self.loginDialog,这个是LoginDialog类型的,而信号是由Ui_Dialog类发出的,ui属性是LoginDialog的一部分。经过这个修改,Ui_MainWindow的login方法就会被调用了。

希望这能帮到你,祝好!

27

有一些概念需要澄清

[QT信号与槽] 和 [Python信号与槽]

pyqt提供的所有预定义信号和槽都是用QT的C++代码实现的。每当你想在Python中使用自定义的信号和槽时,那就是Python信号和槽。因此,有四种情况可以将信号发送到槽:

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

下面的代码展示了如何连接这四种不同的场景

    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信号是在你发出时创建的。

对于槽,有三种签名形式。

  • s.connect(w, SIGNAL("信号签名"), 函数名)
  • s.connect(w, SIGNAL("信号签名"), 实例.方法名)
  • s.connect(w, SIGNAL("信号签名"), 实例, SLOT("槽签名"))

第1和第2种适用于Python槽,而第2和第3种适用于QT槽。很明显,除了QT预定义的槽,任何可调用的Python函数或方法都可以作为Python槽。

这些要点在Summerfield关于信号和槽的文章中有提到。

[旧式QT信号与槽] 和 [新式QT信号与槽]

好吧,上面的描述都是基于旧式的pyqt信号与槽。正如@Idan K所建议的,还有一种新的方式来处理这些事情,特别是对于Python信号。有关更多信息,请参考这里

12

在发出信号和连接信号时,你不能用同一个信号。

QtCore.SIGNAL("aa(str)")QtCore.SIGNAL("aa") 是不一样的。信号必须有相同的格式。顺便说一下,如果你自己定义信号,不要定义参数。只需要写 SIGNAL('aa'),因为定义参数是C++的做法,而Python版本的Qt不需要这样。

所以应该像这样:

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

如果你在发出信号时传递了任何参数,你的登录方法也必须接受这些参数。看看这样是否有帮助 :-)

撰写回答