信号与槽
信号与槽是Qt的核心内容。
信号 [Signal]
信号就是事件(按钮点击、内容发生改变等),或者状态(窗口选中、切换等);当程序触发了某种事件,那么即可发射出来一个信号。
槽 [Slot]
如果想捕获这个信号,然后执行相应的逻辑代码,那么就需要使用到槽,槽实际上是一个函数,当信号发射出来后,会执行与之绑定的槽函数。
信号与槽的连接
为了实现点击某个按钮实现对应函数时,需要把具体的信号和槽绑定到一起。
大致操作流程与方法如下
对象.信号.connect(槽函数)
信号与槽 Demon
接收信号
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()
实现效果
自定义信号
除了接收Qt自带的信号外,也可以自行定义信号,在合适的时机,自行发射信号。
方法:pyqtSingal
声明信号需要在类中的函数之外进行声明
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)
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 + "【发现漏洞】")
time.sleep(0.01)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
实现效果
综合应用
import sys
import time
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("信号与槽")
self.init_ui()
# 主初始化方法
def main_window_init(self):
# 设置窗口大小
self.resize(300, 200)
# 主界面布局 [垂直布局]
self.main_layout = QVBoxLayout()
def init_ui(self):
self.main_window_init()
# 信息Box初始化
self.message_widget_init()
# 设置Box初始化
self.seeting_widget_init()
# 将两个Group添加至主布局器中
self.main_layout.addWidget(self.message_group_box)
self.main_layout.addWidget(self.seeting_group_box)
self.setLayout(self.main_layout)
# 信息部分初始化方法
def message_widget_init(self):
# 信息界面组Group
self.message_group_box = QGroupBox("信息")
# 两个控件水平布局
horizon_layout = QHBoxLayout()
# 控件1:设置转盘控件
self.control_1 = QDial()
# 是否循环滚动 [默认是]
self.control_1.setWrapping(True)
# 是否显示刻度
self.control_1.setNotchesVisible(True)
# 绑定信号至槽函数Dialg_Signal
self.control_1.valueChanged.connect(self.Dialg_Signal)
# 控件2:信息框
# 信息框垂直布局
message_vertical_layout = QVBoxLayout()
# 文字
Message_Lable = QLabel("数值")
# 信息框
self.control_2 = QSpinBox()
# 两个控件添加至垂直布局中
message_vertical_layout.addWidget(self.control_2)
message_vertical_layout.addWidget(Message_Lable)
# 两个控件绑定至垂直布局中
horizon_layout.addWidget(self.control_1)
horizon_layout.addLayout(message_vertical_layout)
# 将垂直布局添加至组中
self.message_group_box.setLayout(horizon_layout)
# 设置部分初始化方法
def seeting_widget_init(self):
# 设置界面组Group
self.seeting_group_box = QGroupBox("设置")
# 控件网格布局
self.grid_layout = QGridLayout()
# 设置项:是否显示刻度
self.seeting_norchesvisible()
self.seeting_notchesVisile()
# 显示刻度组添加至网格布局中
self.grid_layout.addWidget(self.norchesvisible_group_box,1,1)
# 是否循环组添加至网格布局中
self.grid_layout.addWidget(self.notchesVisile_group_box,1,2)
# 将网格布局添加至主Group中
self.seeting_group_box.setLayout(self.grid_layout)
# 设置项:是否显示刻度
def seeting_norchesvisible(self):
# 显示刻度组Group
self.norchesvisible_group_box = QGroupBox("显示刻度")
# 下拉选框控件[是否显示刻度]
self.Combo_NotchesVisible = QComboBox()
# 该Group中为垂直布局
norchesvisible_vertical_layout = QVBoxLayout()
# 配置下拉选框是否可以编辑
self.Combo_NotchesVisible.setEditable(False)
# 添加控件元素
self.Combo_NotchesVisible.addItem("显示")
self.Combo_NotchesVisible.addItem("不显示")
# 连接槽函数至seeting_norchesvisible_Signal
self.Combo_NotchesVisible.currentIndexChanged.connect(self.seeting_norchesvisible_Signal)
# 将Combo_NotchesVisible[下拉选择框]添加至垂直布局中
norchesvisible_vertical_layout.addWidget(self.Combo_NotchesVisible)
# 将norchesvisible_vertical_layout[Group]添加至主Group中
self.norchesvisible_group_box.setLayout(norchesvisible_vertical_layout)
# 设置项:是否允许转盘循环
def seeting_notchesVisile(self):
# 是否循环Group
self.notchesVisile_group_box = QGroupBox("循环滚动")
# 下拉框选择控件
self.Combo_notchesVisile = QComboBox()
# 该Group内为垂直布局
notchesVisile_vertical_layout = QVBoxLayout()
# 配置下拉选框是否可以编辑
self.Combo_NotchesVisible.setEditable(False)
# 添加控件元素
self.Combo_notchesVisile.addItem("循环")
self.Combo_notchesVisile.addItem("不循环")
# 连接槽函数至
self.Combo_notchesVisile.currentIndexChanged.connect(self.seeting_notchesVisile_Signal)
# 将Combo_notchesVisile[下拉选择框]添加至垂直布局中
notchesVisile_vertical_layout.addWidget(self.Combo_notchesVisile)
# 将notchesVisile_vertical_layout[Group]添加至主Group中
self.notchesVisile_group_box.setLayout(notchesVisile_vertical_layout)
# 转盘信号槽方法 [回调函数]
def Dialg_Signal(self):
self.control_2.setValue(self.control_1.value())
# 设置项:是否显示刻度 [回调函数]
def seeting_norchesvisible_Signal(self):
# 判断索引号:0[显示] 1[不显示]
if self.Combo_NotchesVisible.currentIndex() == 0:
self.control_1.setNotchesVisible(True)
elif self.Combo_NotchesVisible.currentIndex() == 1:
self.control_1.setNotchesVisible(False)
# 设置项:是否允许转盘循环 [回调函数]
def seeting_notchesVisile_Signal(self):
# 判断索引号:0[循环] 1[不循环]
if self.Combo_notchesVisile.currentIndex() == 0:
self.control_1.setWrapping(True)
elif self.Combo_notchesVisile.currentIndex() == 1:
self.control_1.setWrapping(False)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
实现效果