zoukankan      html  css  js  c++  java
  • [Python自学] PyQT5-子线程更新UI数据、信号槽自动绑定、lambda传参、partial传参、覆盖槽函数

    一、子线程中更新UI数据

    当我们要持续的更新主线程UI中控件的数据时,可能会导致主窗口阻塞(未响应),这是就需要用子线程将数据传递给主线程,并调用槽函数来更新控件显示数据。

    import sys
    import time
    
    # 导入QT,其中包含一些常量,例如颜色等
    from PyQt5.QtCore import Qt, QThread, pyqtSignal, QDateTime
    # 导入常用组件
    from PyQt5.QtWidgets import QApplication, QMainWindow
    from PyQt5.QtWidgets import QLineEdit
    # 使用调色板等
    from PyQt5.QtGui import QIcon
    
    
    # 创建一个子线程
    class UpdateThread(QThread):
        # 创建一个信号,触发时传递当前时间给槽函数
        update_data = pyqtSignal(str)
    
        def run(self):
            # 无限循环,每秒钟传递一次时间给UI
            while True:
                data = QDateTime.currentDateTime()
                currentTime = data.toString("yyyy-MM-dd hh:mm:ss")
                self.update_data.emit(str(currentTime))
                time.sleep(1)
    
    
    class DemoWin(QMainWindow):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.resize(400, 100)
            self.lineEdit = QLineEdit(self)
            self.lineEdit.resize(400, 100)
    
            # 创建子线程
            self.subThread = UpdateThread()
            # 将子线程中的信号与timeUpdate槽函数绑定
            self.subThread.update_data.connect(self.timeUpdate)
            # 启动子线程(开始更新时间)
            self.subThread.start()
    
            # 添加窗口标题
            self.setWindowTitle("SubThreadDemo")
    
        # 被子线程的信号触发,更新一次时间
        def timeUpdate(self, data):
            self.lineEdit.setText(data)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        app.setWindowIcon(QIcon("images/icon.ico"))
        # 创建一个主窗口
        mainWin = DemoWin()
        # 显示
        mainWin.show()
        # 主循环
        sys.exit(app.exec_())

    在上述代码中,我们启动了一个子线程来循环发送信号,触发信号绑定的槽函数(位于主线程),每次触发都将需要显示的时间数据传递到主线程,并更新到lineEdit控件中。

    实现效果:

    二、信号和槽函数的自动绑定

    我们使用槽函数装饰器,以及控件对象名可以实现信号和槽函数的自动绑定。

    import sys
    
    # 导入QT,其中包含一些常量,例如颜色等
    from PyQt5.QtCore import Qt
    from PyQt5 import QtCore
    # 导入常用组件
    from PyQt5.QtWidgets import QApplication, QWidget
    from PyQt5.QtWidgets import QVBoxLayout
    from PyQt5.QtWidgets import QPushButton, QLabel
    
    # 使用调色板等
    from PyQt5.QtGui import QIcon
    
    
    class DemoWin(QWidget):
        def __init__(self):
            super(DemoWin, self).__init__()
            self.initUI()
    
        def initUI(self):
            self.resize(400, 200)
            self.okButton = QPushButton("OK", self)
            # 给okButton指定一个ObjectName
            self.okButton.setObjectName("okButton")
            self.cancelButton = QPushButton("Cancel", self)
            # 给cancelButton指定一个ObjectName
            self.cancelButton.setObjectName("cancelButton")
    
            self.displayLabel = QLabel()
            layout = QVBoxLayout()
            layout.addWidget(self.okButton)
            layout.addWidget(self.cancelButton)
            layout.addWidget(self.displayLabel)
            self.setLayout(layout)
            # 设置自动信号槽绑定(通过控件对象名称来查找对应的槽函数)
            QtCore.QMetaObject.connectSlotsByName(self)
    
            # 添加窗口标题
            self.setWindowTitle("AutoDemo")
    
        @QtCore.pyqtSlot()  # 将这个函数指定为槽函数
        def on_okButton_clicked(self):
            print("okButton被点击")
            self.displayLabel.setText("okButton被点击")
    
        @QtCore.pyqtSlot()  # 将这个函数指定为槽函数
        def on_cancelButton_clicked(self):
            print("cancelButton被点击")
            self.displayLabel.setText("cancelButton被点击")
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        app.setWindowIcon(QIcon("images/icon.ico"))
        # 创建一个主窗口
        mainWin = DemoWin()
        # 显示
        mainWin.show()
        # 主循环
        sys.exit(app.exec_())

    注意,我们这里使用的是根据ObjectName来查找槽函数,并自动绑定。这种方式的槽函数名必须满足以下规律:

    on_ObjectName_SignalName

    ObjectName即我们给控件设置的objectname,SignalName就是事件名,例如clicked,triggled等。

    实现效果:

    三、通过lambda表达式给槽函数传递参数

    当我们在使用系统默认提供的事件时(例如按钮的clicked事件),他默认是不带参数的,也就是说用connect直接绑定,只能绑定不接受参数的槽函数。

    但是我们有时候需要绑定带参数的槽函数,这时就可以使用lambda表达式将槽函数包装一下。

    import sys
    
    # 导入QT,其中包含一些常量,例如颜色等
    from PyQt5.QtCore import Qt
    # 导入常用组件
    from PyQt5.QtWidgets import QApplication, QWidget
    from PyQt5.QtWidgets import QVBoxLayout
    from PyQt5.QtWidgets import QPushButton, QLabel
    
    # 使用调色板等
    from PyQt5.QtGui import QIcon
    
    
    class DemoWin(QWidget):
        def __init__(self):
            super(DemoWin, self).__init__()
            self.initUI()
    
        def initUI(self):
            self.resize(400, 100)
            self.okButton = QPushButton("OK", self)
            # 使用lambda表达式进行参数传递,即将槽函数封装为一个匿名的无参数函数给信号绑定
            self.okButton.clicked.connect(lambda: self.on_okButton_clicked(20, 50))
    
            self.displayLabel = QLabel()
            self.displayLabel.setAlignment(Qt.AlignCenter)
            layout = QVBoxLayout()
            layout.addWidget(self.okButton)
            layout.addWidget(self.displayLabel)
            self.setLayout(layout)
            # 添加窗口标题
            self.setWindowTitle("LambdaDemo")
    
        def on_okButton_clicked(self, x, y):
            self.displayLabel.setText("x+y = " + str(x + y))
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        app.setWindowIcon(QIcon("images/icon.ico"))
        # 创建一个主窗口
        mainWin = DemoWin()
        # 显示
        mainWin.show()
        # 主循环
        sys.exit(app.exec_())

    实现效果:

    四、通过partial偏函数为槽函数传参数

    import sys
    
    # 导入QT,其中包含一些常量,例如颜色等
    from PyQt5.QtCore import Qt
    # 导入常用组件
    from PyQt5.QtWidgets import QApplication, QWidget
    from PyQt5.QtWidgets import QVBoxLayout
    from PyQt5.QtWidgets import QPushButton, QLabel
    
    # 使用调色板等
    from PyQt5.QtGui import QIcon
    
    from functools import partial
    
    
    class DemoWin(QWidget):
        def __init__(self):
            super(DemoWin, self).__init__()
            self.initUI()
    
        def initUI(self):
            self.resize(400, 100)
            self.okButton = QPushButton("OK", self)
            # 使用functools提供的partial偏函数来传递参数
            self.okButton.clicked.connect(partial(self.on_okButton_clicked, 20, 50))
    
            self.displayLabel = QLabel()
            self.displayLabel.setAlignment(Qt.AlignCenter)
            layout = QVBoxLayout()
            layout.addWidget(self.okButton)
            layout.addWidget(self.displayLabel)
            self.setLayout(layout)
            # 添加窗口标题
            self.setWindowTitle("LambdaDemo")
    
        def on_okButton_clicked(self, x, y):
            self.displayLabel.setText("x+y = " + str(x + y))
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        app.setWindowIcon(QIcon("images/icon.ico"))
        # 创建一个主窗口
        mainWin = DemoWin()
        # 显示
        mainWin.show()
        # 主循环
        sys.exit(app.exec_())

    用法基本和Lambda差不多,也就起到将槽函数封装的效果。封装后,信号所直接绑定的函数是没有参数的。

    五、覆盖(override)槽函数 

    由于QT为我们提供了很多默认的槽函数(默认操作),我们可以通过重写槽函数将其默认操作进行覆盖。

    Demo:

    class DemoWin(QWidget):
        def __init__(self):
            super(DemoWin, self).__init__()
            self.initUI()
    
        def initUI(self):
            # 添加窗口标题
            self.setWindowTitle("OverrideDemo")
    
        def keyPressEvent(self, a0: QtGui.QKeyEvent) -> None:
            if a0.key() == Qt.Key_Escape:
                self.close()
            elif a0.key() == Qt.Key_Alt:
                self.setWindowTitle("按下了Alt键")

    我们通过覆盖keyPressEvent槽函数修改了按ESC和ALT键的行为。当我们按ESC的时候,窗口关闭,当按ALT键的时候窗口标题修改为"按下了Alt键"。

    ====

  • 相关阅读:
    记录
    集合
    数据库一键退出脚本
    修改NLS_DATE_FORMAT的四种方式
    触发器
    (转)rlwrap真是一个好东西
    Windows常用技巧集锦
    UTL_FILE
    redis入门(03)redis的配置
    服务网关
  • 原文地址:https://www.cnblogs.com/leokale-zz/p/13131953.html
Copyright © 2011-2022 走看看