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的信号和槽的主要内容,如果未能解决你的问题,请参考以下文章