- 指数
- 班级 |
- 模块 |
- PyQt v5.14.0参考指南 »
支持信号和插槽
Qt的主要特征之一是它使用信号和插槽在对象之间进行通信。它们的使用鼓励了可重用组件的开发。
当潜在的事情发生时,发出信号。插槽是可调用的Python。如果将信号连接到插槽,则在发出信号时将调用该插槽。如果没有连接信号,则什么也不会发生。发出信号的代码(或组件)不知道或不在乎是否正在使用该信号。
信号/插槽机制具有以下功能。
-
信号可能连接到许多插槽。
-
一个信号也可以连接到另一个信号。
-
信号参数可以是任何Python类型。
-
插槽可以连接到许多信号。
-
连接可以是直接的(即同步)或排队的(即异步)。
-
可以跨线程进行连接。
-
信号可能断开。
粘结和粘结信号
信号(特别是未绑定的信号)是类属性。当信号被引用为该类实例的属性时,PyQt5会自动将该实例绑定到该信号,以创建绑定信号。这与Python本身用于从类函数创建绑定方法的机制相同。
一个绑定信号具有connect()
,disconnect()
和emit()
实现相关联的功能的方法。它还具有一个signal
属性,它是Qt SIGNAL()
宏将返回的信号的签名。
信号可能过载,即。具有特定名称的信号可能支持多个签名。可以用签名对信号进行索引,以选择所需的信号。签名是一系列类型。类型可以是Python类型对象,也可以是C ++类型名称的字符串。C ++类型的名称会自动进行规范化,例如,QVariant
可以使用它来代替non-normalized 。const QVariant &
如果信号过载,那么它将有一个默认值,如果没有给出索引,它将被使用。
发出信号时,如有可能,所有参数都将转换为C ++类型。如果参数没有相应的C ++类型,则将其包装在特殊的C ++类型中,该参数允许在Qt的元类型系统中传递该参数,同时确保正确维护其引用计数。
使用pyqtSignal定义新信号
PyQt5自动为所有Qt的内置信号定义信号。可以使用pyqtSignal工厂将新信号定义为类属性 。
PyQt5.QtCore.
pyqtSignal
(类型[,名称[,版本= 0 [,参数= [] ] ] ] )
创建一个或多个重载的未绑定信号作为类属性。
参量
-
类型 –定义信号的C ++签名的类型。每个类型可以是Python类型对象,也可以是C ++类型名称的字符串。或者,每个参数可以是类型参数的序列。在这种情况下,每个序列定义了不同信号过载的特征。默认为第一次过载。
-
名称 -信号名称。如果省略,则使用class属性的名称。这只能作为关键字参数给出。
-
修订版 –导出到QML的信号的修订版。这只能作为关键字参数给出。
-
arguments –导出到QML的信号参数名称的顺序。这只能作为关键字参数给出。
返回类型
未绑定的信号
以下示例显示了许多新信号的定义:
from PyQt5.QtCore import QObject, pyqtSignal
class Foo(QObject):
# This defines a signal called 'closed' that takes no arguments.
closed = pyqtSignal()
# This defines a signal called 'rangeChanged' that takes two
# integer arguments.
range_changed = pyqtSignal(int, int, name='rangeChanged')
# This defines a signal called 'valueChanged' that has two overloads,
# one that takes an integer argument and one that takes a QString
# argument. Note that because we use a string to specify the type of
# the QString argument then this code will run under Python v2 and v3.
valueChanged = pyqtSignal([int], ['QString'])
新信号只能在QObject的子类中定义 。它们必须是类定义的一部分,并且在定义类后不能动态添加为类属性。
以这种方式定义的新信号将自动添加到类的 QMetaObject中。这意味着它们将出现在Qt Designer中,并且可以使用QMetaObject API 进行内省 。
当参数的Python类型没有对应的C ++类型时,应谨慎使用重载信号。PyQt5使用相同的内部C ++类来表示此类对象,因此可能会产生带有不同Python签名的重载信号,这些信号用相同的C ++签名实现会产生意外结果。以下是一个示例:
class Foo(QObject):
# This will cause problems because each has the same C++ signature.
valueChanged = pyqtSignal([dict], [list])
连接,断开连接和发射信号
使用connect()
绑定信号的方法将信号连接到插槽。
connect
(时隙[,类型= PyQt5.QtCore.Qt.AutoConnection [,no_receiver_check =假] ] ) →PyQt5.QtCore.QMetaObject.Connection
将信号连接到插槽。如果连接失败,将引发异常。
参量
-
slot –要连接的插槽,可以是Python可调用的信号,也可以是另一个绑定的信号。
-
type –进行连接的类型。
-
no_receiver_check –禁止检查基础C ++接收器实例是否仍然存在,并始终传递信号。
退货
可以传递给的Connection对象disconnect()
。这是断开与lambda函数的连接的唯一方法。
使用disconnect()
绑定信号的方法将信号从插槽断开。
disconnect
([ 插槽] )
从信号上断开一个或多个插槽。如果插槽未连接到信号或信号根本没有连接,则会引发异常。
参量
slot –要从中断开连接的可选插槽,它是由Python可调用的返回的 Connection对象 connect()
或另一个绑定的信号。如果省略,则所有与信号连接的插槽都将断开。
使用emit()
绑定信号的方法发出信号。
emit
(* args )
发出信号。
参量
args –传递给任何连接的插槽的可选参数序列。
以下代码演示了不带参数的信号的定义,连接和发射:
from PyQt5.QtCore import QObject, pyqtSignal
class Foo(QObject):
# Define a new signal called 'trigger' that has no arguments.
trigger = pyqtSignal()
def connect_and_emit_trigger(self):
# Connect the trigger signal to a slot.
self.trigger.connect(self.handle_trigger)
# Emit the signal.
self.trigger.emit()
def handle_trigger(self):
# Show that the slot has been called.
print "trigger signal received"
以下代码演示了过载信号的连接:
from PyQt5.QtWidgets import QComboBox
class Bar(QComboBox):
def connect_activated(self):
# The PyQt5 documentation will define what the default overload is.
# In this case it is the overload with the single integer argument.
self.activated.connect(self.handle_int)
# For non-default overloads we have to specify which we want to
# connect. In this case the one with the single string argument.
# (Note that we could also explicitly specify the default if we
# wanted to.)
self.activated[str].connect(self.handle_string)
def handle_int(self, index):
print "activated signal passed integer", index
def handle_string(self, text):
print "activated signal passed QString", text
使用关键字参数连接信号
创建对象时或通过使用pyqtConfigure()
方法,还可以通过传递一个插槽作为对应于信号名称的关键字参数来连接信号 。例如,以下三个片段是等效的:
act = QAction("Action", self)
act.triggered.connect(self.on_triggered)
act = QAction("Action", self, triggered=self.on_triggered)
act = QAction("Action", self)
act.pyqtConfigure(triggered=self.on_triggered)
所述pyqtSlot()装饰
尽管PyQt5允许在连接信号时将任何可调用的Python用作插槽,但有时有必要将Python方法显式标记为Qt插槽并为其提供C ++签名。PyQt5提供了 pyqtSlot()函数装饰器来执行此操作。
PyQt5.QtCore.
pyqtSlot
(类型[,名称[,结果[,版本= 0 ] ] ] )
装饰Python方法以创建Qt插槽。
参量
-
类型 –定义插槽C ++签名的类型。每个类型可以是Python类型对象,也可以是C ++类型名称的字符串。
-
name – C ++将看到的插槽名称。如果省略,将使用要修饰的Python方法的名称。这只能作为关键字参数给出。
-
修订版 –导出到QML的插槽的修订版。这只能作为关键字参数给出。
-
result – 结果的类型,可以是Python类型的对象或指定C ++类型的字符串。这只能作为关键字参数给出。
将信号连接到经过修饰的Python方法还具有减少使用的内存量的优点,并且速度稍快。
例如:
from PyQt5.QtCore import QObject, pyqtSlot
class Foo(QObject):
@pyqtSlot()
def foo(self):
""" C++: void foo() """
@pyqtSlot(int, str)
def foo(self, arg1, arg2):
""" C++: void foo(int, QString) """
@pyqtSlot(int, name='bar')
def foo(self, arg1):
""" C++: void bar(int) """
@pyqtSlot(int, result=int)
def foo(self, arg1):
""" C++: int foo(int) """
@pyqtSlot(int, QObject)
def foo(self, arg1):
""" C++: int foo(int, QObject *) """
也可以链接装饰器,以便使用不同的签名多次定义Python方法。例如:
from PyQt5.QtCore import QObject, pyqtSlot
class Foo(QObject):
@pyqtSlot(int)
@pyqtSlot('QString')
def valueChanged(self, value):
""" Two slots will be defined in the QMetaObject. """
该PyQt_PyObject
信号参数类型
通过PyQt_PyObject
将签名指定为参数的类型,可以将任何Python对象作为信号参数传递 。例如:
finished = pyqtSignal('PyQt_PyObject')
通常将其用于传递不知道实际Python类型的对象。例如,它也可以用于传递整数,这样就不需要从Python对象正常转换为C ++整数再返回。
被传递对象的引用计数将自动维护。finished.emit()
即使对连接进行排队,也不需要信号的发射器在调用之后保留对对象的引用。
通过名称连接插槽
PyQt5支持pyuic5生成的Python代码connectSlotsByName()
最常用的功能,以自动将信号连接到符合简单命名约定的插槽。但是,在类重载Qt信号的情况下(即,具有相同名称但具有不同参数的Qt信号),PyQt5需要附加信息才能自动连接正确的信号。
例如,QSpinBox类具有以下信号:
void valueChanged(int i);
void valueChanged(const QString &text);
当旋转框的值更改时,将同时发出这两个信号。如果您实现了一个名为的插槽on_spinbox_valueChanged
(假定您为QSpinBox实例指定了名称spinbox
),则它将连接到信号的两种变化形式。因此,当用户更改值时,您的广告位将被调用两次-一次使用整数参数,一次使用字符串参数。
所述pyqtSlot()装饰可被用于指定哪一个信号应连接到所述槽。
例如,如果您只对信号的整数变量感兴趣,那么您的插槽定义将如下所示:
@pyqtSlot(int)
def on_spinbox_valueChanged(self, i):
# i will be an integer.
pass
如果您想使用两种不同的Python方法来处理信号的两种变体,则插槽定义可能如下所示:
@pyqtSlot(int, name='on_spinbox_valueChanged')
def spinbox_int_value(self, i):
# i will be an integer.
pass
@pyqtSlot(str, name='on_spinbox_valueChanged')
def spinbox_qstring_value(self, s):
# s will be a Python string object (or a QString if they are enabled).
pass
- 指数
- 班级 |
- 模块 |
- PyQt v5.14.0参考指南 »