使用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\n', 'C:/Users/dell/Desktop/pyqtTest/gui1.py\n', ...]
            ### 可以開多進程調用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\n', 'C:/Users/dell/Desktop/drag1.mp4:606205353405771\n']
            # 因為文件中有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("{}||{}\n".format(fpath,str(id))) # 使用fb的異常捕獲 except fb_exceptions.FacebookRequestError as e: f_fail.write("fail_file_path||{}\n".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快速開發與實戰》配套代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM