目录
主要功能
pyqt5窗体程序设计实践,简述大致流程:包括环境设置、界面设计、程序运行和打包等
环境配置
主要版本如下:
python 3.9.7
PyQt5 5.15.6
GDAL 3.4.1
numpy 1.22.3
pandas 1.4.2
pyinstaller 5.0
窗体程序必需:
建议安装conda创建新的虚拟环境,然后配置到pycharm,便于后续应用
- 新建环境:conda create -n name python=3.9 name换成自定义的英文名
- 激活环境:conda activate name 安装所需的包
- pip install PyQt5
pip install pyqt5-tools
pip install GDAL-3.4.1-cp39-cp39-win_amd64.whl 此处pip在线安装模式错误,下载对应版本的GDAL whl文件,切换到到文件所在目录执行此命名安装,下载网址:Python Extension Packages for Windows - Christoph Gohlke (uci.edu) 可在该网页按ctrl+F 找到gdal
pip install numpy
pip install pandas
pip install pyinstaller - 配置到pycharm,选择新建环境的路径
- 配置快捷工具 添加前面虚拟环境的对应路径:本路径为E:\ProgramData\Anaconda3\envs\qt39\Lib\site-packages\qt5_applications\Qt\bin\designer.exe仅供参考,自行修改。项目路径:$ProjectFileDir$
参考路径:E:\ProgramData\Anaconda3\envs\qt39\python.exe 占位运算符命令-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py 指向项目文件夹下ui文件夹$ProjectFileDir$\ui 后续将ui文件保存在里面
(非必需)打包程序配置:
前面创建的环境中打包,可直接进行打包操作,可是conda环境中打包可能会体积较大,所以安装pipenv虚拟环境拓展包,配置轻量的python虚拟环境进行打包
- 安装 pip install pipenv
- 事先新建并进入项目文件夹中,创建虚拟环境 pipenv --python 3.9 指定python版本为3.9
- 进入虚拟环境 pipenv shell
- 安装拓展包(可不必安装pyqt5-tools开发工具)
pip install PyQt5
pip install pyqt5-tools
pip install GDAL-3.4.1-cp39-cp39-win_amd64.whl
pip install numpy
pip install pandas
pip install pyinstaller - 退出虚拟环境 exit
代码实现
1、设计UI
菜单栏 Tools >External Tools > designer 打开designer
a)新建文件
b)左侧工具栏选择控件 添加到界面
c) 保存ui文件
将*.ui文件保存到项目的ui文件夹下,便于使用拓展工具转化为需要的py文件
日期格式转换.ui文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>475</width>
<height>147</height>
</rect>
</property>
<property name="windowTitle">
<string>日期格式转换</string>
</property>
<widget class="QDateEdit" name="dateEdit">
<property name="geometry">
<rect>
<x>350</x>
<y>30</y>
<width>81</width>
<height>22</height>
</rect>
</property>
<property name="displayFormat">
<string>yyyy-M-d</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>350</x>
<y>10</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>距参考日</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>350</x>
<y>80</y>
<width>81</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>转换</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>30</x>
<y>10</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>选择文件:</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>30</x>
<y>30</y>
<width>281</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>30</x>
<y>60</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>输出路径:</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_2">
<property name="geometry">
<rect>
<x>30</x>
<y>80</y>
<width>281</width>
<height>21</height>
</rect>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
2、窗体代码编译生成
*.ui文件转换为*.py文件,在ui文件夹下右键>External Tools>PyUIC,借助前文配置的转化工具转化
生成的py文件(日期格式转换.py)内容如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '日期格式转换.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(475, 147)
self.dateEdit = QtWidgets.QDateEdit(Dialog)
self.dateEdit.setGeometry(QtCore.QRect(350, 30, 81, 22))
self.dateEdit.setObjectName("dateEdit")
self.label = QtWidgets.QLabel(Dialog)
self.label.setGeometry(QtCore.QRect(350, 10, 54, 12))
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(350, 80, 81, 21))
self.pushButton.setObjectName("pushButton")
self.label_2 = QtWidgets.QLabel(Dialog)
self.label_2.setGeometry(QtCore.QRect(30, 10, 54, 12))
self.label_2.setObjectName("label_2")
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setGeometry(QtCore.QRect(30, 30, 281, 21))
self.lineEdit.setObjectName("lineEdit")
self.label_4 = QtWidgets.QLabel(Dialog)
self.label_4.setGeometry(QtCore.QRect(30, 60, 54, 12))
self.label_4.setObjectName("label_4")
self.lineEdit_2 = QtWidgets.QLineEdit(Dialog)
self.lineEdit_2.setGeometry(QtCore.QRect(30, 80, 281, 21))
self.lineEdit_2.setObjectName("lineEdit_2")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "日期格式转换"))
self.dateEdit.setDisplayFormat(_translate("Dialog", "yyyy-M-d"))
self.label.setText(_translate("Dialog", "距参考日"))
self.pushButton.setText(_translate("Dialog", "转换"))
self.label_2.setText(_translate("Dialog", "选择文件:"))
self.label_4.setText(_translate("Dialog", "输出路径:"))
3、运行程序
py文件(日期格式转换.py)已经编译出来,但并不能运行,因为PyUIC只会生成在designer中定义的东西,还需要加入程序入口的代码。
这里另起一个py文件(main日期格式转换.py)作为程序入口和业务逻辑的实现,这样就可以实现UI和业务逻辑分离,修改了UI重新生成不会将之前的py文件全部覆盖,便于修改
我的py文件(main日期格式转换.py)代码如下:
注意:import刚才生成的py文件名称,我这里是“日期格式转换”,根据情况替换;
a)MyWindow对象继承Pyqt5拓展包内的QDialog和py文件(日期格式转换.py)内的Ui_Dialog
b)初始化函数内进行前端后台的连接:self.dateEdit.dateChanged.connect(self.onDateChanged)为日期框(名称为dateEdit)设置监听事件onDateChanged;self.pushButton.clicked.connect(self.zhuanhuan)为按钮(名称为pushButton)设置点击事件zhuanhuan;QAction定义一个图标,可设置图标,借助act.triggered.connect(self.wenjian)绑定槽函数wenjian;此外pyqt5还有很多的控件以及交互事件;
c)实例化MyWindow对象为myWin,myWin.show()显示窗体
import sys
from datetime import datetime
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import *
from 日期格式转换 import *
class MyWindow(QDialog, Ui_Dialog):
def __init__(self):
super(MyWindow, self).__init__()
self.setupUi(self)
self.maindata = {}
self.maindata["date"] = self.dateEdit.text()
self.maindata["date"] = datetime.strptime(self.maindata["date"], '%Y-%d-%m')
self.dateEdit.dateChanged.connect(self.onDateChanged)
act = QAction(self) # 定义一个行为
act.setIcon(QIcon('image/编辑文件.png')) # 设置行为icon,
act.triggered.connect(self.wenjian) # 绑定行为槽函数
self.lineEdit.addAction(act, QLineEdit.TrailingPosition) # 将该行为添加到lineEdit最右端
act2 = QAction(self) # 定义一个行为
act2.setIcon(QIcon('image/select.png')) # 设置行为icon,
act2.triggered.connect(self.outdir) # 绑定行为槽函数
self.lineEdit_2.addAction(act2, QLineEdit.TrailingPosition) # 将该行为添加到lineEdit最右端
self.pushButton.clicked.connect(self.zhuanhuan)
def onDateChanged(self):
self.maindata["date"] = datetime.strptime(self.dateEdit.text(), '%Y-%d-%m')
def outdir(self):
self.maindata["outPath"] = QFileDialog.getExistingDirectory(None, "输出文件夹", "C:/") # 返回选中的文件夹路径
# QFileDialog.getOpenFileName() # 返回选中的文件路径
# QFileDialog.getOpenFileNames() # 返回选中的多个文件路径
# QFileDialog.getSaveFileName() # 存储文件
self.lineEdit_2.setText((QtCore.QCoreApplication.translate("tile", self.maindata["outPath"])))
print(self.maindata)
def wenjian(self):
self.maindata["wenjian"] = QFileDialog.getOpenFileName(None,"选取文件","C:/","CSV文件(*.csv)")
# 返回选中的文件夹路径
if(self.maindata["wenjian"][0]==""):
return
self.maindata["wenjian"]=self.maindata["wenjian"][0]
pathMixName = self.maindata["wenjian"].split('/') # 将fn按照/切分
pathx = "/".join(pathMixName[0:len(pathMixName) - 1]) # 假设切分后有n部分,将前n-1部分用/重新拼接,就是文件的路径
namex = pathMixName[len(pathMixName) - 1] # 最后一个就是文件名
print(pathx,namex)
self.maindata["wenjianname"]=namex
self.lineEdit.setText(self.maindata["wenjian"])
print(self.maindata)
def zhuanhuan(self):
print(self.maindata)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
myWin = MyWindow()
myWin.show()
sys.exit(app.exec_())
d)窗体结果
程序打包
可直接在conda虚拟环境中打包,移动到py文件所在目录,打包方式主要有两种1)打包成一个exe:pyinstaller -w -F 日期格式转换.py 刚才生成的py文件名称,我这里是“日期格式转换”,根据情况替换;2)打包成文件目录pyinstaller -w 日期格式转换.py 速度较快,体积较大。
注意:打包完成后会在dist文件夹,-w为窗体程序,运行时关闭控制台;image等资源需要手动复制,1)为exe同路径、2)为dist下程序文件内;
若需要打包成更小体积的程序,就需要配置前文的 “(非必需)打包程序配置”,激活虚拟环境后移动到py文件所在目录,后续步骤相同