用PyQt5写一个exe(绘制图表,读写文件)

title: PyQt5桌面开发实例
date: 2020-03-16 12:30:05
categories: 
    - Python
tags: 
    - 桌面开发
    - PyQt
cover: https://antrovirens-1-1258258000.cos.ap-shanghai.myqcloud.com/cloud/%E9%9C%B2%E7%B1%B3%E5%A8%85.png

P.S. 发现我啥时候把nodejs给卸掉了…

设计

已知坐标,计算AB两点间距离和方位角,输出结果

工程

设计ui - 编译ui - 编写函数与响应 - 打包exe

代码

UI设计

一个menu,两个下拉单,

self.menu
self.action_Open
self.action_Save
self.action_Close
self.action_Quit
self.menu_2
self.action_Calculate

6个lineEdit用来输入和输出结果 ,1个plainTextEdit作为进程提示,1个graphicsView输出图形

self.lineEdit_XA
self.lineEdit_XB
self.lineEdit_YA
self.lineEdit_YB
self.lineEdit_Sab
self.lineEdit_tab
self.plainTextEdit
self.graphicsView

准备工作

测试数据文件

1,2
3,4

头文件

import sys
from math import pi, atan, sqrt
from datetime import datetime #输出时间

import matplotlib
matplotlib.use("Qt5Agg")  # 声明使用QT5
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtGui import * #这里懒得改了
from PyQt5.QtWidgets import *
from Ui_MainWindow import Ui_MainWindow

主函数

if __name__ == '__main__':
    app = QApplication(sys.argv)
    dlg = MainWindow()
    dlg.show()
    sys.exit(app.exec_())

全局变量

初始化为float

x = [0.0, 0.0]
y = [0.0, 0.0]
Sab = 0.0
Tab = 0.0

功能函数

计算方位角(高斯平面坐标系)

def Azimuth():
    dx = x[1] - x[0]
    dy = y[1] - y[0]
    
    if dx ==0:
        if dy >=0 :
            a = pi/2
        else:
            a = pi * 3 / 2
    elif dy ==0:
        if dx >= 0:
            a=0
        else:
            a = pi
    else:
        a = atan(dy / dx)
        if dx <= 0:
            a = a + pi
        elif dy <= 0:
            a = a + 2 * pi
    return a

quit

    @pyqtSlot()
    def on_action_Quit_triggered(self):
        self.close()

读取文件

推荐用with as格式写

   
    @pyqtSlot()
    def on_action_Open_triggered(self):
        filename,_ = QFileDialog.getOpenFileName(self,  '输入坐标数据', './',  'All Files (*);;Text Files (*.txt)');
        if filename == '':
            self.plainTextEdit.appendPlainText('[' + str(datetime.now()) + ']' + '打开失败 返回值为空')
            return 0
        f=open(filename,'r', encoding='utf-8')
        dic = []
        for line in f.readlines():
            line=line.strip('\n') #去掉换行符\n
            b=line.split(',') #将每一行以空格为分隔符转换成列表
            dic.append(b)
        
        
        self.lineEdit_XA.setText(dic[0][0])
        self.lineEdit_YA.setText(dic[0][1])
        self.lineEdit_XB.setText(dic[1][0])
        self.lineEdit_YB.setText(dic[1][1])
        
        self.plainTextEdit.appendPlainText('[' + str(datetime.now()) + ']' + '打开文件:' + str(filename))
        f.close()
 

写入文件

    @pyqtSlot()
    def on_action_Save_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: 保存结果        
        with open('输出结果.txt','a') as f:
            f.write('[' + str(datetime.now()) + ']' + '\n')
            f.write('A:'+str([x[0], y[0]]) + ';B:' + str([x[1],y[1]]) + '\n')
            f.write('Sab = '+ str(Sab) + '; Tab = ' + str(Tab) + '\n')
            f.write('\n')
        
        self.plainTextEdit.appendPlainText('[' + str(datetime.now()) + ']' + '保存成功')

执行计算

 # TODO: 检查是否缺失条件, 进行计算, 绘制图形
        
        if self.lineEdit_XA.text() == '' or self.lineEdit_XB.text() == '' or self.lineEdit_YA.text() == '' or self.lineEdit_YB.text() == '':   #空的情况下,内容为‘’ (空白);不是None
            self.plainTextEdit.appendPlainText('[' + str(datetime.now()) + ']' + '中断:参数为空')
            return 0
            
        XA = float(self.lineEdit_XA.text())
        XB = float(self.lineEdit_XB.text())
        YA = float(self.lineEdit_YA.text())
        YB = float(self.lineEdit_YB.text())
        
        if XA ==XB and YA == YB:
            self.plainTextEdit.appendPlainText('[' + str(datetime.now()) + ']' + '中断:两点重合')
            return 0
        
        global x, y, Sab, Tab # 给全局变量赋值
        
        x = [XA, XB]
        y = [YA, YB]
        
        Sab = sqrt((XA - XB) * (XA - XB) + (YA - YB) * (YA - YB) )
        Tab = Azimuth()
        
        self.lineEdit_Sab.setText(str(Sab))
        self.lineEdit_tab.setText(str(Tab))
        
        self.plainTextEdit.appendPlainText('[' + str(datetime.now()) + ']' + '计算完成:' + 'Sab = '+ str(Sab) + '; Tab = ' + str(Tab))

