当前位置:网站首页>PySide6 信号、槽
PySide6 信号、槽
2022-07-06 09:27:00 【擒贼先擒王】
信号与槽的入门应用(一):https://blog.csdn.net/jia666666/article/details/81774175
信号与槽的再细分(二):https://blog.csdn.net/jia666666/article/details/81774858
信号与槽的高级玩法(三):https://blog.csdn.net/jia666666/article/details/81775378
信号与槽的高级用法(四):https://blog.csdn.net/jia666666/article/details/81775614
Qt Designer神助攻(五):https://blog.csdn.net/jia666666/article/details/81780619
多线程中信号与槽的使用(六):https://blog.csdn.net/jia666666/article/details/81780930
多窗口数据传递(七):https://blog.csdn.net/jia666666/article/details/81781697
事件处理机制(八):https://blog.csdn.net/jia666666/article/details/81781992
1、根据 使用 进行分类
1. 内置信号、内置槽
内置信号与槽的使用,是指在发射信号时,使用窗口控件的函数,而不是自定义的函数,这种也是我们前面用的最多。示例:
# -*- coding: utf-8 -*-
import sys
from PySide6.QtWidgets import QMessageBox, QPushButton, QApplication, QWidget
def show_msg():
QMessageBox.information(widget, '信息提示框', 'Ok 弹出测试信息')
app = QApplication(sys.argv)
widget = QWidget()
btn = QPushButton('测试点击按钮', widget)
btn.clicked.connect(show_msg)
widget.resize(300, 300)
widget.show()
sys.exit(app.exec())
这个例子将一个按钮对象的内置clicked信号与自定义槽函数show_msg() 连接。单击按钮,就会触发这个槽函数,弹出一个信息提示框
2. 自定义信号、自定义槽
自定义信号与槽的使用:是指在发射信号时,不使用窗口控件的函数,而是使用自定义的函数,(简单的说就是使用oyqtsSignal类实例发射信号),之所以要使用自定义的信号与槽,是因为通过内置函数发射信号有自身的缺陷,首先,内置函数只包含一些常用地信号,有些信号发射找不到对应的内置函数,其次在特定的情况下,才能发射此信号,如按钮的点击事件,最后,内置函数传递的参数是特定的,不可以自定义,使用自定义的信号与槽函数则没有这些缺陷
在pyqt5中,自定义信号与槽的适用很灵活,比如因为业务需要,在程序中的某些地方需要发射一个信号,传递多种数据,然后在槽函数接受这些数据,这样就可以很灵活的实现一些业务逻辑
简单的一个实例:简单的自定义信号与槽
import sys
from PySide6 import QtCore
# 定义一个名字叫 say_some_words 的 slot, 并接收string
@QtCore.Slot(str)
def say_some_words(words):
print(words)
# 信号对象
class Communicate(QtCore.QObject):
# 创建一个名字叫 speak 的信号
speak = QtCore.Signal(str)
some_one = Communicate()
# connect signal and slot
some_one.speak.connect(say_some_words)
# emit 'speak' signal
some_one.speak.emit("Hello everybody!")
添加重载:
import sys
from PySide6 import QtCore
# define a new slot that receives a C 'int' or a 'str'
# and has 'saySomething' as its name
@QtCore.Slot(int)
@QtCore.Slot(str)
def say_something(stuff):
print(stuff)
class Communicate(QtCore.QObject):
# create two new signals on the fly: one will handle
# int type, the other will handle strings
speakNumber = QtCore.Signal(int)
speakWord = QtCore.Signal(str)
someone = Communicate()
# connect signal and slot properly
someone.speakNumber.connect(say_something)
someone.speakWord.connect(say_something)
# emit each 'speak' signal
someone.speakNumber.emit(10)
someone.speakWord.emit("Hello everybody!")
使用槽重载以及一些复杂的信号连接及发射
import sys
from PySide6 import QtCore
# define a new slot that receives an C 'int' or a 'str'
# and has 'saySomething' as its name
@QtCore.Slot(int)
@QtCore.Slot(str)
def say_something(stuff):
print(stuff)
class Communicate(QtCore.QObject):
# create two new signals on the fly: one will handle
# int type, the other will handle strings
speak = QtCore.Signal((int,), (str,))
someone = Communicate()
# connect signal and slot. As 'int' is the default
# we have to specify the str when connecting the
# second signal
someone.speak.connect(say_something)
someone.speak[str].connect(say_something)
# emit 'speak' signal with different arguments.
# we have to specify the str as int is the default
someone.speak.emit(10)
someone.speak[str].emit("Hello everybody!")
示例:
import sys
from PySide6.QtCore import QObject, Signal, Slot
"""
PyQt使用了另外一种方式。为了将PyQt脚本转而使用PySide运行
只需要使用下面的代码进行修改。
from PySide.QtCore import Signal as pyqtSignal
from PySide.QtCore import Slot as pyqtSlot
或者
QtCore.pyqtSignal = QtCore.Signal
QtCore.pyqtSlot = QtCore.Slot
"""
# 信号对象
class CustomSignal(QObject):
# 定义一个信号
signal_send_msg = Signal(str, str)
def __init__(self):
super(CustomSignal, self).__init__()
def run(self):
# 发射信号
# self.sendmsg.emit('hell')
# 发射多个参数
self.signal_send_msg.emit('第一参数', '第二个参数')
# 槽对象
class CustomSlot(QObject):
def __init__(self):
super(CustomSlot, self).__init__()
self.temp = None
# 槽对象中的槽函数
# def get( self,msg ):
# print("QSlot get msg => " + msg)
# 多个参数
def get_msg(self, msg1, msg2):
self.temp = None
print("QSlot get msg => " + msg1 + ' ' + msg2)
if __name__ == '__main__':
custom_signal = CustomSignal() # 实例化信号对象
custom_slot = CustomSlot() # 实例化槽对象
# 把信号绑定到槽函数上
custom_signal.signal_send_msg.connect(custom_slot.get_msg)
custom_signal.run()
# 把信号与槽函数解绑
custom_signal.signal_send_msg.disconnect(custom_slot.get_msg)
custom_signal.run()
3. 装饰器的信号、槽
所谓装饰器信号与槽,就是通过 装饰器 的方法来定义信号与槽函数
示例:通过 @QtCore.Slot(str) 装饰一个函数,把函数变成一个 槽函数
import sys
from PySide6 import QtCore
# 定义一个名字叫 say_some_words 的 slot, 并接收string
@QtCore.Slot(str)
def say_some_words(words):
print(words)
# 信号对象
class Communicate(QtCore.QObject):
# 创建一个名字叫 speak 的信号
speak = QtCore.Signal(str)
some_one = Communicate()
# connect signal and slot
some_one.speak.connect(say_some_words)
# emit 'speak' signal
some_one.speak.emit("Hello everybody!")
2、根据信号与槽各自的性质分类
内置信号、内置槽函数
演示单击时关闭窗口,使用内置的信号与槽函数
# -*- coding: utf-8 -*-
from PySide6.QtWidgets import *
import sys
class WinForm(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('内置的信号/槽示例')
self.resize(300, 150)
btn = QPushButton('关闭', self)
btn.clicked.connect(self.close)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec())
内置信号、自定义槽函数
# -*- coding: utf-8 -*-
from PySide6.QtWidgets import *
import sys
class WinForm(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('内置的信号和自定义槽函数示例')
self.resize(300, 150)
btn = QPushButton('关闭', self)
btn.clicked.connect(self.btn_close)
def btn_close(self):
# 自定义槽函数
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec())
自定义信号、内置槽函数
# -*- coding: utf-8 -*-
import sys
from PySide6 import QtCore
from PySide6.QtWidgets import *
class WinForm(QWidget):
# 自定义信号,不带参数
button_clicked_signal = QtCore.Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('自定义信号和内置槽函数示例')
self.resize(300, 150)
btn = QPushButton('关闭', self)
# 连接 信号和槽
btn.clicked.connect(self.btn_clicked)
# 接收信号,连接到槽
self.button_clicked_signal.connect(self.close)
def btn_clicked(self):
# 发送自定义信号,无参数
self.button_clicked_signal.emit()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec())
自定义信号、自定义槽函数
# -*- coding: utf-8 -*-
import sys
from PySide6 import QtCore
from PySide6.QtWidgets import *
class WinForm(QWidget):
# 自定义信号,不带参数
button_clicked_signal = QtCore.Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('自定义信号和槽函数示例')
self.resize(300, 150)
btn = QPushButton('关闭', self)
# 连接 信号和槽
btn.clicked.connect(self.btn_clicked)
# 接收信号,连接到自定义槽函数
self.button_clicked_signal.connect(self.btn_close)
def btn_clicked(self):
# 发送自定义信号,无参数
self.button_clicked_signal.emit()
def btn_close(self):
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec())
3、信号、槽 高级用法
所谓高级,就是自定义信号与槽时,可以传递参数。
自定义信号一般流程
定义信号
定义槽函数
连接信号与槽函数
发射信号
定义 信号
通过 类成员变量 定义信号对象
signal1 = QtCore.Signal() # 无参数的信号
signal2 = QtCore.Signal(int) # 带一个参数(整数)的信号
signal3 = QtCore.Signal(int, str) # 带两个参数(整数,字符串)的信号
signal4 = QtCore.Signal(list) # 带一个参数(列表)的信号
signal5 = QtCore.Signal(dict) # 带一个参数(字典)的信号
signal6 = QtCore.Signal([int, str], [str]) # 带(整数 字符串)或者(字符串)的信号
定义 槽函数
定义一个槽函数,它有多个不同的输入参输数
def signal_call_1(self):
print("signal1 emit")
def signal_call_2(self, val):
print('signal2 emit,value:', val)
def signal_call_3(self, val, text):
print('signall3 emit,value:', val, text)
def signal_call_4(self, val):
print('signal4 emit,value:', val)
def signal_call_5(self, val):
print('signal5 emit,value', val)
def signal_call_6(self, val, text):
print('signal6 emit,value', val, text)
def signal_call_7(self, val):
print('signal6 overload emit', val)
连接信号 与 槽函数
#信号与槽函数的链接
self.signal1.connect(self.signal_call_1)
self.signal2.connect(self.signal_call_2)
self.signal3.connect(self.signal_call_3)
self.signal4.connect(self.signal_call_4)
self.signal5.connect(self.signal_call_5)
self.signal6[int,str].connect(self.signal_call_6)
self.signal6[str].connect(self.signal_call_7)
发射信号
#信号发射
self.signal1.emit()
self.signal2.emit(1)
self.signal3.emit(1,'第三个')
self.signal4.emit([1,2,3,4])
self.signal5.emit({"name":'JIA','age':'21'})
self.signal6[int,str].emit(1,"第六")
self.signal6[str].emit('第六')
实例:完整代码如下
# -*- coding: utf-8 -*-
import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import QObject, Signal, Slot
class CustomSignal(QObject):
signal1 = Signal() # 无参数的信号
signal2 = Signal(int) # 带一个参数(整数)的信号
signal3 = Signal(int, str) # 带两个参数(整数,字符串)的信号
signal4 = Signal(list) # 带一个参数(列表)的信号
signal5 = Signal(dict) # 带一个参数(字典)的信号
signal6 = Signal([int, str], [str]) # 带(整数 字符串)或者(字符串)的信号
def __init__(self, parent=None):
super(CustomSignal, self).__init__(parent)
# 信号与槽函数的链接
self.signal1.connect(self.signal_call_1)
self.signal2.connect(self.signal_call_2)
self.signal3.connect(self.signal_call_3)
self.signal4.connect(self.signal_call_4)
self.signal5.connect(self.signal_call_5)
self.signal6[int, str].connect(self.signal_call_6)
self.signal6[str].connect(self.signal_call_7)
# 信号发射
self.signal1.emit()
self.signal2.emit(1)
self.signal3.emit(1, '第三个')
self.signal4.emit([1, 2, 3, 4])
self.signal5.emit({"name": 'JIA', 'age': '21'})
self.signal6[int, str].emit(1, "第六")
self.signal6[str].emit('第六')
# 槽函数
def signal_call_1(self):
print("signal1 emit")
def signal_call_2(self, val):
print('signal2 emit,value:', val)
def signal_call_3(self, val, text):
print('signall3 emit,value:', val, text)
def signal_call_4(self, val):
print('signal4 emit,value:', val)
def signal_call_5(self, val):
print('signal5 emit,value', val)
def signal_call_6(self, val, text):
print('signal6 emit,value', val, text)
def signal_call_7(self, val):
print('signal6 overload emit', val)
if __name__ == '__main__':
custom_signal = CustomSignal()
自定义参数的传递
在编程过程中,经常会遇到给槽函数传递自定义参数的情况,比如有一个信号与槽函数的连接是
button.clicked.connect(show_page)
对于clicked 信号,它是没有参数的,对于show_page函数来说,希望他可以接受参数,希望show_page 函数如下这样
def show_page(self,name):
print(name',点击了’)
于是就会产生一个问题,信号发出的参数个数与槽函数接受的参数个数不一,那么如何解决这个问题呢 ? 这里提供两种解决方法;
- 第一种:lamdba表达式
- 第二种:使用functools中的partial函数
两种方法,下面均已写上,自己可运行查看,注意注释。
# -*- coding: utf-8 -*-
import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import QObject, Signal, Slot
from functools import partial
class WinForm(QMainWindow):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
# 实例化两个按钮
button1 = QPushButton('Button1')
button2 = QPushButton('Button2')
# todo 第一种方法
# 单击信号关联槽函数,利用 lambda 表达式传递一个参数
# button1.clicked.connect(lambda :self.onButtonClick(1))
# button2.clicked.connect(lambda :self.onButtonClick(2))
#
# todo 第二种方法
button1.clicked.connect(partial(self.btn_click, 1))
button2.clicked.connect(partial(self.btn_click, 2))
# 实例化窗口
main = QWidget()
# 设置窗口的布局,并向其中添加控件
layout = QHBoxLayout(main)
layout.addWidget(button1)
layout.addWidget(button2)
# 设置为中央控件
self.setCentralWidget(main)
self.resize(500, 500)
def btn_click(self, n):
# 弹窗信息提示框,输出被点击的信息
print("Button {0}".format(n))
QMessageBox.information(self, '信息提示框', 'Button {0}'.format(n))
if __name__ == '__main__':
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec_())
使用 lambda 表达式传递按钮数字给槽函数,当然还可以传递其他东西,甚至是按钮本身
button1.clicked.connect(lambda :self.onButtonClick(1))
button2.clicked.connect(lambda :self.onButtonClick(2))
使用 functools 中的 partial 函数可以固定函数参数
button1.clicked.connect(partial(self.onButtonClick, 1))
button2.clicked.connect(partial(self.onButtonClick, 2))
装饰器信号与槽
所谓装饰器信号与槽,就是通过装饰器的方法来定义信号与槽函数。
如下
@PySide6.QtCore.Slot(参数)
def on_发送者对象名称)发射信号名称(self,参数):
pass
这种方法有效的前提是下面的函数已经执行:
QMetaObject.connectSlotsByName(QObject)
在上面的代码中,"发送者对象名称" 就是使用 "setObjectName函数" 设置的名称。因此自定义槽函数的命名规则也可以看做:
on + 使用setObjectName 设置的名称 + 信号名称
具体实例
# -*- coding: utf-8 -*-
import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import QObject, Signal, Slot, QMetaObject
class WinForm(QWidget):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.btn_ok = QPushButton('ok', self) # 创建按钮,添加到自身窗口中
self.btn_ok.setObjectName('btn_ok') # 使用 setObjectName 设置对象名称
# 设置自身的布局为水平布局,并添加按钮控件到其中
layout = QHBoxLayout(self)
layout.addWidget(self.btn_ok)
self.resize(300, 150)
# TODo 第一种方法
# self.okButton.clicked.connect(self.btn_ok_clicked)
# 第二种方法
QMetaObject.connectSlotsByName(self)
# def btn_ok_clicked(self):
# print('单击了ok按钮')
@Slot()
def on_btn_ok_clicked(self):
print('单击了ok按钮')
if __name__ == '__main__':
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec())
QtCore.QMetaObject.connectSlotsByName(self) 是 PySide6 中根据 信号名称自动连接到槽函数的核心代码,这行代码用来将 QObject 中的子孙对象的某些对象按照其 objectName 连接到相应的槽函数。
举个例子说名一下,假设代码 QtCore.QMetaObject.connectSlotsByName(self) 已经执行,则下面的代码
@QtCore.Slot()
def on_okButton_clicked(self):
print('单击了ok按钮')
会被自动识别为下面的代码
def __init__(self,parent=None):
self.okButton.clicked.connect(self.okButton_clicked)
def okButton_clicked(self):
print('单击了ok按钮')
信号与槽的断开与连接
有时候基于某些原因,想要临时或永久的断开某个信号与槽函数的连接,一般把 connect 前面加上dis 就是解除绑定的意思:即disconnect
实例如下
# -*- coding: utf-8 -*-
import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import QObject, Signal, Slot, QMetaObject
class SignalClass(QObject):
signal1 = Signal() # 声明无参数的信号
signal2 = Signal(int) # 声明带一个int类型参数的信号
def __init__(self, parent=None):
super(SignalClass, self).__init__(parent)
# 将 signal1 信号连接到两个槽函数
self.signal1.connect(self.sig1Call)
self.signal1.connect(self.sig2Call)
# 将signal2信号连接到信号1
self.signal2.connect(self.signal1)
# 发射信号
self.signal1.emit()
self.signal2.emit(1)
# 断开信号与槽函数的关系
self.signal1.disconnect(self.sig1Call)
self.signal1.disconnect(self.sig2Call)
self.signal2.disconnect(self.signal1)
# 绑定信号与槽函数
self.signal1.connect(self.sig1Call)
self.signal2.connect(self.sig1Call)
# 信号发射
self.signal1.emit()
self.signal2.emit(1)
# 输出信号1发射
def sig1Call(self):
print('signal-1 emit')
# 输出信号2发射
def sig2Call(self):
print('signal-2 emit')
if __name__ == '__main__':
signal = SignalClass()
4、信号 与 槽 之 Qt Designer 神助攻
前面都是手工输入代码的信号与槽的使用方法,因为采用这种方法介绍时会简单一些。但是在实战应用中,由于 Qt Designer 可以很好的实现界面显示与业务逻辑分离,如果能够使用 Qt Designer 自动创建一些信号与槽机制,那就更好了
本例要实现的功能是:通过一个模拟打印的界面来详细说明信号的使用,在打印时,可以设置打印的份数,纸张类型,触发打印按钮后,将执行结果显示在右侧,通过QCheckBox(全屏预览 复选框)来选择是否通过全屏模式进行预览,将执行结果显示在右侧
按F1键可以显示helpmessage帮助信息
第一步:Qt Designer
首先,使用Qt Designer新建一个模板名为widget的简单窗口,通过将widget box区域的控件拖曳到窗口中,实现如图的界面效果
这里对窗口控件进行简要说明
控件类型 | 控件名称 | 作用 |
QSpinBox | numberSpinBox | 显示打印的分数 |
QComboBox | styleCombo | 显示打印的纸张类型,纸张类型包括A3,A4等 |
QPushButton | printButton | 连接emitPrintSiagnal函数的绑定,触发自定义信号printSignal的发射 |
QCheckBox | prievewState | 是否全屏预览 |
QPushButton | priviewButton | 连接emitPreviewSignal函数的绑定,触发自定义信号previewSignal的发射 |
QLabel | resultLabel | 显示执行结果 |
第二步:将界面文件ui转换为py文件
pyuic5 -o xxxxx.py xxxxx.ui
会在界面文件同级目录下生成一个py文件,为了使窗口的显示与业务逻辑分离,在建一个调用窗口显示的文件,在调用类中添加多个自定义信号,并与槽函数进行绑定,其完整代码如下
# -*- coding: utf-8 -*-
import sys
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtWidgets import *
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("Form")
MainWindow.resize(715, 225)
self.controlsGroup = QtWidgets.QGroupBox(MainWindow)
self.controlsGroup.setGeometry(QtCore.QRect(10, 20, 451, 151))
self.controlsGroup.setObjectName("controlsGroup")
self.widget = QtWidgets.QWidget(self.controlsGroup)
self.widget.setGeometry(QtCore.QRect(10, 40, 411, 30))
self.widget.setObjectName("widget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QtWidgets.QLabel(self.widget)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.numberSpinBox = QtWidgets.QSpinBox(self.widget)
self.numberSpinBox.setObjectName("numberSpinBox")
self.horizontalLayout.addWidget(self.numberSpinBox)
self.styleCombo = QtWidgets.QComboBox(self.widget)
self.styleCombo.setObjectName("styleCombo")
self.styleCombo.addItem("")
self.styleCombo.addItem("")
self.styleCombo.addItem("")
self.horizontalLayout.addWidget(self.styleCombo)
self.label_2 = QtWidgets.QLabel(self.widget)
self.label_2.setObjectName("label_2")
self.horizontalLayout.addWidget(self.label_2)
self.printButton = QtWidgets.QPushButton(self.widget)
self.printButton.setObjectName("printButton")
self.horizontalLayout.addWidget(self.printButton)
self.widget1 = QtWidgets.QWidget(self.controlsGroup)
self.widget1.setGeometry(QtCore.QRect(10, 100, 201, 30))
self.widget1.setObjectName("widget1")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget1)
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.previewStatus = QtWidgets.QCheckBox(self.widget1)
self.previewStatus.setObjectName("previewStatus")
self.horizontalLayout_2.addWidget(self.previewStatus)
self.previewButton = QtWidgets.QPushButton(self.widget1)
self.previewButton.setObjectName("previewButton")
self.horizontalLayout_2.addWidget(self.previewButton)
self.resultGroup = QtWidgets.QGroupBox(MainWindow)
self.resultGroup.setGeometry(QtCore.QRect(470, 20, 231, 151))
self.resultGroup.setObjectName("resultGroup")
self.resultLabel = QtWidgets.QLabel(self.resultGroup)
self.resultLabel.setGeometry(QtCore.QRect(20, 30, 191, 101))
self.resultLabel.setObjectName("resultLabel")
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("Form", "打印控件"))
self.controlsGroup.setTitle(_translate("Form", "打印控制"))
self.label.setText(_translate("Form", "打印份数:"))
self.styleCombo.setItemText(0, _translate("Form", "A3"))
self.styleCombo.setItemText(1, _translate("Form", "A4"))
self.styleCombo.setItemText(2, _translate("Form", "A5"))
self.label_2.setText(_translate("Form", "纸张类型:"))
self.printButton.setText(_translate("Form", "打印"))
self.previewStatus.setText(_translate("Form", "全屏预览"))
self.previewButton.setText(_translate("Form", "预览"))
self.resultGroup.setTitle(_translate("Form", "操作结果"))
self.resultLabel.setText(_translate("Form", "<html><head/><body><p><br/></p></body></html>"))
class MyMainWindow(QMainWindow, Ui_MainWindow):
help_signal = QtCore.Signal(str)
print_signal = QtCore.Signal(list)
# 声明一个多重载版本的信号,包括了一个带int和str类型参数的信号,以及带str参数的信号
preview_signal = QtCore.Signal([int, str], [str])
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.setupUi(self)
self.init_signal_and_slot()
def init_signal_and_slot(self):
self.help_signal.connect(self.show_help_message)
self.print_signal.connect(self.print_paper)
self.preview_signal[str].connect(self.preview_paper)
self.preview_signal[int, str].connect(self.preview_paper_with_args)
self.printButton.clicked.connect(self.emit_print_signal)
self.previewButton.clicked.connect(self.emit_preview_signal)
# 发射预览信号
def emit_preview_signal(self):
if self.previewStatus.isChecked():
self.preview_signal[int, str].emit(1080, " Full Screen")
elif not self.previewStatus.isChecked():
self.preview_signal[str].emit("Preview")
# 发射打印信号
def emit_print_signal(self):
print_info = [self.numberSpinBox.value(), self.styleCombo.currentText()]
self.print_signal.emit(print_info)
def print_paper(self, print_info):
self.resultLabel.setText("打印: " + "份数:" + str(print_info[0]) + " 纸张:" + str(print_info[1]))
def preview_paper_with_args(self, style, text):
self.resultLabel.setText(str(style) + text)
def preview_paper(self, text):
self.resultLabel.setText(text)
# 重载点击键盘事件
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_F1:
self.help_signal.emit("help message")
# 显示帮助消息
def show_help_message(self, message):
self.resultLabel.setText(message)
self.statusBar().showMessage(message)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MyMainWindow()
win.show()
sys.exit(app.exec())
5、多线程中信号与槽的使用
最简单的多线程 QThread 使用
方法是利用 QThread 函数。
示例:QThread 函数和信号简单结合的方法
# -*- coding: utf-8 -*-
import sys
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class MyThread(QThread):
# 自定义信号参数为str类型
custom_signal = Signal(str)
def __init__(self, parent=None):
super(MyThread, self).__init__(parent)
# 初始化名称为空
self.times = None
self.identity = None
def set_identity(self, text):
# 设置多线程名称
self.identity = text
def set_val(self, val):
# 接受数据,运行多线程
self.times = int(val)
self.run()
def run(self):
# 当次数大于0以及名称不为空时执行代码
while self.times > 0 and self.identity:
# 发射信号,触发打印函数,次数-1
self.custom_signal.emit(self.identity + '==>' + str(self.times))
self.times -= 1
class WinForm(QWidget):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
# 创建一个线程实例并设置名称 变量 信号与槽
self.thread = MyThread()
self.thread.set_identity('thread1')
self.thread.custom_signal.connect(self.out_text)
self.thread.set_val(6)
# 打印输出文本
def out_text(self, text):
print(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec())
pass
示例:
import sys, time
from PySide6.QtCore import (
Signal, Slot, Qt, QThread
)
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QPushButton, QLabel, QApplication
)
class mainWindow(QWidget):
def __init__(self) -> None:
super().__init__()
self.label = QLabel("Hello!")
self.label.setAlignment(Qt.AlignCenter)
self.but = QPushButton("Click!")
self.but.clicked.connect(self.fun)
self.layout = QVBoxLayout()
self.layout.addWidget(self.label)
self.layout.addWidget(self.but)
self.setLayout(self.layout)
self.setWindowTitle('Signal Example')
self.resize(300, 300)
self.show()
@Slot()
def fun(self):
self.th = Th()
self.th.timer.connect(self.flushlabel)
self.th.finish.connect(self.isFinish)
self.th.start()
@Slot(int)
def flushlabel(self, nu):
self.label.setText(str(nu))
@Slot(bool)
def isFinish(self, bo):
if bo is True:
self.but.setEnabled(True)
else:
self.but.setEnabled(False)
class Th(QThread):
timer = Signal(int)
finish = Signal(bool)
def __init__(self) -> None:
super().__init__()
def run(self):
print('Start Timer')
self.finish.emit(False)
for x in range(5):
self.timer.emit(5 - x)
time.sleep(1)
self.finish.emit(True)
if __name__ == '__main__':
app = QApplication([])
widgets = mainWindow()
sys.exit(app.exec())
主线程与子线程的使用
有时候在开发程序时会经常执行一些耗时的操作,这样就会导致界面卡顿,这也是多线程的应用范围之一,这样我们就可以创建多线程,使用主线程更新界面,使用子线程后台处理数据,最后将结果显示在界面上
# -*- coding: utf-8 -*-
import sys
import time
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class BackQthread(QThread):
# 自定义信号为str参数类型
update_date = Signal(str)
def run(self):
while True:
# 获得当前系统时间
data = QDateTime.currentDateTime()
# 设置时间显示格式
current_time = data.toString('yyyy-MM-dd hh:mm:ss dddd')
# 发射信号
self.update_date.emit(str(current_time))
# 睡眠一秒
time.sleep(1)
class window(QDialog):
def __init__(self):
super(window, self).__init__()
# 设置标题与初始大小
self.backend = None
self.setWindowTitle('PyQt5界面实时更新的例子')
self.resize(400, 100)
# 实例化文本输入框及其初始大小
self.input = QLineEdit(self)
self.input.resize(400, 100)
self.init_ui()
def init_ui(self):
# 实例化对象
self.backend = BackQthread()
# 信号连接到界面显示槽函数
self.backend.update_date.connect(self.handle_display)
# 多线程开始
self.backend.start()
def handle_display(self, data):
# 设置单行文本框的文本
self.input.setText(data)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = window()
win.show()
sys.exit(app.exec())
6、信号与槽之多窗口数据传递
在pyqt编程过程中,经常会遇到输入或选择多个参数的问题,把多个参数写到一个窗口中,主窗口会显得很臃肿,所以,一般是添加一个按钮,调用对话框,在对话框中进行参数的选择,关闭对话框将参数返回给主窗口
pyqt提供了一些标准的对话框类,用于输入数据,修改数据,更改应用的设置等,常见的有QFileDialog,QInputDialog,QColorDialog, QFontDialog等,在不同的窗口之间传参数有两种常用的方式,一种在自定义对话框之间通过属性传参,另一种在窗口之间使用信号与槽
示例 1:单一窗口的数据传递
对于具有单一窗口的程序来说,一个控件的变化会影响另一个控件的变化,这中变化利用信号与槽的关系非常容易解决
# -*- coding: utf-8 -*-
import sys
import time
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class WinForm(QWidget):
def __init__(self):
super(WinForm, self).__init__()
self.init_ui()
def init_ui(self):
# 先创建水平滑块和Lcd控件
lcd = QLCDNumber(self)
slider = QSlider(Qt.Horizontal, self)
# 垂直布局,添加控件
vbox = QVBoxLayout()
vbox.addWidget(lcd)
vbox.addWidget(slider)
# 设置窗口布局
self.setLayout(vbox)
# 设置滑块数值信号改变连接Lcd的更新
slider.valueChanged.connect(lcd.display)
# 设置初始位置以及初始大小,设置标题
self.setGeometry(300, 300, 350, 150)
self.setWindowTitle('信号与槽:连接滑块LCd')
if __name__ == '__main__':
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec())
示例 2:多窗口数据传递:调用属性
新建对话框子窗口属性,form_QDialog.py
import sys
import time
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class DateDialog(QDialog):
def __init__(self, parent=None):
super(DateDialog, self).__init__(parent)
self.setWindowTitle('DateDialog')
# 在布局中添加控件
layout = QVBoxLayout(self)
self.datetime = QDateTimeEdit(self)
self.datetime.setCalendarPopup(True)
self.datetime.setDateTime(QDateTime.currentDateTime())
layout.addWidget(self.datetime)
buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)
layout.addWidget(buttons)
def date_time(self):
return self.datetime.dateTime()
@staticmethod
def get_datetime(parent=None):
dialog = DateDialog(parent)
result = dialog.exec_()
date = dialog.date_time()
return date.date(), date.time(), result == QDialog.Accepted
再新建一个主窗口文件 form_main.py ,用来调用 form_QDialog.py
# -*- coding: utf-8 -*-
# @Author : 佛祖保佑, 永无 bug
# @Date :
# @File : form_main.py.py
# @Software: PyCharm
# @description : XXX
import sys
from PySide6.QtWidgets import *
from form_QDialog import DateDialog
class WinForm(QWidget):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.resize(400, 90)
self.setWindowTitle('对话框关闭时返回值给主窗口的例子')
self.lineEdit = QLineEdit(self)
self.btn1 = QPushButton('弹出对话框1')
self.btn1.clicked.connect(self.on_btn1_clicked)
self.btn2 = QPushButton('弹出对话框2')
self.btn2.clicked.connect(self.on_btn2_clicked)
grid_layout = QGridLayout(self)
grid_layout.addWidget(self.lineEdit)
grid_layout.addWidget(self.btn1)
grid_layout.addWidget(self.btn2)
def on_btn1_clicked(self):
dialog = DateDialog(self)
result = dialog.exec()
date = dialog.date_time()
self.lineEdit.setText(date.date().toString())
print('\n日期对话框的返回值')
print('date=%s' % str(date.date))
print('time=%s' % str(date.time()))
print('result=%s' % result)
def on_btn2_clicked(self):
date, time, result = DateDialog.get_datetime()
self.lineEdit.setText(date.toString())
print('\n 日期对话框的返回值')
print('date=%s' % str(date))
print('time=%s' % str(time))
print('result=%s' % result)
if __name__ == '__main__':
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec())
pass
运行结果:
示例 3:多窗口数据传递:信号与槽
对于多窗口的数据传递,一般是通过子窗口发射信号的,主窗口通过槽函数捕获这个信号,然后获取信号里面的数据。
子窗口发射的信号有两种:
- 一种是发射内置pyqt信号。
- 一种是发射自定义的信号。发射自定义的信号的好处是它的参数可以自定义,可以为int list dict等各种类型与多个参数
建一个子对话框文件,这里名称为:form_QDialog.py
# -*- coding: utf-8 -*-
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
class DateDialog(QDialog):
Signal_OneParameter = Signal(str)
def __init__(self, parent=None):
super(DateDialog, self).__init__(parent)
self.setWindowTitle('子窗口:用来发射信号')
# 在布局中添加部件
layout = QVBoxLayout(self)
self.label = QLabel(self)
self.label.setText('前者发射内置信号\n后者发射自定义信号')
self.datetime_inner = QDateTimeEdit(self)
self.datetime_inner.setCalendarPopup(True)
self.datetime_inner.setDateTime(QDateTime.currentDateTime())
self.datetime_emit = QDateTimeEdit(self)
self.datetime_emit.setCalendarPopup(True)
self.datetime_emit.setDateTime(QDateTime.currentDateTime())
layout.addWidget(self.label)
layout.addWidget(self.datetime_inner)
layout.addWidget(self.datetime_emit)
# 使用两个button(ok和cancel)分别连接accept()和reject()槽函数
buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
Qt.Horizontal, self)
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)
layout.addWidget(buttons)
self.datetime_emit.dateTimeChanged.connect(self.emit_signal)
def emit_signal(self):
date_str = self.datetime_emit.dateTime().toString()
self.Signal_OneParameter.emit(date_str)
创建主窗口 form_main.py,调用对话框文件 form_QDialog.py
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from form_QDialog import DateDialog
class WinForm(QWidget):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.resize(400, 90)
self.setWindowTitle('信号与槽传递参数的示例')
self.open_btn = QPushButton('获取时间')
self.lineEdit_inner = QLineEdit(self)
self.lineEdit_emit = QLineEdit(self)
self.open_btn.clicked.connect(self.open_dialog)
self.lineEdit_inner.setText('接收子窗口内置信号的时间')
self.lineEdit_emit.setText('接收子窗口自定义信号的时间')
grid = QGridLayout()
grid.addWidget(self.lineEdit_inner)
grid.addWidget(self.lineEdit_emit)
grid.addWidget(self.open_btn)
self.setLayout(grid)
def open_dialog(self):
dialog = DateDialog(self)
'''连接子窗口的内置信号与主窗口的槽函数'''
dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)
'''连接子窗口的自定义信号与主窗口的槽函数'''
dialog.Signal_OneParameter.connect(self.deal_emit_slot)
dialog.show()
def deal_inner_slot(self, date):
self.lineEdit_inner.setText(date.toString())
def deal_emit_slot(self, date_str):
self.lineEdit_emit.setText(date_str)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec())
7、信号与槽 之 事件处理机制
信号与槽可以说是对事件处理机制的高级封装,如果说事件是用来创建窗口控件的,那么信号与槽就是用来对这个控件进行使用的,比如一个按钮,当我们使用按钮时,只关心clicked信号,至于这个按钮如何接受并处里鼠标点击事件,然后再发射这个信号,则不关心,但是如果要重载一个按钮,这时候就要关心了,比如可以改变它的行为:在鼠标按下时触发 clicked 信号,而不是释放时
常见事件类型
qt 程序是事件驱动的,它的每个动作都有幕后某个事件所触发,Qt事件类型有很多,常见的如下
- 键盘事件:按键的按下与松开
- 鼠标事件:鼠标指针的移动,鼠标按键的按下与松开
- 拖放事件:用鼠标进行拖放
- 滚轮事件:鼠标滚轮滚动
- 绘屏事件:重绘制屏幕的某些部分
- 定时事件:定时器到时
- 焦点事件:键盘焦点移动
- 进入和离开事件:鼠标指针移入Widget内,或者移出
- 移动事件:Widget的位置改变
- 大小改变事件:widget的大小改变
- 显示和隐藏事件:widget显示与隐藏
- 窗口事件:窗口是否为当前窗口
还有一些常见的 qt 事件,比如 Socket 事件,剪切板事件,字体改变事件,布局改变事件
使用事件处理的方法
pyqt 提供如下 5 种事件处理和过滤的方法(有弱到强),其中只有前两种方法使用最频繁
1. 重新实现事件函数
比如 mousePressEvent(),keyPressEvent(),paintEvent(),这是最常规的事件处理方法
2. 重新实现 QObject.event()
一般用在pyqt没有提供该事件的处理函数的情况下,即增加新事件时
3. 安装事件过滤器
如果对QObject调用installEventFilter,则相当于为这个QObject安装了一个事件过滤器,对于QObject的全部事件来说,它们都会先传递到事件过滤函数eventFilter中,在这个函数中,我们可以抛弃或者修改这些事件,比如对自己感兴趣的事件使用自定义的处理机制,对其他事件采用默认的事件处理机制,由于这中方法会调用installEventFilter的所有QObject的事件进行过滤,因此如果要过滤的事件比较多,则会降低程序的性能
4. 在 QApplication 中安装事件过滤器
这种方法比上一种更强大,QApplication的事件过滤器将捕获所有的QObject事件,而且第一个获得该事件,也就是说,在将事件发送给其他任何一个事件过滤器之前,都会发送给QApplication的事件过滤器
5. 重新实现QApplication的notify()方法
pyqt使用notify来分发事件,要想在任何事件处理器之前捕获事件,唯一的方法就是重新实现QApplication的notify(),在实践中,在调试才会用这中方法
示例:经典案例
绘制事件
调整窗口大小事件
鼠标释放事
鼠标移动事件
键盘按下事件
重载tab键
import sys
from PySide6.QtCore import (QEvent, QTimer, Qt)
from PySide6.QtWidgets import (QApplication, QMenu, QWidget)
from PySide6.QtGui import QPainter
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
# 初始化数据
# 鼠标双击False
self.justDoubleClicked = False
# 按键,输出文本,提示消息为空
self.key = ""
self.text = ""
self.message = ""
# 设置窗口初始大小与位置
self.resize(400, 300)
self.move(100, 100)
# 设置标题
self.setWindowTitle("Events")
# 定时器1秒后执行槽函数
QTimer.singleShot(1000, self.give_help)
# 避免窗口大小重绘事件的影响,可以把参数0改变成3000(3秒),然后在运行,就可以明白这行代码的意思。
def give_help(self):
self.text = "请点击这里触发追踪鼠标功能"
# 重绘事件,也就是触发paintEvent函数。
self.update()
'''重新实现关闭事件'''
def closeEvent(self, event):
print("Closed")
'''重新实现上下文菜单事件'''
def contextMenuEvent(self, event):
# 实例化菜单,添加子菜单one two并附加快捷键功能,关联槽函数
menu = QMenu(self)
one_action = menu.addAction("&One")
two_action = menu.addAction("&Two")
one_action.triggered.connect(self.one)
two_action.triggered.connect(self.two)
# 如果message为空,执行
if not self.message:
# 在菜单中添加一条分割线
menu.addSeparator()
# 添加自菜单three,关联槽函数
threeAction = menu.addAction("Thre&e")
threeAction.triggered.connect(self.three)
# 菜单栏出现在鼠标的位置
menu.exec_(event.globalPos())
'''上下文菜单槽函数'''
def one(self):
self.message = "Menu option One"
self.update()
def two(self):
self.message = "Menu option Two"
self.update()
def three(self):
self.message = "Menu option Three"
self.update()
'''重新实现绘制事件'''
def paintEvent(self, event):
text = self.text
i = text.find("\n\n")
if i >= 0:
text = text[0:i]
# 若触发了键盘按钮,则在文本信息中记录这个按钮信息。
if self.key:
text += "\n\n你按下了: {0}".format(self.key)
painter = QPainter(self)
painter.setRenderHint(QPainter.TextAntialiasing)
# 绘制信息文本的内容
painter.drawText(self.rect(), Qt.AlignCenter, text)
# 若消息文本存在则在底部居中绘制消息,5秒钟后清空消息文本并重绘。
if self.message:
# 显示给定坐标处的文本,坐标,对齐方式。文本内容
painter.drawText(self.rect(), Qt.AlignBottom | Qt.AlignHCenter,
self.message)
# 5秒钟后触发清空信息的函数,并重新绘制事件
QTimer.singleShot(5000, self.clear_message)
QTimer.singleShot(5000, self.update)
'''清空消息文本的槽函数'''
def clear_message(self):
self.message = ""
'''重新实现调整窗口大小事件'''
def resizeEvent(self, event):
self.text = "调整窗口大小为: QSize({0}, {1})".format(
event.size().width(), event.size().height())
self.update()
'''重新实现鼠标释放事件'''
def mouseReleaseEvent(self, event):
# 若鼠标释放为双击释放,则不跟踪鼠标移动
if self.justDoubleClicked:
self.justDoubleClicked = False
# 若鼠标释放为单击释放,则需要改变跟踪功能的状态,如果开启跟踪功能的话就跟踪,不开启跟踪功能就不跟踪
else:
# 单击鼠标
self.setMouseTracking(not self.hasMouseTracking())
if self.hasMouseTracking():
self.text = "开启鼠标跟踪功能.\n" + \
"请移动一下鼠标!\n" + \
"单击鼠标可以关闭这个功能"
else:
self.text = "关闭鼠标跟踪功能.\n" + \
"单击鼠标可以开启这个功能"
self.update()
'''重新实现鼠标移动事件'''
def mouseMoveEvent(self, event):
# 如果没有鼠标双击,执行
if not self.justDoubleClicked:
# 窗口坐标转换为屏幕坐标
global_pos = self.mapToGlobal(event.pos())
self.text = """鼠标位置:
窗口坐标为:QPoint({0}, {1})
屏幕坐标为:QPoint({2}, {3}) """.format(event.pos().x(), event.pos().y(), global_pos.x(), global_pos.y())
self.update()
'''重新实现鼠标双击事件'''
def mouseDoubleClickEvent(self, event):
self.justDoubleClicked = True
self.text = "你双击了鼠标"
self.update()
'''重新实现键盘按下事件'''
def keyPressEvent(self, event):
self.key = ""
if event.key() == Qt.Key_Home:
self.key = "Home"
elif event.key() == Qt.Key_End:
self.key = "End"
elif event.key() == Qt.Key_PageUp:
if event.modifiers() & Qt.ControlModifier:
self.key = "Ctrl+PageUp"
else:
self.key = "PageUp"
elif event.key() == Qt.Key_PageDown:
if event.modifiers() & Qt.ControlModifier:
self.key = "Ctrl+PageDown"
else:
self.key = "PageDown"
elif Qt.Key_A <= event.key() <= Qt.Key_Z:
if event.modifiers() & Qt.ShiftModifier:
self.key = "Shift+"
self.key += event.text()
# 如果key有字符,不为空,则绘制字符
if self.key:
self.key = self.key
self.update()
# 否则就继续监视这个事件
else:
QWidget.keyPressEvent(self, event)
'''重新实现其他事件,适用于PyQt没有提供该事件的处理函数的情况,Tab键由于涉及焦点切换,不会传递给keyPressEvent,因此,需要在这里重新定义。'''
def event(self, event):
# 如果有按键按下,并且按键是tab键
if (event.type() == QEvent.KeyPress and
event.key() == Qt.Key_Tab):
self.key = "在event()中捕获Tab键"
self.update()
return True
return QWidget.event(self, event)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = Widget()
form.show()
app.exec()
示例 2:过滤器的使用
下面的代码意思是这个过滤器只对 label1 的事件进行处理,并且只处理它的鼠标按下事件和鼠标释放事件
import sys
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class EventFilter(QDialog):
def __init__(self, parent=None):
super(EventFilter, self).__init__(parent)
self.setWindowTitle('事件过滤器')
# 实例化并设置四个标签文本
self.label1 = QLabel('请点击')
self.label2 = QLabel('请点击')
self.label3 = QLabel('请点击')
self.labelState = QLabel('test')
# 加载三个图片
self.image1 = QImage('images\cartoon1.ico')
self.image2 = QImage('images\cartoon2.ico')
self.image3 = QImage('images\cartoon3.ico')
self.width = 600
self.height = 300
# 设置初始大小
self.resize(self.width, self.height)
# 使用事假过滤器
self.label1.installEventFilter(self)
self.label2.installEventFilter(self)
self.label3.installEventFilter(self)
# 设置窗口布局方式并添加控件
layout = QGridLayout(self)
layout.addWidget(self.label1, 500, 0)
layout.addWidget(self.label2, 500, 1)
layout.addWidget(self.label3, 500, 2)
layout.addWidget(self.labelState, 600, 1)
def eventFilter(self, watched, event):
# 对事件一的处理过滤机制
if watched == self.label1:
if event.type() == QEvent.MouseButtonPress:
mouseEvent = QMouseEvent(event)
if mouseEvent.buttons() == Qt.LeftButton:
self.labelState.setText('按下鼠标左键')
elif mouseEvent.buttons() == Qt.MidButton:
self.labelState.setText('按下鼠标中间键')
elif mouseEvent.buttons() == Qt.RightButton:
self.labelState.setText('按下鼠标右键')
# 转换图片大小
transform = QTransform()
transform.scale(0.5, 0.5)
tmp = self.image1.transformed(transform)
self.label1.setPixmap(QPixmap.fromImage(tmp))
if event.type() == QEvent.MouseButtonRelease:
self.labelState.setText('释放鼠标按键')
self.label1.setPixmap(QPixmap.fromImage(self.image1))
return QDialog.eventFilter(self, watched, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = EventFilter()
app.installEventFilter(dialog)
dialog.show()
app.exec()
边栏推荐
- Cost accounting [23]
- 入门C语言基础问答
- E. Breaking the Wall
- Indonesian medical sensor Industry Research Report - market status analysis and development prospect forecast
- China chart recorder market trend report, technology dynamic innovation and market forecast
- Perform general operations on iptables
- Accounting regulations and professional ethics [2]
- 【练习-7】Crossword Answers
- Accounting regulations and professional ethics [3]
- Shell脚本编程
猜你喜欢
MATLAB综合练习:信号与系统中的应用
Optimization method of path problem before dynamic planning
Gartner:关于零信任网络访问最佳实践的五个建议
Record of force deduction and question brushing
信息安全-威胁检测-flink广播流BroadcastState双流合并应用在过滤安全日志
Nodejs+vue网上鲜花店销售信息系统express+mysql
渗透测试 ( 2 ) --- 渗透测试系统、靶机、GoogleHacking、kali工具
Penetration testing (5) -- a collection of practical skills of scanning King nmap and penetration testing tools
[analysis of teacher Gao's software needs] collection of exercises and answers for level 20 cloud class
1010 things that college students majoring in it must do before graduation
随机推荐
【练习-6】(Uva 725)Division(除法)== 暴力
Research Report on market supply and demand and strategy of Chinese graphic screen printing equipment industry
Learning record: USART serial communication
Opencv learning log 18 Canny operator
渗透测试 ( 2 ) --- 渗透测试系统、靶机、GoogleHacking、kali工具
【练习-11】4 Values whose Sum is 0(和为0的4个值)
Research Report on market supply and demand and strategy of China's Medical Automation Industry
CEP used by Flink
【练习-3】(Uva 442)Matrix Chain Multiplication(矩阵链乘)
Flink 使用之 CEP
渗透测试 ( 1 ) --- 必备 工具、导航
编程到底难在哪里?
cs零基础入门学习记录
Research Report of cylindrical grinder industry - market status analysis and development prospect forecast
Learning record: use stm32f1 watchdog
【练习-7】(Uva 10976)Fractions Again?!(分数拆分)
Optimization method of path problem before dynamic planning
C语言学习笔记
Learning records: serial communication and solutions to errors encountered
基于web的照片数码冲印网站