最近遇到一个需求是做一个可以在win系统中运行的可执行的GUI程序(上一次做GUI程序是大学时候搞的一个网络嗅探器以及几个串口通信的小东西)。C艹已经被我完全扔了,用C艹做肯定不现实!
网上查了下Python还真有做GUI的包——PyQt,底层应该是封装了C艹,不纠结这些技术细节,于是打算用PyQt试试。。。
下面是在此期间做的几个demo以及一些问题记录,当做是个人笔记吧,也希望能帮助到初学PyQt的你。。。
说明
PyQt的版本
使用的是PyQt5。
关于开发与运行的环境
所有的demo与打包过程只能在Windows中执行:我找到的好几个demo都没办法在Mac上顺利运行!而且我做的demo都只能打包成.exe文件!也就是说开发与运行环境一定要选择Windows!
选择本地文件复制到桌面
执行效果
代码
# -*- coding: utf-8 -*- from __future__ import unicode_literals import os # Form implementation generated from reading ui file 'xiazai.ui' # # Created by: PyQt5 UI code generator 5.11.2 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import * from PyQt5.QtCore import * from socket import * import sys import time # from erji import * # 默认路径是桌面 lujing = 'C:/Users/dell/Desktop/' # class Ui_MainWindow1(object): # # def setupUi(self, MainWindow): # MainWindow.setObjectName("MainWindow") # MainWindow.resize(821, 517) # MainWindow.setStyleSheet("background-image:url('back1.png')") # self.centralwidget = QtWidgets.QWidget(MainWindow) # self.centralwidget.setObjectName("centralwidget") # # self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget) # self.textBrowser.setGeometry(QtCore.QRect(40, 50, 751, 111)) # font = QtGui.QFont() # font.setPointSize(16) # font.setBold(True) # font.setWeight(75) # self.textBrowser.setFont(font) # self.textBrowser.setObjectName("textBrowser") # self.textBrowser.clear() # ADDR = ('127.0.0.1', 8888) # s = socket() # s.connect(ADDR) # s.send(b'L') # data = s.recv(1024).decode() # if data == 'OK': # data = s.recv(4096).decode() # files = data.split('#') # for file in files: # self.textBrowser.append(file) # # self.pushButton = QtWidgets.QPushButton(self.centralwidget) # self.pushButton.setGeometry(QtCore.QRect(600, 400, 191, 41)) # font = QtGui.QFont() # font.setPointSize(16) # font.setBold(True) # font.setWeight(75) # self.pushButton.setFont(font) # self.pushButton.setObjectName("pushButton") # self.pushButton.clicked.connect(self.loadfile) # # self.label = QtWidgets.QLabel(self.centralwidget) # self.label.setGeometry(QtCore.QRect(330, 10, 361, 41)) # self.label.setObjectName("label") # # self.label_2 = QtWidgets.QLabel(self.centralwidget) # self.label_2.setGeometry(QtCore.QRect(60, 200, 311, 41)) # self.label_2.setObjectName("label_2") # # self.lineEdit = QtWidgets.QLineEdit(self.centralwidget) # self.lineEdit.setGeometry(QtCore.QRect(370, 200, 421, 41)) # font = QtGui.QFont() # font.setPointSize(16) # font.setBold(True) # font.setWeight(75) # self.lineEdit.setFont(font) # self.lineEdit.setText("") # self.lineEdit.setObjectName("lineEdit") # self.lineEdit.setPlaceholderText("请输入文件名") # # self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) # self.pushButton_2.setGeometry(QtCore.QRect(320, 400, 191, 41)) # font = QtGui.QFont() # font.setPointSize(16) # font.setBold(True) # font.setWeight(75) # self.pushButton_2.setFont(font) # self.pushButton_2.setObjectName("pushButton_2") # self.pushButton_2.clicked.connect(self.save_path) # # self.label_3 = QtWidgets.QLabel(self.centralwidget) # self.label_3.setGeometry(QtCore.QRect(60, 280, 301, 20)) # self.label_3.setObjectName("label_3") # # self.textBrowser_2 = QtWidgets.QTextBrowser(self.centralwidget) # self.textBrowser_2.setGeometry(QtCore.QRect(370, 270, 421, 41)) # font = QtGui.QFont() # font.setPointSize(12) # font.setBold(True) # font.setWeight(75) # self.textBrowser_2.setFont(font) # self.textBrowser_2.setObjectName("textBrowser_2") # self.textBrowser_2.append(lujing) # # self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget) # self.pushButton_3.setGeometry(QtCore.QRect(40, 400, 191, 41)) # font = QtGui.QFont() # font.setPointSize(16) # font.setBold(True) # font.setWeight(75) # self.pushButton_3.setFont(font) # self.pushButton_3.setObjectName("pushButton_3") # self.pushButton_3.clicked.connect(self.flush) # # # MainWindow.setCentralWidget(self.centralwidget) # # self.menubar = QtWidgets.QMenuBar(MainWindow) # self.menubar.setGeometry(QtCore.QRect(0, 0, 821, 23)) # self.menubar.setObjectName("menubar") # # MainWindow.setMenuBar(self.menubar) # # self.statusbar = QtWidgets.QStatusBar(MainWindow) # self.statusbar.setObjectName("statusbar") # # MainWindow.setStatusBar(self.statusbar) # # self.retranslateUi(MainWindow) # QtCore.QMetaObject.connectSlotsByName(MainWindow) # # # 下载 # def loadfile(self): # word = self.lineEdit.text() # global lujing # path = lujing + word # ADDR = ('127.0.0.1', 8888) # s = socket() # s.connect(ADDR) # s.send(('G ' + word).encode()) # data = s.recv(1024).decode() # if data == 'OK': # fd = open(path, 'wb') # while True: # data = s.recv(1024) # if data == b"##": # break # fd.write(data) # fd.close() # # # 选择保存路径 # def save_path(self): # l = [] # openfile_name = QFileDialog.getExistingDirectory() # l.append(openfile_name) # global lujing # if l[0]: # lujing = l[0] + "/" # self.textBrowser_2.clear() # self.textBrowser_2.append(lujing) # # # 刷新 # def flush(self): # self.textBrowser.clear() # ADDR = ('127.0.0.1', 8888) # s = socket() # s.connect(ADDR) # s.send(b'L') # data = s.recv(1024).decode() # if data == 'OK': # data = s.recv(4096).decode() # files = data.split('#') # for file in files: # self.textBrowser.append(file) # # def retranslateUi(self, MainWindow): # _translate = QtCore.QCoreApplication.translate # MainWindow.setFixedSize(MainWindow.width(), MainWindow.height()) # MainWindow.setWindowTitle(_translate("MainWindow", "下载中")) # self.pushButton.setText(_translate("MainWindow", "下载")) # self.label.setText(_translate( # "MainWindow", "<html><head/><body><p><span style=" font-size:18pt; font-weight:600;">下载文件列表</span></p></body></html>")) # self.label_2.setText(_translate( # "MainWindow", "<html><head/><body><p><span style=" font-size:16pt; font-weight:600;">请在此输入您要下载的文件名:</span></p></body></html>")) # self.pushButton_2.setText(_translate("MainWindow", "选择下载路径")) # self.label_3.setText(_translate( # "MainWindow", "<html><head/><body><p><span style=" font-size:16pt; font-weight:600;">您选择的下载路径是:</span></p></body></html>")) # self.pushButton_3.setText(_translate("MainWindow", "刷新")) class Ui_MainWindow(QtWidgets.QWidget): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(542, 442) MainWindow.setStyleSheet("background-image:url('upload.png')") self.MainWindow = MainWindow self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") # 上传按钮 self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(30, 320, 221, 41)) font = QtGui.QFont() font.setPointSize(16) font.setBold(True) font.setWeight(75) self.pushButton.setFont(font) self.pushButton.setObjectName("pushButton") self.pushButton.clicked.connect(self.upfile) # # 开始下载 # self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget) # self.pushButton_4.setGeometry(QtCore.QRect(290, 320, 221, 41)) # font = QtGui.QFont() # font.setPointSize(16) # font.setBold(True) # font.setWeight(75) # self.pushButton_4.setFont(font) # self.pushButton_4.setObjectName("pushButton_4") # self.pushButton_4.clicked.connect(self.jump_to_erji) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 542, 23)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") # MainWindow.setStatusBar(self.statusbar) #该行会使得屏幕下方出现一片空白 self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # 上传 def upfile(self): lst = [] openfile_name = QFileDialog.getOpenFileName(self) print("file_path>>>>>", openfile_name, type(openfile_name)) lst.append(openfile_name) print("开始上传了!!!") print("lst>>>>>", lst) ### 下面就可以调用接口了 # 测试 将文件写在桌面 if lst[0][0]: file_path = lst[0][0] new_file_name = "new_file" new_file_path = os.path.join(lujing,new_file_name) # 将选择的文件写入到指定的地方 —— 这里指定的是win电脑的桌面 with open(new_file_path,"wb") as fw: with open(file_path,"rb")as fr: while 1: line = fr.readline() print("line<<<<<",line) if not line: break fw.write(line) # if l[0][0]: # ADDR = ('127.0.0.1', 8888) # s = socket() # s.connect(ADDR) # lujing = l[0][0] # fd = open(lujing, 'rb') # filename = lujing.split('/')[-1] # s.send(("P " + filename).encode()) # data = s.recv(1024).decode() # if data == 'OK': # while True: # data = fd.read(1024) # if not data: # time.sleep(0.1) # s.send(b'##') # break # s.send(data) # # 这一块注意,是重点从主界面跳转到Demo1界面,主界面隐藏,如果关闭Demo界面,主界面进程会触发self.form.show()会再次显示主界面5 # def jump_to_erji(self): # self.MainWindow.hide() # MainWindow1 = QtWidgets.QDialog() # ui = Ui_MainWindow1() # # MainWindow = QtWidgets.QMainWindow() # ui.setupUi(MainWindow1) # MainWindow1.show() # MainWindow1.exec_() # self.MainWindow.show() def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setFixedSize(MainWindow.width(), MainWindow.height()) MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "上传文件")) # self.pushButton_4.setText(_translate("MainWindow", "下载文件")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
拓展说明
上传如果有逻辑的话将逻辑代码写在 Ui_MainWindow类中的upfile方法中!
代码中的 QFileDialog.getOpenFileName 方法只能获取单个文件,自己试了下想要获取多个文件可以使用方法:QFileDialog.getOpenFileNames (只差一个s 0-0)
我这里在上传文件后拓展了一些方法,记录一下:
### 给列表去重 def duplicate_removal_lst(lst:list)->list: # 从后往前遍历 for i in lst[::-1]: for k in range(lst.count(i)): if lst.count(i) > 1: lst.remove(i) return lst class Ui_MainWindow(QtWidgets.QWidget): def setupUi(self, MainWindow): ...... # 上传 def upfile(self): lst = [] # openfile_name = QFileDialog.getOpenFileName(self) # 这个控件只能选一个文件 openfile_name = QFileDialog.getOpenFileNames(self) # 这个控件可以选多个文件! print("file_path>>>>>", openfile_name, type(openfile_name)) lst.append(openfile_name) print("开始上传了!!!") print("lst>>>>>", lst) # lst>>>>> [(['C:/Users/dell/Desktop/drag1.mp4', 'C:/Users/dell/Desktop/fail.txt', 'C:/Users/dell/Desktop/go语言学习笔记$$$.doc'], 'All Files (*)')] ### 下面就可以调用接口了 if lst[0][0]: file_path_lst = lst[0][0] print("file_path_lst>>>>>",file_path_lst) # ['C:/Users/dell/Desktop/pyqtTest/fb_test.py ', 'C:/Users/dell/Desktop/pyqtTest/gui1.py ', ...] ### 可以开多进程调用SDK 先用同步代码实现效果 success_file_path = os.path.join(lujing,"success.txt") fail_file_path = os.path.join(lujing,"fail.txt") # 记录上传成功与失败的视频的路径 f_success = open(success_file_path,"a+") f_fail = open(fail_file_path,"a+") ### 注意 a+ 方式读文件会把光标放在最后,想要获取之前记录的内容需要将光标放在开始的位置!!! f_success.seek(0) success_lines_lst = f_success.readlines() print("success_lines>>>>>", success_lines_lst) # ['C:/Users/dell/Desktop/123123.gif:2780036978947806 ', 'C:/Users/dell/Desktop/drag1.mp4:606205353405771 '] # 因为文件中有id,在判断上传的文件是否在已上传的文件列表中需要再构建一下 existed_lst = list() for fp in success_lines_lst: append_str = fp.split("||")[0] if append_str not in existed_lst: existed_lst.append(append_str) # 已经成功上传的文件路径 print("existed_lst>>>>",existed_lst) # ['C:/Users/dell/Desktop/123123.gif', 'C:/Users/dell/Desktop/drag1.mp4'] # 防止一次上传相同的文件,给列表去重 ———— 实际上同一个文件夹中是不会有重名的文件的,似乎多此一举 ~ ~! file_path_lst = duplicate_removal_lst(file_path_lst) for fpath in file_path_lst: try: # 如果被选的文件之前已经上传成功了,就不再上传了 print("fpath>>>>",fpath) if fpath in existed_lst: print("############# 这个文件已经上传过了 #####################",fpath) # continue不走下面的逻辑 continue print("############# 这个文件没传过 #####################",fpath)
# 业务代码省去 ret = crate_ad(fpath,"xxx") # 先不用传account_id id = ret["id"] ## 中间用 || 分割 !!! f_success.write("{}||{} ".format(fpath,str(id))) # 使用fb的异常捕获 except fb_exceptions.FacebookRequestError as e: f_fail.write("fail_file_path||{} ".format(fpath)) continue f_success.close() f_fail.close() # ret = get_account_campaigns() #ret = crate_ad(file_path,"xxx") # print("创建的ret>>>>>",ret)
多文件上传的效果
123
123
222
222
666
666
遇到问题及一些参考的博客与资料链接
1、pyinstaller打包相关
打包命令:
pyinstaller xxx.py --noconsole // 最后在dist中的那个对应名称的文件夹中找到可执行程序,如果有图片或者其他静态资源的话记得将这些静态资源放在dist里面的那个文件夹中!
一些参考资料:
python安装pyinstaller出现的错误解决办法——使用最后的命令即可
pyqt5程序打包成exe文件的步骤和遇到的坑,以及如何更改exe的图标
2、打包过程遇到一个报错:AttributeError: module 'enum' has no attribute 'IntFlag'
成功解决AttributeError: module 'enum' has no attribute 'IntFlag'?
3、参考书籍以及资料
http://zetcode.com/gui/pyqt5/firstprograms/
https://www.cnblogs.com/wudeng/p/9337065.html
https://weread.qq.com/web/reader/6393267071ccfa97639f573