PyQt5簡單開發


1.窗口類型

QMainWindow:可以包含菜單欄、工具欄、標題欄、狀態欄,是最常見的窗口形式

QWidgets:不確定窗口的用途,使用QWidgets

QDialog:對話窗口的基類,用於執行短期任務,沒有菜單欄、工具欄、狀態欄

2.創建窗體應用程序

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication


class MainWin(QMainWindow):
    def __init__(self):
        super(MainWin, self).__init__()

        self.setWindowTitle("抓取工具")

        self.resize(400, 300)
        self.status = self.statusBar()
        self.status.showMessage('抓取工具')


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MainWin()
    mainWin.show()

    sys.exit(app.exec_())

從Main中可知,創建窗體程序,先要創建QApplication對象即應用對象,然后創建窗口對象(繼承自三種窗口類型),然后調用窗口的顯示函數show(),注意:沒有show函數,運行時指揮創建相關進程,即用用程序,窗口不顯示,唯有調用show函數,窗口才會顯示。

3.在窗體創建控件對象

按鈕、輸入框、標簽等控件基本上都在QtWidgets類中,添加控件代碼示例

class MainWin(QMainWindow):
    path = './app_icon.cio'

    def __init__(self):
        super(MainWin, self).__init__()
        self.init_ui()

    # 界面初始化
    def init_ui(self):
        # 創建控件對象
        self.edit_name = QtWidgets.QLineEdit()
        self.btn = QtWidgets.QPushButton('退出')
        # 創建布局
        layout = QHBoxLayout()
        # 往布局中添加控件
        layout.addWidget(self.btn)
        layout.addWidget(self.edit_name)

        self.btn.clicked.conect(self.btn_click)
        # 把布局放到窗口上
        mainFrame = QtWidgets.QWidget()
        mainFrame.setLayout(layout)
        # 居中充滿屏幕
        self.setCentralWidget(mainFrame)
        # 設置圖標
        self.setWindowIcon(QIcon(self.path))

        self.setWindowTitle("窗體程序")
        self.resize(400, 300)
        self.status = self.statusBar()
        self.status.showMessage('狀態欄')

 4.使用QtDesigner進行界面設計

1.配置PyCharm相關開發環境,下載安裝相關包,pyqt5以及pyqt5-tools。然后在Pycharm中ExtenalTools中添加

 

 

 

 

QtDesigner路徑:$Python安裝路徑$\Lib\site-packages\pyqt5_tools\Qt\bin\designer.exe,工作空間:$ProjectFileDir$

PyUIC路徑:Python.exe路徑,工作空間:$FileDir$,參數變量:-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py

二者使用時請在Tools -》 ExtenalTools下選擇

2.打開QtDesigner設計UI文件,選中UI文件使用PyUIC將其轉為Pyton文件。

3.使用UI文件

UI類

from PyQt5 import QtCore, QtGui, QtWidgets


# UI執行窗口界面
class Ui_ExecWindow(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.process_display = QtWidgets.QTextBrowser(Form)
        self.process_display.setGeometry(QtCore.QRect(50, 50, 300, 200))
        self.process_display.setObjectName("process_display")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))

窗口類

class ExecWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.ui = Ui_ExecWindow()
        self.ui.setupUi(self)

建議二者分開,添加槽和信號的綁定可以在窗口類的初始化函數中書寫。例如:

class ConfWindow1(QDialog):
    def __init__(self, task_type):
        QDialog.__init__(self)
        self.ui = Ui_ConfWindow1()
        self.ui.setupUi(self)
        self.new_actions = list()
        self.task_type = task_type  # 任務類型
        # 信號與槽綁定
        self.ui.rbtn_b.toggled.connect(self.input_type)
        self.ui.btn_save.clicked.connect(self.save_configuration)
        self.ui.btn_save_single.clicked.connect(self.save_single_action)

ui是UI類的實例對象。

4.重寫事件

