利用python快速开发一个上位机软件

利用python快速开发一个上位机软件,第1张

PyQt5+QtDesigner学习记录

标签: 漂流小江 2020年2月6日


一、串口调试助手
1.QT界面实现
(1)界面面图片展示

(图示1处函数为自定义函数)
(2)界面代码展示

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'chuankou.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(775, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.sendbutton = QtWidgets.QPushButton(self.centralwidget)
        self.sendbutton.setGeometry(QtCore.QRect(115, 266, 91, 31))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.sendbutton.setFont(font)
        self.sendbutton.setObjectName("sendbutton")
        self.sendcom = QtWidgets.QComboBox(self.centralwidget)
        self.sendcom.setGeometry(QtCore.QRect(100, 60, 131, 51))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.sendcom.setFont(font)
        self.sendcom.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.sendcom.setObjectName("sendcom")
        self.sendcom.addItem("")
        self.sendcom.setItemText(0, "")
        self.sendbot = QtWidgets.QComboBox(self.centralwidget)
        self.sendbot.setGeometry(QtCore.QRect(100, 160, 131, 41))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.sendbot.setFont(font)
        self.sendbot.setObjectName("sendbot")
        self.sendbot.addItem("")
        self.sendbot.addItem("")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 60, 71, 41))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.label.setFont(font)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(20, 150, 71, 41))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.label_2.setFont(font)
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.recvddata = QtWidgets.QTextEdit(self.centralwidget)
        self.recvddata.setGeometry(QtCore.QRect(240, 20, 371, 281))
        font = QtGui.QFont()
        font.setPointSize(13)
        self.recvddata.setFont(font)
        self.recvddata.setObjectName("recvddata")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(350, 310, 131, 41))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.label_3.setFont(font)
        self.label_3.setAlignment(QtCore.Qt.AlignCenter)
        self.label_3.setObjectName("label_3")
        self.inputdata = QtWidgets.QTextEdit(self.centralwidget)
        self.inputdata.setGeometry(QtCore.QRect(260, 360, 321, 81))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.inputdata.setFont(font)
        self.inputdata.setObjectName("inputdata")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(500, 470, 151, 41))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.label_4.setFont(font)
        self.label_4.setAlignment(QtCore.Qt.AlignCenter)
        self.label_4.setObjectName("label_4")
        self.senddata = QtWidgets.QPushButton(self.centralwidget)
        self.senddata.setGeometry(QtCore.QRect(120, 380, 91, 31))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.senddata.setFont(font)
        self.senddata.setObjectName("senddata")
        self.checknline = QtWidgets.QCheckBox(self.centralwidget)
        self.checknline.setGeometry(QtCore.QRect(210, 460, 211, 51))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.checknline.setFont(font)
        self.checknline.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.checknline.setObjectName("checknline")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 775, 18))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.sendbutton.clicked.connect(MainWindow.open_com)
        self.sendcom.activated['QString'].connect(MainWindow.port_changed)
        self.sendbot.activated['QString'].connect(MainWindow.baud_changed)
        self.senddata.clicked.connect(MainWindow.senddatatocom)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.sendbutton.setStatusTip(_translate("MainWindow", "点击连接"))
        self.sendbutton.setText(_translate("MainWindow", "连接"))
        self.sendbot.setItemText(0, _translate("MainWindow", "9600"))
        self.sendbot.setItemText(1, _translate("MainWindow", "115200"))
        self.label.setText(_translate("MainWindow", "串口"))
        self.label_2.setText(_translate("MainWindow", "波特率"))
        self.label_3.setText(_translate("MainWindow", "接收显示"))
        self.label_4.setText(_translate("MainWindow", "发送数据"))
        self.senddata.setText(_translate("MainWindow", "发送"))
        self.checknline.setText(_translate("MainWindow", "发送新行"))



1.界面逻辑实现代码
(1)逻辑代码展示

import serial
import sys
import struct
import serial.tools.list_ports
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import *
from chuankou import *


########################
#函数区
####################################################
# 串口函数区
def get_com_list():
    Com_List = []
    plist = list(serial.tools.list_ports.comports())
    if len(plist) > 0:
        for i in range(len(plist)):
            Com_List.append(list(plist[i])[0])
    return Com_List

#####################################################

