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