详解PyQt5 GUI 接收UDP数据并动态绘图的过程(多线程间信号传递)

目录
  • 1. Qt 的用法
  • 2. Pycharm 设置
    • 2.1 安装 Pyqt5 和 pyinstaller 包
    • 2.2 Pycharm pyqt工具配置
  • 3 UDP图形界面设计
    • 3.1 GUI设计
    • 3.2 将GUI文件转换为py文件
    • 3.3 widget窗体提升,整合matplotlib的功能
    • 3.4 GUI 设计结果
  • 4 多线程编程UDP通讯
    • 4.1 信号和槽函数
    • 4.2 多线程
  • 5 Pyinstaller 打包成exe

1. Qt 的用法

  pyqt5是qt的python版本,其主要是以对象的形式存在的,在编程的过程中无法可视化,带来诸多的不便。为了简化pyqt5的界面设计环节,我们可以使用qt中的设计器Qt Designer (C:\Qt\5.12.11\mingw73_32\bin\designer.exe)来设计图形界面,生成的图形界面通常保存在*.ui后缀的文件中。

 pyqt5可以直接调用.ui文件,也可以通过pyqt5自带的pyuic.exe将设计好的.ui文件转换为.py格式的pyqt5类,供其他模块调用。

 Qt 的安装教程在CSDN论坛上有很多,在此不再赘述了,建议使用 Qt5, 高版本的Qt6目前还没有被 matplotlib 纳入后端支持。

2. Pycharm 设置

 首先安利一波,Pycharm在代码颜色主题、功能界面、python环境切换、打开终端、jupyter notebook支持、变量查看、Markdown支持、console多开等方面具有较高的便利性,因此本人主要使用pychrm 进行相关代码的开发,推荐使用。

2.1 安装 Pyqt5 和 pyinstaller 包

 在pycharm底部打开终端,并输入如下代码安装pyqt5包和pyinstaller包。Pyinstaller包是用来将pyqt5GUI设计打包成exe可执行文件的工具,有了这个工具,就可以将程序拷贝到其他windows电脑上使用。

pip install pyqt5,pyinstaller

 后续还需要安装matplotlib包,按照类似的方式进行安装,不再赘述。在安装了pyqt5后,matplotlib会自动以pyqt5为后端,绘制出来的图像效果更好,所带的工具栏也更加实用,推荐日常使用。

2.2 Pycharm pyqt工具配置

 在使用Qt进行界面设计时,可以在pycharm中将Qt软件自带的几个工具都配置为外部工具(这就是pycharm众多优点之一),方便随时调用。pycharm中以及点击文件-设置-工具-外部工具(英文版自行对照)即可进入外部工具添加界面。

Qt Designer 工具(设计Qt 界面)

程序路径:

C:\Qt\5.12.11\mingw73_32\bin\designer.exe

工作目录:

$ProjectFileDir$

Qt Creator 工具(设计Qt 界面)

 程序路径在对应环境的Script目录下:

C:\Anaconda3\envs\tensor37\Scripts\pyuic5.exe

 参数设置如下:

$FileName$ -o $FileNameWithoutExtension$.py

 工作目录:

$ProjectFileDir$

PyUI 工具(Qt UI界面转为python代码)

 程序路径:

C:\Qt\Tools\QtCreator\bin\qtcreator.exe

 工作目录:

$ProjectFileDir$

 完成上述设置后在右键菜单中可以打开designer.exe和creator.exe这两个GUI设计应用,选中.ui文件右键运行pyuic.exe则会生成同名的.py文件,文件中包含有能够产生相同GUI的pyqt5类。

3 UDP图形界面设计

3.1 GUI设计

 在pycharm的空白处右键选择外部工具,打开designer,新建Main Window窗体。

 根据需要,我设计了一个UDP网络编程的界面,主要功能是接收UDP客户端发来的正弦数据,保存数据到txt文件中并将其绘制在底部的widget (窗体部件)中。

 目标运行界面如下:

3.2 将GUI文件转换为py文件

 设计好界面后,保存得到widget_recev.ui图形文件,在左侧的项目资源管理器中可以选中ui文件右键实用外部pyuic工具将其转换为widget_recev.py文件,供程序调用。这个操作在后续的调试中经常会用到,随时改动GUI随时生成新的py文件。新建的py文件会覆盖原来的内容,所以建议另建其他python模块调用该模块,避免信息丢失。