#创建主界面
class MyWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setupUi(self)
        self.setWindowIcon(QIcon('serialscope.ico'))#程序的图标
        #创建一个定时器
        self.sendbutton.setToolTip('点击打开串口')
        # 初始化一个定时器,防止while循环读串口时陷入死循环
        self.timer = QTimer(self)  # 初始化一个定时器
        self.timer.timeout.connect(self.time_out)  # 计时结束调用time_out()

    def show_dialog(self, str=''):
        # 创建QDialog对象
        dialog = QDialog()
        # 创建按钮到新创建的dialog对象中
        lb = QLabel(str, dialog)
        lb.move(50, 50)
        # btn = QPushButton('ok', dialog)
        # 移动按钮,设置dialog的标题
        # btn.move(50, 50)
        dialog.setWindowTitle("Dialog")
        # 设置窗口的属性为Qt.ApplicationModal模态,用户只有关闭d窗后,才能关闭主界面
        dialog.setWindowModality(Qt.NonModal)
        dialog.exec_()
    #定时100ms读一次数据,未用while,防止程序陷入死循环
    def time_out(self):  # 按时接收数据
            global ser, timer_value
            # data = ser.readline()
            data = ser.read_all()  # 读取串口中的数据
            if data != b'':
                data = data.decode('utf-8')
                self.recvddata.append(data)
            self.timer.start(timer_value)  # 原本不需要重启,是考虑到变时定时

    #######################
    def open_com(self):
        global ser, serialPort, baudRate, com_list
        com_list = get_com_list()  # 得到可用串口
        if com_list != []:  # 如果一切正常,串口正常打开
            if serialPort != None:  # 如果也没出过什么叉子
                ser.port = serialPort
                ser.baudrate = baudRate
                if self.sendbutton.text() == '连接':
                    ser.open()  # 上述 *** 作已经打开串口,不能再次打开端口
                    self.timer.start(timer_value)  # 定时处理一次接收的数据
                    self.sendbutton.setText("关闭")
                    self.sendbutton.setToolTip('点击关闭串口')
                    print('串口已连接')
                    # while True:
                    #     data = ser.read_all()  # 读取串口中的数据
                    #     if data != b'':
                    #         data = data.decode('utf-8')
                    #         print(data)
                else:
                    self.timer.stop()
                    ser.close()  # 关闭端口
                    self.sendbutton.setText("连接")
                    self.sendbutton.setToolTip('点击打开串口')
                    print('串口已断开')
            else:  # 如果中途出过叉子,先修复
                myWin.port_combo.clear()
                for i in range(len(com_list)):  # 将可用串口填充到下拉框
                    myWin.sendcom.addItem(com_list[i])
                serialPort = com_list[0]  # 串口号
        else:  # 已经坏透了,显示提示框
            serialPort = None
            myWin.sendcom.clear()
            myWin.show_dialog(str='请先打开串口')
   #向串口发送数据
    def senddatatocom(self):
        global serialPort, ser
        if self.sendbutton.text() == '关闭'and serialPort != None:
            send_str=self.inputdata.toPlainText()
            state_checknline=self.checknline.isChecked()
            if state_checknline == True:#选择是否换行
                print('发送新行')
                send_str += '\r\n'
            ser.write(send_str.encode('utf-8'))#将要发送的数据写入串口
            print('发送数据为:'+send_str)
        else:
            self.show_dialog(str='请先打开串口')
    #改变串口
    def port_changed(self, text):
        global serialPort
        serialPort = text
        print('串口:' + serialPort)
        ser.port = serialPort
    #改变波特率
    def baud_changed(self, text):
        global baudRate
        baudRate = int(text)
        print(baudRate)
        ser.baudrate=baudRate
####################################################
#全局变量及先行代码
app = QApplication(sys.argv)
myWin = MyWindow()
myWin.show()
# myWin.Port_send() #开机有可用串口则自动打开串口
baudRate = 115200  # 波特率
timer_value=100
#################################################
ser=serial.Serial(timeout=0.5)
com_list=get_com_list() #得到可用串口
if com_list!=[]:
    for i in range(len(com_list)):  # 将可用串口填充到下拉框
        myWin.sendcom.addItem(com_list[i])
    serialPort = com_list[0]  # 串口号
else:
    serialPort = None
    myWin.show_dialog(str='请先打开串口')


sys.exit(app.exec_())
(2)逻辑效果展示

二、PyQt5使用技巧总结
1.多线程的三种使用
*背景:*在PyQt中所有的窗口都在UI主线程中(就是执行了QApplication.exec()的线程,在这个线程中执行耗时的 *** 作阻塞UI线程,从而导致窗口停止响应,加入多线程机制会很好的解决这个问题。
(1)计时器模块QTimer
实现:

    #首先引入QTimer模块
    from PyQt5.QtCore import Qt, QTimer
#****************************************************
    # 初始化一个定时器,防止while循环读串口时陷入死循环
    self.timer = QTimer(self)  # 初始化一个定时器
    self.timer.timeout.connect(self.time_out)  # 计时结束调用time_out()
#****************************************************
    #定时100ms读一次数据,未用while,防止程序陷入死循环
    def time_out(self):  # 按时接收数据
            pass
        self.timer.start(timer_value)  # 原本不需要重启,是考虑到变时定时
#****************************************************
    self.timer.start(timer_value)  # 定时处理一次接收的数据,timer_value为设置的时间,单位ms
#****************************************************
 self.timer.stop()#停止计时

(2)线程模块QThread
实现:

    #首先引入QTimer模块
    from PyQt5.QtCore import Qt, QTimer
#****************************************************
  #要使用QThread开始一个线程,需创建其子类,覆盖其QThread.run()函数,
  #如:
  class Thread(QThread):
    def__init__(self):
        super(Thread,self).__init__()
    def run(self):
        #相关代码
        pass
        
#****************************************************
     #接下来创建一个新的线程
     thread=Thread()
     thread.start()
#****************************************************
  

此笔记写的有些粗糙,更详细笔记我已在本人公众号更新,或者想要了解更多或者想要获取该工程代码请关注微信公众号“漂流小江”,还可以在b站观看小江的视频课程。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/757532.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-01
下一篇 2022-05-01

发表评论

登录后才能评论

评论列表(0条)

保存