以關閉窗口事件為例:

    def closeEvent(self, event):
        reply = QMessageBox.question(self, '確認', '確認退出嗎', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

當窗口關閉時會觸發該事件,可以用其他事件綁定窗口對象的close方法進行觸發,或其他關閉事件觸發

5.界面跳轉

事件綁定對應的方法(信號和槽),如單擊事件綁定下面函數:(注意如果要傳參時請在請在函數(槽)前使用lambda:標記,否則會出錯)

請使用self標記窗口類對象為成員變量,否則直接調用show函數會發生閃退現象。

# 信號與槽綁定
self.ui.btn_conf1.clicked.connect(lambda: self.configure_win_open(1))
self.ui.btn_conf2.clicked.connect(lambda: self.configure_win_open(2))


# 打開對應的配置界面 def configure_win_open(self, win_id): if win_id == 1: self.conf_win = ConfWindow1(self.task_type) self.conf_win.show() elif win_id == 2: self.conf_win = ConfWindow2(self.task_type) self.conf_win.show() else: print("沒有該窗口")

6.PyQt中多線程處理,解決界面假死問題

當界面要執行一個耗時間較長的任務時,使用單線程會出現界面假死現象。使用多線程可以解決,模板如下

線程子類

# 多線程,執行任務
from PyQt5 import QtCore
from PyQt5.QtCore import QThread
from selenium import webdriver

from application_task.Task import Task
from customize_exception.CustomizeException import NoSuchSelectorError
from utils import Util


class Task_Excutor(QThread):
    _signal = QtCore.pyqtSignal(str)  # 自定義信號

    def __init__(self, task_type):
        super().__init__()
        self.task_type = task_type

    def __del__(self):
        self.wait()

    def run(self):
        driver = webdriver.Chrome()
        actions = []
        task_conf = {}
        # 出現異常傳遞信號,因為當前線程無法使用GUI
        try:
            actions = Util.json_2_element_actions(
                "./configuration/" + self.task_type + "動作配置.json")
            task_conf = Util.load_conf("./configuration/" + self.task_type + "雜項配置.json")
        except FileNotFoundError as e:
            self._signal.emit(str("e"))
        except NoSuchSelectorError as e1:
            self._signal.emit(str("e1"))
        except Exception as e2:
            self._signal.emit(str("e2"))
        else:
            try:
                task = Task(driver, actions, task_conf)
                task.original_task()
            except Exception as e3:
                self._signal.emit(str("e3"))
            else:
                # 成功信號
                self._signal.emit(str("succeed"))

界面調用類中定義的方法

 # 任務開始
    def start_task(self):
        self.thread = Task_Excutor(self.ui.task_selector.currentText())
        self.thread._signal.connect(self.call_back)
        self.thread.start()

    # 信號回調處理
    def call_back(self, msg):
        if msg == "e":
            QMessageBox(QMessageBox.NoIcon, '錯誤', '指定路徑下配置文件不存在').exec()
        elif msg == "e1":
            QMessageBox(QMessageBox.NoIcon, '錯誤', '配置文件出錯,沒有指定的選擇器').exec()
        elif msg == "e2":
            QMessageBox(QMessageBox.NoIcon, '錯誤', '未知錯誤,執行過程中出錯').exec()
        elif msg == "e3":
            QMessageBox(QMessageBox.NoIcon, '錯誤', '未知錯誤,初始化動作或配置失敗').exec()
        elif msg == 'succeed':
            QMessageBox(QMessageBox.NoIcon, '提示', '任務執行成功').exec()
        else:
            QMessageBox(QMessageBox.NoIcon, '提示', '未知線程回調消息').exec()

創建一個線程的子類,重寫run方法。並定義信號,調用該線程的界面類中添加開始線程的方法start_task(),並與觸發線程開始的事件綁定。start_task()方法中為自定義信號綁定方法call_back,用於處理創建的線程的執行任務過程中信號傳遞處理。

注意:由於pyqt中,非GUI線程是無法調用控件的,如在執行任務中實例化QMessageBox會出現錯誤導致程序異常退出。所以通過回調函數觸發指定的信號並傳遞到GUI線程中進行控件的處理。


免責聲明!

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



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