前言
我认为,信号就是触发,槽就是触发的事件。
一、信号与槽
- 信号(signal)
其实就是事件(按钮点击 、内容发生改变 、窗口的关闭事件) 或者是 状态 (check选中了, togglebutton 切换。)
当程序触发了某种状态或者发生了某种事件(比如:按钮被点击了, 内容改变等等),那么即可发射出来一个信号。 - 槽( slot)
若想捕获这个信号,然后执行相应的逻辑代码,那么就需要使用到 槽 , 槽实际上是一个函数, 当信号发射出来后,会执行与之绑定的槽函数。 - 将信号与槽链接
为了能够实现,当点击某个按钮时执行某个逻辑,需要把具体的信号和具体的槽函数绑定到一起.
对象.信号.connect(槽函数)
二、Demo
接收信号
代码
'''
#Author :susocool
#Creattime:2024/1/31
#FileName:11-接收信号
#Description:点击按钮的时候触发
'''
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# 更改当前Widge的宽高
self.resize(500, 300)
# 创建一个按钮
btn = QPushButton("点我点我", self)
# 设置窗口位置、宽高
btn.setGeometry(200, 200, 100, 30)
# 将按钮被点击时触发的信号与我们定义的函数(方法)进行绑定
# 注意:这里没有(),即写函数的名字,而不是名字()
btn.clicked.connect(self.click_my_btn)
def click_my_btn(self, arg):
# 槽函数,点击按钮则调用该函数
# 这里的参数正好是信号发出,传递的参数
print("点击按钮啦~", arg)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
运行结果
自定义信号【重点】
自定义信号需要使用到 pyqtSignal来声明信号 ,并且需要在类中的函数之外声明
代码
'''
#Author :susocool
#Creattime:2024/1/31
#FileName:12-自定义信号
#Description: 模拟检测过程
'''
import sys
import time
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyWindow(QWidget):
# 声明一个信号 只能放在函数的外面
my_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.init_ui()
self.msg_history = list() # 用来存放消息
def init_ui(self):
self.resize(500, 200)
# 创建一个整体布局器
container = QVBoxLayout()
# 用来显示检测到漏洞的信息
self.msg = QLabel("")
self.msg.resize(440, 15)
# print(self.msg.frameSize())
self.msg.setWordWrap(True) # 自动换行
self.msg.setAlignment(Qt.AlignTop) # 靠上
self.msg.setStyleSheet("background-color: yellow; color: black;")
# 创建一个滚动对象
scroll = QScrollArea()
scroll.setWidget(self.msg)
# 创建垂直布局器,用来添加自动滚动条
v_layout = QVBoxLayout()
v_layout.addWidget(scroll)
# 创建水平布局器
h_layout = QHBoxLayout()
btn = QPushButton("开始检测", self)
# 绑定按钮的点击,点击按钮则开始检测
btn.clicked.connect(self.check)
h_layout.addStretch(1) # 伸缩器
h_layout.addWidget(btn)
h_layout.addStretch(1)
# 操作将要显示的控件以及子布局器添加到container
container.addLayout(v_layout)
container.addLayout(h_layout)
# 设置布局器
self.setLayout(container)
# 绑定信号和槽
self.my_signal.connect(self.my_slot)
def my_slot(self, msg):
# 更新内容 在自定义的显示窗口内
print(">>",msg)
self.msg_history.append(msg)
# 消息之间用HTML换行标签<br>分隔
self.msg.setText("<br>".join(self.msg_history))
self.msg.resize(440, self.msg.frameSize().height() + 15)
self.msg.repaint() # 更新内容,如果不更新可能没有显示新内容
def check(self):
for i, ip in enumerate(["192.168.1.%d" % x for x in range(1, 255)]):
msg = "模拟,正在检查 %s 上的漏洞...." % ip
# print(msg)
if i % 5 == 3:
# 表示发射信号 对象.信号.发射(参数)
self.my_signal.emit(msg + "【发现漏洞】") # 相当于调用my_slot函数
time.sleep(0.01)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
首先,声明一个信号,注意只能放在函数的外面
其次,绑定信号与槽
最好,表示发射信号 对象.信号.发射
最后,信号被触发。
for i, ip in enumerate(…):这部分是一个for循环,它遍历上面生成的IP地址列表。在每次循环中,变量i是IP地址的索引(从0开始),ip是对应的IP地址。
enumerate()函数:这个函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标.
运行结果
总结
- 自定义信号里面的滚动功能可以使用在别的地方。
- 学习了简单的信号与槽的触发、和自定义触发信号。