PyQt5 信号(Signal)和槽(Slot)(同步和异步)

信号(Signal)和槽(Slot)是PyQt编程对象之间进行通信的机制。每个继承自QWidget的控件都支持信号与槽机制。信号发射时(发送请求),连接的槽函数就会自动执行(针对请求进行处理)
内置信号和槽
所谓内置信号与槽的使用。是指在发射信号时,使用窗口控件的函数,而不是自定义的函数。信号与槽的连接方法是通过QObject.signal.connect将一个QObject的信号连接到另一个QObject的槽函数。
槽函数close为窗口控件函数
信号与槽:self.pushButton.clicked.connect(self.close)
内置信号和自定义槽使用实例
槽函数showMsg为自定义函数。
信号与槽:self.pushButton.clicked.connect(self.showMsg)
自定义信号和槽使用实例
槽函数可以为自定义函数showMsg,也可以为窗口控件函数close。
这里需要注意一下声明信号的位置和父类,否则可能会报错
信号与槽:self.my_signal.connect(self.print_num)


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.my_signal.connect(self.print_num)
    def print_num(self):
        for i in range(10000):
            print(i)

不知对错
下面是我的一些理解不知对错,信号和槽提供了一种跨线程的UI访问方式,执行顺序仍然是同步执行。

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.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_asterisk。

那我们把函数mousePressEvent改一下

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

运行代码,鼠标按下,仍然会先执行print_num,再执行print_num_asterisk。

下面我们把其中一个打印函数放在多线程里

    def mousePressEvent(self, QMouseEvent):
        self.my_threadHandle = threading.Thread(target=self.print_num)
        self.my_threadHandle.setDaemon(True)
        self.my_threadHandle.start()
        self.print_num_asterisk()

运行代码,鼠标按下,两个函数的打印会交替执行。

我们再做如下更改,按照预想,应该是两个函数的打印会交替执行,但实际上先执行print_num_asterisk,再执行print_num。我认为的原因,主线程也就是UI线程,是相应信号的线程,当主线程正在执行函数mousePressEvent,函数执行之后,才去响应子线程的信号。
子线程函数内不要采用信号和槽,直接调用函数就行,和主线程通讯再采用信号和槽的方式

    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_signal.emit()

暂时的结论是信号(Signal)和槽(Slot)主要是用于窗体间通讯,想要执行异步操作还需要多线程。

    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_threadHandle0 = threading.Thread(target=self.get_signal0)
        self.my_threadHandle0.setDaemon(True)
        self.my_threadHandle0.start()
        self.print_num_asterisk()
    def get_signal0(self):
        self.my_signal.emit()

两个函数的打印会交替执行。

    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_threadHandle0 = threading.Thread(target=self.get_signal0)
        self.my_threadHandle0.setDaemon(True)
        self.my_threadHandle0.start()
        #self.print_num_asterisk()
    def get_signal0(self):
        self.my_signal.emit()

先执行print_num_asterisk,再执行print_num

跨线程访问UI,窗体间通讯,宜采用信号和槽

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值