• 使用PyQt5做的几个GUI以及使用过程遇到的问题记录 ***


    最近遇到一个需求是做一个可以在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出现的错误解决办法——使用最后的命令即可

    pyinstaller打包pyqt5程序 全过程 超详细

    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 

    4、Git上找的一些学习资料及demo

    Python/PyQt5的demo合集及文档

    《Python Qt GUI与数据可视化编程》随书源码

    《PyQt5快速开发与实战》配套代码

  • 相关阅读:
    Mybatis使用resultType实现一对一查询
    利用webSocket使网页和服务器通信
    hdu--1728--special bfs
    hdu--1429--状压bfs
    hdu--3006--不知为何wa
    hdu--3001--类似旅行商<tsp>
    hdu--2660--二维费用背包
    hdu--4632--dp
    hdu--4497--数论
    hdu--4496--并查集
  • 原文地址:https://www.cnblogs.com/paulwhw/p/13595126.html
Copyright © 2020-2023  润新知