PyQt5的信号和槽

Posted CCH2023

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyQt5的信号和槽相关的知识,希望对你有一定的参考价值。

信号signal和槽slot是Qt的核心机制,也是进行PyQt编程时对象之间通信的基础。每一个QObject对象(包括各种窗口和控件)都支持信号和槽机制。通过信号和槽的关联,就可以实现对象之间的通信。当信号发射的时候,连接的槽函数方法就自动执行。在PyQt5中,信号和槽是通过对象的signal.connect()方法进行连接的。

信号和槽的主要特点:

1)一个信号可以连接多个槽;

2)一个槽可以监听多个信号;

3)信号和信号之间可以互连;

4)信号和槽的连接可以跨线程;

5)信号与槽的连接方式即可以是同步,也可以是异步的;

6)信号的参数可以是任何Python类型的。

编辑signal和slot,两者建立关系:

self.pushButton.clicked.connect(MainWindow.close)    # 内置的槽函数

自定义槽:

自定义槽的概念就是定义一个函数,该函数实现相应的功能。

例如:showMessage() 函数

将自定义槽连接到信号:

self.pushButton.clicked.connect(self.showMessage)

例:

场景一:

import sys

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5 import QtCore


class Demo(QWidget):
    my_signal = pyqtSignal()

    def __init__(self):
        super(Demo, self).__init__()
        self.resize(400, 300)
        self.label = QLabel("Hello World", self)
        self.label.setGeometry((QtCore.QRect(50, 30, 89, 25)))
        self.my_signal.connect(self.print_num)

    def mousePressEvent(self, QMouseEvent):
        self.print_num()
        self.print_num_asterisk()

    def print_num(self):
        for i in range(10000):
            print(i)

    def print_num_asterisk(self):
        for i in range(10000):
            print(str(i) + "**")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

鼠标按下,直接调用的是print_num()和print_num_aterisk()两个函数。

场景二:然后再对mousePressEvent函数中的print_num函数改成self.my_signal.emit():

    def mousePressEvent(self, QMouseEvent):
        self.my_signal.emit()
        self.print_num_asterisk()

执行任然是相同的结果。

场景三:

    def mousePressEvent(self, QMouseEvent):
        # self.my_signal.emit()

        self.my_threadHandle = threading.Thread(target=self.print_num)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()

        self.print_num_asterisk()

将其中的一个打印函数放在多线程里。运行代码,鼠标按下,两个函数的打印会交替执行。

 

场景四:

我们将采用signal和slot的方式,在多线程里执行。

    def mousePressEvent(self, QMouseEvent):
        # self.my_signal.emit()

        self.my_threadHandle = threading.Thread(target=self.get_signal)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()

        self.print_num_asterisk()

    def get_signal(self):
        self.my_signal.emit()

按照预想,应该是两个函数的打印交替执行,但实际上先执行的print_num_asterisk函数,然后再执行的print_num函数。主线程正在执行函数mousePressEvent,函数执行完之后,才去响应子线程的信号。

得出的结论:子线程函数里不要使用信号和槽,直接调用函数就行,和主线程通讯再采用信号和槽的方式。

import sys

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5 import QtCore
import threading


class Demo(QWidget):
    my_signal = pyqtSignal()

    def __init__(self):
        super(Demo, self).__init__()
        self.resize(400, 300)
        self.label = QLabel("Hello World", self)
        self.label.setGeometry((QtCore.QRect(50, 30, 89, 25)))
        self.my_signal.connect(self.print_num)

    def mousePressEvent(self, QMouseEvent):

        self.my_threadHandle = threading.Thread(target=self.get_signal)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()

        self.print_num_asterisk()

    def get_signal(self):

        self.my_threadHandle = threading.Thread(target=self.get_signal0)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()

        # self.print_num_asterisk()

    def get_signal0(self):
        self.my_signal.emit()


    def print_num(self):
        for i in range(10000):
            print(i)

    def print_num_asterisk(self):
        for i in range(10000):
            print(str(i) + "**")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

先执行print_num_asterisk,再执行print_num。

import sys

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5 import QtCore
import threading


class Demo(QWidget):
    my_signal = pyqtSignal()

    def __init__(self):
        super(Demo, self).__init__()
        self.resize(400, 300)
        self.label = QLabel("Hello World", self)
        self.label.setGeometry((QtCore.QRect(50, 30, 89, 25)))
        self.my_signal.connect(self.print_num)

    def mousePressEvent(self, QMouseEvent):

        self.my_threadHandle = threading.Thread(target=self.get_signal)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()

        # self.print_num_asterisk()

    def get_signal(self):

        self.my_threadHandle = threading.Thread(target=self.get_signal0)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()

        self.print_num_asterisk()

    def get_signal0(self):
        self.my_signal.emit()

    def print_num(self):
        for i in range(10000):
            print(i)

    def print_num_asterisk(self):
        for i in range(10000):
            print(str(i) + "**")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

这段代码是交替执行。

窗体间通信使用信号和槽。

跨线程访问UI,宜采用信号和槽。

PyQt 中的信号和槽

【中文标题】PyQt 中的信号和槽【英文标题】:Signals and slots in PyQt 【发布时间】:2010-04-02 21:47:21 【问题描述】:

过去我在 C++ 中有过一些 Qt 的经验。我现在开始使用 PyQt,发现它有点令人困惑。除了 Riverbank 的少量文件外,似乎没有任何确定的文件来源。我想我想知道的第一件事是 PyQt 有一个初始的驼峰,它确实变得更容易了。 [编辑: 我遇到的主要问题是由于拼写错误 - init 而不是 __init__。我现在不觉得太难了:P]

PyQt 的PyQt docs talk about new style signals and slots 以及旧样式。他们认为新样式更好,但我想知道这是否是大多数 PyQt 用户所做的。

【问题讨论】:

【参考方案1】:

是的,就是这样。新语法更清晰,为什么不呢? 请注意,当您尝试按名称连接插槽时,您必须显式调用 connectSlotsByName,因为在执行和连接它们之前没有预处理器可以工作。

PS:此外,用于信号/插槽连接的 C++ 语法很丑陋,而且旧的 PyQt 语法毫无理由地非常相似,所以我很高兴看到 PyQt 中的这种变化。

PS2:最近这里有一个关于这个的问题,看看吧。

【讨论】:

哎呀 :) 这不是俄语,只是一个错字。它“出局了”。在俄罗斯charmap中。【参考方案2】:

参考见: PyQt Class Reference - 它非常全面,并通过示例进行了详细说明。大多数示例都是用 C++ 编写的,虽然我是 Python 新手,但我并不觉得翻译成 Python 很困难。

如果您是一位经验丰富的开发人员并开始使用 Python 和 PyQt,这是一本非常好的书 - 关于我所知道的唯一一本关于该主题的完整书籍:Rapid GUI Programming with Python and Qt.

信号和槽:我总是在 PyQt 中使用新的信号和槽语法,它简单而优雅——更“pythonic”。 PyQt 很棒,但在许多方面它仍然非常像 C++ - 他们对“pythonate”它做的越多越好。

【讨论】:

以上是关于PyQt5的信号和槽的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5的信号和槽

C++ GUI Qt的建立连接,信号和槽

PyQt5——信号和槽初探

python pyqt5 自定义信号和槽

PyQt5中的信号与槽,js 与 Qt 对象之间互相调用

Qt信号槽如何附带自定义参数