3.3 widget窗体提升,整合matplotlib的功能

 这里需要注意的是,matplotlib中的FigureCanvas和GUI中的widget都是Qwidget的子类,matplotlib是无法直接在widget中绘图的,需要在Designer中将widget提升为Qwidget类。选中GUI中的widget右键选择提升窗口部件,选择Qwidget,给提升的类取一个好记的名字,在这里我使用的是mplwidget。

 生成的widget_recev.py最后面会生成一句:

from mplwidget import mplwidget

 将其放在类文件的开头,否则会报错。

 mplwidget.py 模块需要自己构建,在对应的路径下自己建一个mplwidget.py文件,主要功能是创建一个同时继承了FigureCanvas与QWidget的类,按照上面预定义的,将其命名为mplwidget类。该操作使原来的widget窗体具有了matplotlib画布功能,可以在上面绘图了。mplwidget.py文件的内容如下:

# _*_coding: UTF-8_*_
# 开发作者 :TXH
# 开发时间 :2021-09-05 14:42
# 文件名称 :mplwidget.py
# 开发工具 :Python 3.7 + Pycharm IDE

from PyQt5 import QtGui,QtWidgets
from matplotlib.backends.backend_qt5agg \
 import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5.QtCore import QThread

class MplCanvas(FigureCanvas,QThread):
    def __init__(self):
        self.fig = Figure()
        FigureCanvas.__init__(self, self.fig)
        FigureCanvas.setSizePolicy(self,
        QtWidgets.QSizePolicy.Expanding,
        QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

class mplwidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.canvas = MplCanvas()
        self.vbl = QtWidgets.QVBoxLayout()
        self.vbl.addWidget(self.canvas)
        self.setLayout(self.vbl)

3.4 GUI 设计结果

 生成的pyqt5 UI(widget_recev.py)内容如下。该文件是根据Qt ui文件自动生成的,因此一般只需要知道里面有哪些部件即可,对于一些大小、位置设置的细节可以不用关注,因为已经在GUI设计的时候做好了。

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt_Learning.UDP.GUI.mplwidget import mplwidget  # 根据mplwidget 的位置改动

class Ui_Widget(object):
    def setupUi(self, Widget):
        Widget.setObjectName("Widget")
        Widget.resize(280, 165)
        self.label_2 = QtWidgets.QLabel(Widget)
        self.label_2.setGeometry(QtCore.QRect(110, 10, 55, 16))
        self.label_2.setObjectName("label_2")
        self.lineEdit_2 = QtWidgets.QLineEdit(Widget)
        self.lineEdit_2.setGeometry(QtCore.QRect(110, 30, 61, 21))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.pushButton = QtWidgets.QPushButton(Widget)
        self.pushButton.setGeometry(QtCore.QRect(10, 120, 71, 24))
        self.pushButton.setObjectName("pushButton")
        self.label = QtWidgets.QLabel(Widget)
        self.label.setGeometry(QtCore.QRect(12, 10, 55, 16))
        self.label.setObjectName("label")
        self.lineEdit = QtWidgets.QLineEdit(Widget)
        self.lineEdit.setGeometry(QtCore.QRect(12, 30, 81, 21))
        self.lineEdit.setObjectName("lineEdit")
        self.pushButton_2 = QtWidgets.QPushButton(Widget)
        self.pushButton_2.setGeometry(QtCore.QRect(180, 120, 75, 24))
        self.pushButton_2.setObjectName("pushButton_2")
        self.lineEdit_5 = QtWidgets.QLineEdit(Widget)
        self.lineEdit_5.setGeometry(QtCore.QRect(190, 80, 61, 21))
        self.lineEdit_5.setObjectName("lineEdit_5")
        self.label_3 = QtWidgets.QLabel(Widget)
        self.label_3.setGeometry(QtCore.QRect(190, 60, 71, 16))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(Widget)
        self.label_4.setGeometry(QtCore.QRect(10, 60, 71, 16))
        self.label_4.setObjectName("label_4")
        self.lineEdit_3 = QtWidgets.QLineEdit(Widget)
        self.lineEdit_3.setGeometry(QtCore.QRect(10, 80, 51, 21))
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.label_5 = QtWidgets.QLabel(Widget)
        self.label_5.setGeometry(QtCore.QRect(110, 60, 71, 16))
        self.label_5.setObjectName("label_5")
        self.lineEdit_4 = QtWidgets.QLineEdit(Widget)
        self.lineEdit_4.setGeometry(QtCore.QRect(110, 80, 51, 21))
        self.lineEdit_4.setObjectName("lineEdit_4")
        self.label_6 = QtWidgets.QLabel(Widget)
        self.label_6.setGeometry(QtCore.QRect(70, 80, 21, 16))
        self.label_6.setObjectName("label_6")

        self.retranslateUi(Widget)
        QtCore.QMetaObject.connectSlotsByName(Widget)

    def retranslateUi(self, Widget):
        _translate = QtCore.QCoreApplication.translate
        Widget.setWindowTitle(_translate("Widget", "数据发送端"))
        self.label_2.setText(_translate("Widget", "端口"))
        self.lineEdit_2.setText(_translate("Widget", "9999"))
        self.pushButton.setText(_translate("Widget", "发送正弦"))
        self.label.setText(_translate("Widget", "IP地址"))
        self.lineEdit.setText(_translate("Widget", "127.0.0.1"))
        self.pushButton_2.setText(_translate("Widget", "停止发送"))
        self.lineEdit_5.setText(_translate("Widget", "8"))
        self.label_3.setText(_translate("Widget", "正弦通道数"))
        self.label_4.setText(_translate("Widget", "正弦频率"))
        self.lineEdit_3.setText(_translate("Widget", "50"))
        self.label_5.setText(_translate("Widget", "正弦幅度"))
        self.lineEdit_4.setText(_translate("Widget", "1"))
        self.label_6.setText(_translate("Widget", "Hz"))

4 多线程编程UDP通讯

 使用Qt进行界面设计非常方便。pyqt编程的难点在于底层的信号-槽函数机制以及多线程编程。先抛开多线程UDP编程,简单举例讲一下信号-槽函数的原理。

4.1 信号和槽函数

 信号相当于是GUI主循环中的事件,一旦触发某个事件,对应的槽函数(对象方法)将会运行。

 信号可以是内建信号,也可以是自定义信号。内建信号一般直接跟部件相关联,可以根据一定的规则构建对应的槽函数,例如:

def on_pushButtom_clicked(self):
    ...
def on_pushButtom_2_clicked(self):
    ...
def on_pushButtom_3_clicked(self):
    ...

分别对应着pushButtom,pushButtom_2,pushButtom_3 三个按钮被触发 clicked()事件时的自动关联槽函数,事件触发后立即运行对应的槽函数。类似的,checkBox_5被触发则默认自动关联如下槽函数,传递chencked 布尔信号:

def on_checkBox_5_toggled(self,checked):
    ...

 自定义信号则更加灵活,其在事件触发时通过emit()函数发送数据。在pyqt5中,信号发送的数据类型可以是python支持的任何类型, 目前的测试表明,numpy.array、list、str、int、float等数据类型可以通过信号传递给槽函数,作为槽函数的输入。

在主线程(或GUI主循环)内,自定义简单的信号和槽函数对如下。

from PyQt5.QtCore import QObject
from PyQt5 import QtCore

class Test(QObject):
    test_signal = QtCore.pyqtSignal(list)  # 定义test_signal 信号
    def __init__(self, parent=None):
        super().__init__(parent)
        self.test_signal.connect(self.print_data)  # 将信号与test槽函数关联

    def toggle(self):
        a = list([1, 2, 3, 4, 5])
        self.test_signal.emit(a)  # 向槽函数发送信号

    @QtCore.pyqtSlot(list)
    def print_data(self, list_var):  # 定义槽函数
        # 槽函数一旦接收到test_signal 发送的数据,立即执行后续内容
        print(list_var) 

test = Test()
test.toggle()

>>> [1, 2, 3, 4, 5]

 信号一般在初始化方法之前定义,作为Qt类的成员,定义信号时给出所发送信号的数据类型,以下例子中使用的是list类型。在初始化时将信号与对应的槽函数相关联。然后根据需要在不同的方法中发送信号给槽函数,槽函数接收到数据后立即执行函数中的内容。以上例子较为简单,主要在主线线程内进行信号和槽函数的触发。后文中将给出多线程进行信号和槽函数传递数据的案例。

4.2 多线程

 pyqt的主界面使用的是主线程,可以看做是一个死循环。一旦主线程中产生了较为耗时的操作,将导致主线程出现假死的现象,体现在GUI界面就是无响应和无法进行任何操作。

 在进行GUI程序设计时一般遵循GUI界面和代码界面分开设计的原则,主线程只负责管理基本GUI的动作,而耗时的操作则通过子线程进行计算。

 回到“多线程UDP通讯”的主题,在创建好GUI的基础上,UDP通讯接收端的主函数如下。代码实现了主线程向子线程、子线程向子线程以及子线程向主线程传递数据的三种情况。

当然,所有信号与槽函数的连接都必须在主线程中完成。
具体方法是:在主线程中创建子线程实例,将子线程作为主线程的成员,如此可以实现子线程与子线程,子线程与主线程之间的信号传递。

# _*_coding: UTF-8_*_
# 开发作者 :TXH
# 开发时间 :2021-08-26 18:24
# 文件名称 :Receiver.py
# 开发工具 :Python 3.7 + Pycharm IDE

import socket
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt_Learning.UDP.GUI.widget_recev import Ui_MainWindow
from PyQt5 import QtCore,uic
from PyQt5.QtCore import QThread,pyqtSlot

class QmyDialog(QMainWindow): # 主窗体本身占用一个主线程
    UDP_para = QtCore.pyqtSignal(list)
    sender_para = QtCore.pyqtSignal(list)
    def __init__(self, parent=None):
        super().__init__(parent)
        self.pause=False
        self.statusBar().showMessage('Load UI...')
        if 0:
            self.ui = uic.loadUi('E:/Pywork/PyQt_Learning/UDP/GUI/widget_recev.ui',self) #
        else:
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
        self.statusBar().showMessage('Init Canvas...')
        self.canvas = self.ui.widget.canvas # 绘图设置
        self.canvas.ax1 = self.canvas.fig.add_subplot(111)
        self.canvas.ax1.get_yaxis().grid(True)

        self.statusBar().showMessage('Init UDP...') # 状态栏更新
        self.UDP = UDPThread(self.para(1)) # 创建子线程1
        self.UDP_para.connect(self.UDP.UDP_para_update) # 主线程向UDP线程传递参数

        self.statusBar().showMessage('Init plot sender...')
        self.Plot_fig = Plot_Thread(self.para(2)) # 创建子线程2
        self.UDP.send_data.connect(self.Plot_fig.send) # UDP子线程向绘图子线程发送数据
        self.sender_para.connect(self.Plot_fig.Sender_para_update) # 主线程向绘图子线程传递参数
        self.Plot_fig.plot_data.connect(self.plot_fig) # 绘图子线程将数据发给主线程plot_fig函数,让其绘图
        self.statusBar().showMessage('Ready!')

    def on_pushButton_clicked(self):  # 设置参数
        self.update_udp_para()
        self.update_sender_para()
        self.statusBar().showMessage('Para changed...')

    def on_pushButton_2_clicked(self):  # 接收数据
        self.update_udp_para()
        self.update_sender_para()
        self.UDP.pause = False
        self.Plot_fig.pause=False
        self.UDP.start()
        self.ui.lineEdit.setReadOnly(True)
        self.ui.lineEdit_2.setReadOnly(True)
        self.Plot_fig.start()
        self.statusBar().showMessage('Receiving data...')

    def on_pushButton_3_clicked(self):  # 停止接收和绘图
        self.pause=True
        self.update_udp_para()
        self.update_sender_para()
        self.statusBar().showMessage('Receiving paused!')

    def plot_fig(self,temp): # 绘图函数,不计算,避免主线程阻塞,接收数据后立即绘图
        self.canvas.ax1.clear()
        self.canvas.ax1.plot(temp)
        self.canvas.fig.tight_layout()
        self.canvas.draw()

    def update_udp_para(self): # UPD子线程参数设置
        self.UDP_para.emit(self.para(1))

    def update_sender_para(self):# 绘图计算子线程参数设置
        self.sender_para.emit(self.para(2))

    def para(self,flag):
        if flag==1:
            return list([self.ui.lineEdit.text(),int(self.ui.lineEdit_2.text()),self.pause])
        else:
            return list([int(self.ui.lineEdit_3.text()),self.pause])

# 定义UDP 接收线程类
class UDPThread(QThread):
    send_data = QtCore.pyqtSignal(str)
    def __init__(self,udp_para_list):
        super().__init__()
        self.IP,self.Port,self.pause = udp_para_list
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 设置socket协议为UDP
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    def run(self) -> None: # 死循环接收UDP数据
        try:
            self.s.bind((self.IP, self.Port))
        except:pass
        i = 1
        with open('out.txt', 'w') as f: # 将获取的UDP数据保存到本地的txt中
            while True:
                temp = self.s.recv(1024).decode('utf-8')  # 接收 socket 数据
                if i%11==1:
                    self.send_data.emit(temp)
                f.writelines(temp + '\n')
                i=(i+1)%2000
                if self.pause: # 判断是否跳出循环
                    break

    def UDP_para_update(self,udp_para_list):
        self.Ip,self.Port,self.pause=udp_para_list

# 定义绘图计算子线程类
class Plot_Thread(QThread):
    plot_data = QtCore.pyqtSignal(list)
    def __init__(self,para_list):
        super().__init__()
        self.pause = False
        self.data = []
        self.max_len = para_list[0]
        self.i=1

    def change_Len(self,len): # 绘图长度设置
        if len<1000:
            self.max_len=1000
        else:
            self.max_len = len

    # 接收UDP接收子线程发来的数据,并转发给GUI中的绘图方法
    @pyqtSlot(str)
    def send(self,data):
        self.data.append(float(data))
        if len(self.data)>self.max_len:
            self.data=self.data[(len(self.data)-self.max_len):]
        self.i=(self.i+1)%(1000)
        if self.i==0:
            self.plot_data.emit(self.data)  # 每收到 1000个点将data数据发给GUI进行绘图

    def Sender_para_update(self,para_list): # 根据主线程的信号更新绘图长度
        self.max_len,self.pause=para_list

# if __name__ == "__main__":
app = QApplication(sys.argv)  # 调用父类构造函数,创建窗体
form = QmyDialog()  # 创建UI对象
form.show()  #
sys.exit(app.exec())  #

 效果显示如下:
点击记录并绘图,程序在保存UDP接收的数据的同时,将部分数据发送到GUI界面进行绘图。

5 Pyinstaller 打包成exe

 pyinstaller将代码打包成exe时会面临生成的exe过大的情况,一个很小功能的exe体积高达200M。归根到底是pyinstaller将一些相互关联的安装包都打包到exe中了,而大多数安装包在当前项目中并没有真正使用到。

经测试,可以使用pipenv 创建一个干净的虚拟环境,降低exe的大小。 环境中只安装需要的pyinstaller, pyqt5, numpy等即可。在虚拟环境下生成的pyqt5 exe可执行文件只有几十兆。

 想进一步压缩可以下载 upx.exe,将放入pipenv虚拟环境下的Script文件夹中,pyinstaller打包的时候会自动调用。压缩量小,但算是有点效果的,毕竟没有其他补救措施了。

 在pipenv虚拟环境下运行如下代码:

# Gen_EXE.py
import os
error = os.system('pyinstaller --clean -Fw E:\\Pywork\PyQt_Learning\\UDP\\GUI\\Receiver.py  E:\\Pywork\\PyQt_Learning\\UDP\\GUI\\widget_recev.py E:\\Pywork\\PyQt_Learning\\UDP\\GUI\\mplwidget.py') # 添加所有相关的py文件
if not error: print('成功生成exe文件!')

 最终的大小约为44M,个人感觉还行。

 写在最后:兴趣使然,水平有限,欢迎相互交流。

到此这篇关于PyQt5 GUI 接收UDP数据并动态绘图(多线程间信号传递)的文章就介绍到这了,更多相关PyQt5 GUI动态绘图内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • PyQt5中多线程模块QThread使用方法的实现

    本文主要讲解使用多线程模块QThread解决PyQt界面程序唉执行耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题.用户使用工具过程中出现这些问题时会误以为程序出错,从而把程序关闭.这样,导致工具的用户使用体验不好.下面我们通过模拟上述出现的问题并讲述使用多线程QThread模块解决此类问题的方法. PyQt程序卡顿和无法实时显示问题现象 使用PyQt界面程序,点击运行按钮后,程序在显示框中每秒打印1个数字.程序代码如下: # -*- coding: utf-8 -*- impor

  • Pyqt5 实现多线程文件搜索的案例

    我学Java的时候也用Swing做了一个文件搜索的小程序,但界面真的挺丑的,现在学了点python,感觉python是最简单的语言,没有之一. (大家没事都可以来学的,真的很简单有趣哦) 我采用的是pyqt5,所以需要先安装Pyqt5模块 直接cmd命令输入 pip install pyqt5 闲言少叙,上代码!! # -*- coding: utf-8 -*- # @Time : 2018\9\15 20:39 # @Author : Tang weiyang # @File : FileSe

  • python GUI库图形界面开发之PyQt5多线程中信号与槽的详细使用方法与实例

    PyQt5简单多线程信号与槽的使用 最简单的多线程使用方法是利用QThread函数,展示QThread函数和信号简单结合的方法 import sys from PyQt5.QtCore import * from PyQt5.QtWidgets import * class Main(QWidget): def __init__( self, parent=None ): super(Main, self).__init__(parent) #创建一个线程实例并设置名称 变量 信号与槽 self

  • python GUI库图形界面开发之PyQt5简单绘图板实例与代码分析

    在PyQt中常用的图像类有四种,QPixmap,QImage,QPicture,QBitmap 类型 描述 QPixmap 专门为绘图设计的,在绘制图片时需要使用QPixmap QImage 提供了一个与硬件无关的图像表示函数,可以用于图片像素级访问 QPicture 是一个绘图设备类,它继承自QPainter类,可以使用QPainter的begin()函数在QPicture上绘图,使用end()函数结束绘图,使用QPicture的save()函数将QPainter所使用的绘图指令保存在文件中

  • PyQt5多线程防卡死和多窗口用法的实现

    心得:写着写着找到了自己的感觉,还是需要大量的代码和项目来加深对代码的理解 一.PyQt5多线程防卡死 在界面中,通常用会有一些按钮,点击后触发事件,比如去下载一个文件或者做一些操作,这些操作会耗时,如果不能及时结束,主线程将会阻塞,这样界面就会出现未响应的状态,因此必须使用多线程来解决这个问题. # -*- coding: UTF-8 -*- """"================================================= @Projec

  • PYQT5开启多个线程和窗口,多线程与多窗口的交互实例

    每点击一次按钮,弹出一个对话框(子窗口),同时开启一个子线程来执行任务并更新对话框内容,关闭对话框则关闭对应子线程 1. 建立一个简单的主界面和一个自定义对话框 from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(327,

  • 详解PyQt5 GUI 接收UDP数据并动态绘图的过程(多线程间信号传递)

    目录 1. Qt 的用法 2. Pycharm 设置 2.1 安装 Pyqt5 和 pyinstaller 包 2.2 Pycharm pyqt工具配置 3 UDP图形界面设计 3.1 GUI设计 3.2 将GUI文件转换为py文件 3.3 widget窗体提升,整合matplotlib的功能 3.4 GUI 设计结果 4 多线程编程UDP通讯 4.1 信号和槽函数 4.2 多线程 5 Pyinstaller 打包成exe 1. Qt 的用法   pyqt5是qt的python版本,其主要是以对

  • 详解Python GUI编程之PyQt5入门到实战

    1. PyQt5基础 1.1 GUI编程学什么 大致了解你所选择的GUI库 基本的程序的结构:使用这个GUI库来运行你的GUI程序 各种控件的特性和如何使用 控件的样式 资源的加载 控件的布局 事件和信号 动画特效 界面跳转 设计工具的使用 1.2 PyQT是什么 QT是跨平台C++库的集合,它实现高级API来访问现代桌面和移动系统的许多方面.这些服务包括定位和定位服务.多媒体.NFC和蓝牙连接.基于Chromium的web浏览器以及传统的UI开发.PyQt5是Qt v5的一组完整的Python

  • 详解PyQt5信号与槽的几种高级玩法

    信号(Signal)和槽(Slot)是Qt中的核心机制,也是在PyQt编程中对象之间进行通信的机制.本文介绍了几种PyQt 5信号与槽的几级玩法. 在Qt中,每一个QObject对象和PyQt中所有继承自QWidget的控件(这些都是QObject的子对象)都支持信号与槽机制.当信号发射时,连接的槽函数将会自动执行.在PyQt 5中信号与槽通过object.signal.connect()方法连接. PyQt的窗口控件类中有很多内置信号,开发者也可以添加自定义信号.信号与槽具有如下特点. 一个信

  • 详解pyqt5的UI中嵌入matplotlib图形并实时刷新(挖坑和填坑)

    一.pyqt5的UI中嵌入matplotlib的方法 1.导入模块 导入模块比较简单,首先声明使用pyqt5,通过FigureCanvasQTAgg创建画布,可以将画布的图像显示到UI,相当于pyqt5的一个控件,后面的绘图就建立在这个画布上,然后把这个画布当中pyqt5的控件添加到pyqt5的UI上,其次要导入matplotlib.figure的Figure ,这里要注意的是matplotlib.figure中的Figure,不是matplotlib.pyplot模块中的Figure,要区分清

  • 详解PyQt5中textBrowser显示print语句输出的简单方法

    开发python程序处理大数据量的时候,少不了使用print语句看看输出结果:长时间处理数据时用print输出处理进展情况.使用PyQt5开发了UI界面后,本能地想让已自己调试好的py代码中的print输出到UI的textBrowser中显示出来.在CSDN上查了不少结果,一般都是使用多线程.我对多线程研究不多,就采用了变通办法,效果还挺好. 在Ui界面程序(Ui_startaml.py)中设置textBrowser用于显示程序输出信息,并自己定义代码(def printf ),以后将.py程序

  • SpringBoot开发详解之Controller接收参数及参数校验

    目录 Controller 中注解使用 传输参数的几种Method 获取参数的几种常用注解 使用对象直接获取参数 使用@Valid对参数进行校验 总结 Controller 中注解使用 接受参数的几种传输方式以及几种注解: 在上一篇中,我们使用了JDBC链接数据库,完成了简单的后端开发.但正如我在上文中抛出的问题,我们能不能更好的优化我们在Controller中接受参数的方式呢?这一篇中我们就来聊一聊怎么更有效的接收Json参数. 传输参数的几种Method 在定义一个Rest接口时,我们通常会

  • 详解python实现读取邮件数据并下载附件的实例

    详解python实现读取邮件数据并下载附件的实例 实现结果图: 实现代码: #!/usr/bin/python2.7 # _*_ coding: utf-8 _*_ """ @Author: MarkLiu """ import poplib import email from email.parser import Parser from email.header import decode_header from email.utils im

  • Android模拟器接收UDP数据包的若干问题分析

    本文实例分析了Android模拟器接收UDP数据包的若干问题.分享给大家供大家参考,具体如下: android模拟器无法接收UDP数据包 代码如下: DatagramPacket pack = null; DatagramSocket mail_data = null; byte receiver[] = new byte[100]; try { pack = new DatagramPacket(receiver,receiver.length); mail_data = new Datagr

  • 详解复制备份docker容器数据的方法

    这里以jenkins容器为例,介绍三种方法. 方法一 将容器打包成镜像,这时数据就在镜像中了,im:1.0为容器名,可以随便取 docker commit <container id> im:1.0 重新运行镜像,-v将容器内tmp目录映射到宿主机上的tmp目录 docker run -itd -v /tmp:/tmp im:1.0 // 第一个tmp是宿主机目录,第二个是容器内目录 把 /var/jenkins_home的文件复制到tmp下,注意这里的container name是随机生成的

  • 详解Python中如何将数据存储为json格式的文件

    一.基于json模块的存储.读取数据 names_writer.py import json names = ['joker','joe','nacy','timi'] filename='names.json' with open(filename,'w') as file_obj: json.dump(names,file_obj) 解释:我们先导入json模块,再创建一个名字列表,第5行我们指定了要将该列表存储到其中的文件的名称.通常使用扩展名.json来指出文件存储的数据为json格式.

随机推荐