• PyQt5(四) 线程与绘图处理


    线程与绘图处理

    参考文章:https://blog.csdn.net/liming89/article/details/109576602

    引出问题:

    import sys
    import time
    
    from PyQt5.QtWidgets import QMainWindow,QWidget,QApplication,QMessageBox
    from PyQt5.uic import loadUi
    
    class DemoWin():
        def __init__(self):
            self.ui=loadUi("../ui/task.ui")
            self.ui.button1.clicked.connect(self.clicked_one)
            self.ui.button2.clicked.connect(self.clicked_two)
        def clicked_one(self):
            print("Hello world...")
            time.sleep(10)
        def clicked_two(self):
            print("开始执行。。")
            QMessageBox.information(self.ui,"提示","哈哈哈")
    if __name__ == '__main__':
        app=QApplication(sys.argv)
        obj=DemoWin()
        obj.ui.show()
        sys.exit(app.exec_())
    

    image-20220424100856541

    问题:假设当操作一十分耗时的时候,剩下的加界面会卡住,无法操作,因此在使用的时候需要进行异步的设置。

    1.界面阻塞

    上述问题的原因是因为,我们的代码都是在主线程中执行的。

     sys.exit(app.exec_())
     # app.exec_() 其实会让主线程进入一个死循环,循环不断处理用户的操作事件
    

    当我们点击发送按钮后,Qt 的核心代码就会收到这个点击事件,并调用相关的Slot 函数去处理。

    self.ui.button1.clicked.connect(self.clicked_one)
    

    如果 clicked_one很快能接收到响应,那么 clicked_one 就可以很快返回,返回后, 整个程序又进入到 app.exec_() 里面接收各种 事件,并且调用相应的函数去处理。界面就不会僵死,因为所有的操作界面的事件,都能得到及时的处理。

    但是,如果这个clicked_one要很长时间才能返回,这段时间内,整个程序就停在 下面这行代码处

    time.sleep(10)
    

    自然就没有机会去处理其他的用户操作界面的事件了,当然程序就僵死了。

    2.多线程处理

    使用Python的原生线程进行操作,适当的时候可以使用函数的嵌套,闭包 进行参数的封装。

    import sys
    import time
    from threading import Thread
    
    from PyQt5.QtWidgets import QMainWindow,QWidget,QApplication,QMessageBox
    from PyQt5.uic import loadUi
    
    class DemoWin():
        def __init__(self):
            self.ui=loadUi("../ui/task.ui")
            self.ui.button1.clicked.connect(self.clicked_one)
            self.ui.button2.clicked.connect(self.clicked_two)
        def clicked_one(self):
            print("Hello world...")
            thread=Thread(target=self.run_task,args=(10,))
            thread.start()# 设置线程为供cpu调度的状态
            print("run success !!!")
        def run_task(self,t):
            time.sleep(t)
            print("异步任务执行完整")
        def clicked_two(self):
            print("开始执行。。")
            QMessageBox.information(self.ui,"提示","哈哈哈")
    if __name__ == '__main__':
        app=QApplication(sys.argv)
        obj=DemoWin()
        obj.ui.show()
        sys.exit(app.exec_())
    

    image-20220424102837759

    • 补充:子线程发信号更新界面,请参考:https://www.byhy.net/tut/py/gui/qt_08/

    3.绘制图形

    参考文章:https://blog.csdn.net/wuwei_201/article/details/106106387

    import sys
    
    from PyQt5.QtWidgets import QApplication,QMainWindow,QWidget
    from PyQt5 import QtWidgets
    from PyQt5 import QtCore
    import numpy as np
    
    import matplotlib
    matplotlib.use("Qt5Agg")  # 声明使用pyqt5
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg  # pyqt5的画布
    import matplotlib.pyplot as plt
    # matplotlib.figure 模块提供了顶层的Artist(图中的所有可见元素都是Artist的子类),它包含了所有的plot元素
    from matplotlib.figure import Figure
    class MyMatplotlibFigure(FigureCanvasQTAgg):
        """
        创建一个画布类,并把画布放到FigureCanvasQTAgg
        """
        def __init__(self, width=10, heigh=10, dpi=100):
            plt.rcParams['figure.facecolor'] = 'r'  # 设置窗体颜色
            plt.rcParams['axes.facecolor'] = 'b'  # 设置绘图区颜色
            # 创建一个Figure,该Figure为matplotlib下的Figure,不是matplotlib.pyplot下面的Figure
            self.figs = Figure(figsize=(width, heigh), dpi=dpi)
            super(MyMatplotlibFigure, self).__init__(self.figs)  # 在父类种激活self.fig,
            self.axes = self.figs.add_subplot(111)  # 添加绘图区
        def mat_plot_drow_axes(self, t, s):
            """
            用清除画布刷新的方法绘图
            :return:
            """
            self.axes.cla()  # 清除绘图区
    
            self.axes.spines['top'].set_visible(False)  # 顶边界不可见
            self.axes.spines['right'].set_visible(False)  # 右边界不可见
            # 设置左、下边界在(0,0)处相交
            # self.axes.spines['bottom'].set_position(('data', 0))  # 设置y轴线原点数据为 0
            self.axes.spines['left'].set_position(('data', 0))  # 设置x轴线原点数据为 0
            self.axes.plot(t, s, 'o-r', linewidth=0.5)
            self.figs.canvas.draw()  # 这里注意是画布重绘,self.figs.canvas
            self.figs.canvas.flush_events()  # 画布刷新self.figs.canvas
    
    class MainDialogImgBW_(QtWidgets.QMainWindow):
        """
        创建UI主窗口,使用画板类绘图。
        """
        def __init__(self):
            super(MainDialogImgBW_, self).__init__()
            self.setWindowTitle("显示matplotlib")
            self.setObjectName("widget")
            self.resize(800, 600)
            self.label = QtWidgets.QLabel(self)
            self.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
            self.canvas = MyMatplotlibFigure(width=5, heigh=4, dpi=100)
            self.plotcos()
            self.hboxlayout = QtWidgets.QHBoxLayout(self.label)
            self.hboxlayout.addWidget(self.canvas)
    
        def plotcos(self):
            # plt.clf()
            t = np.arange(0.0, 5.0, 0.01)
            s = np.cos(2 * np.pi * t)
            # self.canvas.aexs.plot(t, s)
            self.canvas.mat_plot_drow_axes(t, s)
            self.canvas.figs.suptitle("sin")  # 设置标题
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        main = MainDialogImgBW_()
        main.show()
        sys.exit(app.exec_())
    
    

    创建画布类继承FigureCanvasQTAgg,主窗口中添加上实例化,画图控件self.canvas,绘制上对应数据即可。

  • 相关阅读:
    个人项目-小学四则运算 “软件”之初版
    分布式版本控制系统Git的安装与使用
    第一次作业-准备
    结对项目-四则运算 “软件”之升级版
    第三次作业:个人项目-小学四则运算 “软件”之初版
    分布式版本控制系统Git的安装与使用
    第一次作业:准备
    结对项目-四则运算 “软件”之升级版
    个人项目-小学四则运算 “软件”之初版
    分布式版本控制系统Git的安装与使用
  • 原文地址:https://www.cnblogs.com/Blogwj123/p/16185420.html
Copyright © 2020-2023  润新知