Qt 控件的信号(如何自定义信号)

Posted on Wed, 25 Dec 2024 16:06:42 +0800 by LiangMingJian


概述

信号和槽是 QT 的核心机制,其本质是一种高级接口,应用于对象之间的通信,它是 QT 区别于其它工具包的重要地方。

在其它的 GUI 工具包中,任何部件 Widget 都有一个回调函数用于响应它们能触发的每个动作,比如,点击,输入,缩放等。但在 QT 中,信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序时更为简洁明了。

所有从 QObject 或其子类派生的类都能够包含信号和槽。

  • 当对象改变其状态时,信号就由该对象发射出去,它不需要知道另一端是谁在接收这个信号。
  • 槽函数用于接收信号,本质是普通的对象函数。同样的,一个槽并不知道是否有任何信号与自己相连接。

通用信号(所有控件都具备)

在 PySide6 中,对于任意 Qt 控件,其往往拥有一些固有的信号,比如下面的列表:

信号名含义(发生了什么)附带数据典型场景
clicked控件被鼠标点击无(或 bool)按钮点击、复选框选中
pressed鼠标按下控件(未松开)无实现“按下时高亮”等交互
released鼠标松开控件(按下后)无配合 pressed 做按压动效
hovered鼠标悬停在控件上无悬浮提示、按钮变色
focusIn控件获得焦点(如输入框选中)无输入框获得焦点时高亮边框
focusOut控件失去焦点无输入框失去焦点时校验内容
destroyed控件被销毁控件对象资源释放、清理关联数据
accepted对话框点击“确认”按钮无对话框提交数据
rejected对话框点击“取消”按钮无对话框放弃操作

这些组件可以通过 connect 方法来连接槽函数,用来接收数据并处理。

# 将 MyButton 的点击信号连接到一个名为 myButtonEvent 的槽函数
self.ui.MyButton.clicked.connect(self.myButtonEvent)

一般来说,上述方法便已足够使用,但在某种条件下,用户可能希望在执行槽函数时,往槽函数里面传递一些参数,此时上述的连接方法便不足够使用。

因为固有的信号往往并不会携带我们想要的参数,所以我们只能通过 lambda 方法,通过构建匿名函数的方式来往槽函数里面传递值。

实际上,这里的正确做法一般是建议自定义信号来传递参数。

self.ui.ExportButton.clicked.connect(lambda: self.exportButtonEvent(1))

自定义信号

在 PySide6 中,通过类 Signal(),开发者可以自定义信号使用。自定义的信号不同于固有信号,可以自行决定信号是否要返回值,需要返回什么值。

s1 = Signal()
s2 = Signal(int)
s3 = Signal(str, str)

信号在创建后,在执行完想要的操作后,便可以通过 emit() 方法进行发送。

s1.emit()
s2.emit(1)
s3.emit("topic", "message")

对于自定义的信号,其连接方式与固有信号一样,都是通过 connect() 来完成的。

s1.connect(on_s1_even)
s2.connect(on_s2_even)
s3.connect(on_s3_even)

对于槽函数,如果自定义信号中有参数传递,那么在槽函数中,便可以按顺序定义形参,来对信号传入的参数进行接收。

def on_s2_even(flag):
	print(flag)

def on_s3_even(topic, message):
	print(f"收到消息 [{topic}]: {message}")

特殊的一些信号

输入类控件(QLineEdit / QTextEdit)特有的信号。

信号名含义(发生了什么)附带数据典型场景
textChanged文本内容发生变化(实时)最新文本实时搜索、输入框内容校验
editingFinished用户结束编辑(如失去焦点)无输入完成后的处理逻辑

列表/表格类控件(QComboBox / QListView)特有的信号。

信号名含义(发生了什么)附带数据典型场景
currentIndexChanged当前选中项发生变化当前索引下拉框选中项变化、选项切换

滑块类控件(QSlider / QSpinBox)特有的信号。

信号名含义(发生了什么)附带数据典型场景
valueChanged数值发生变化当前值滑块、数值输入框的实时反馈