输出图形

这个还有点麻烦,参考的是这个人的代码(Matplotlib植入PyQt5 + QT5的UI呈现):https://www.cnblogs.com/laoniubile/p/5904817.html

写了一个类来实现把figure给传递出去

class Figure_Canvas(FigureCanvas):   # 通过继承FigureCanvas类,使得该类既是一个PyQt5的Qwidget,又是一个matplotlib的FigureCanvas,这是连接pyqt5与matplot                                          lib的关键

    def __init__(self, parent=None, width=5.1, height=4, dpi=10):
        fig = Figure(figsize=(width, height), dpi=80)  # 创建一个Figure,注意:该Figure为matplotlib下的figure,不是matplotlib.pyplot下面的figure

        FigureCanvas.__init__(self, fig) # 初始化父类
        self.setParent(parent)

        self.axes = fig.add_subplot(111) # 调用figure下面的add_subplot方法,类似于matplotlib.pyplot下面的subplot方法

    def StartPlot(self):
        self.axes.set_xlabel('Y')
        self.axes.set_ylabel('X')

        self.axes.scatter(y[0], x[0], c= 'red', marker='o')
        self.axes.scatter(y[1], x[1], c= 'yellow')
        self.axes.legend(('A', 'B'), loc='best')
        
        self.axes.set_title('Calculation Results',color = 'blue')
        
        self.axes.plot(y, x, c= 'blue', lw=0.5)
        
        self.axes.annotate('(' + str(x[0]) + ',' + str(y[0]) + ')',   xy=(y[0], x[0]), xytext=(-40, 6), textcoords='offset points', weight='heavy')
        self.axes.annotate('(' + str(x[1]) + ',' + str(y[1]) + ')',   xy=(y[1], x[1]), xytext=(-40, 6), textcoords='offset points', weight='heavy')
        
        t1 = (y[0]+y[1])/2
        t2 = (x[0]+x[1])/2
       
        self.axes.annotate('Sab = '+ str(Sab) + '; Tab = ' + str(Tab),   xy=(t1, t2), xytext=(-80, 80), textcoords='offset points',  color = 'blue',  arrowprops = dict( arrowstyle = '->', connectionstyle = 'arc3', color = 'b'))
        

用QGraphicsScene来加载figure,然后在View显示

        ins = Figure_Canvas() #实例化一个FigureCanvas
        ins.StartPlot()  # 画图
        graphicscene = QGraphicsScene()  #创建一个QGraphicsScene,因为加载的图形(FigureCanvas)不能直接放到graphicview控件中,必须先放到graphicScene,然后再把graphicscene放到graphicview中
        graphicscene.addWidget(ins)  # 把图形放到QGraphicsScene中,注意:图形是作为一个QWidget放到QGraphicsScene中的
        
#        graphicscene=graphicscene.scaled(self.graphicsView.width()-10,self.graphicsView.height()-10)
#        咋调大小暂时还没搞清楚

        self.graphicsView.setScene(graphicscene) # 把QGraphicsScene放入QGraphicsView
        self.graphicsView.show()  # 调用show呈现图形

打包exe

贴一个upx win64的下载链接,我自己上传的,官网下载巨慢,把upx扔到scrips下面就会自动使用,有时候会缺一些奇怪的东西,咋解决还没搞明白:https://www.lanzous.com/iabcmxi

感觉写个程序自己用用就行了,打包交作业实属憨憨,,特么生成出来200m,怕不是把整个qt整进去了

在文件夹里面按住shift右键,打开powershell,是个命令行就行

pyinstaller -F filename  #生成单个exe文件,比较小   -D为生成dll文件和一个exe文件,整个文件夹巨几儿大

然后会多两文件夹和一个spec文件,build里面是生成的中间文件,dist里面是生成的程序文件,spec文件里面可以手动修改生成选项

怎么优化可以看看这个文章(pyinstaller打包的exe太大?你需要嵌入式python玄学 拓展篇):https://zhuanlan.zhihu.com/p/77317765

总结

莫得总结

结果文件

[2020-03-16 15:20:07.085889]
A:[1.0, 1.0];B:[1.0, 2.0]
Sab = 1.0; Tab = 1.5707963267948966

用PyQt5写一个exe(绘制图表,读写文件)_第1张图片

你可能感兴趣的:(软件开发)