PyQt5 GUI程式設計

余生没有余生發表於2024-03-19

一.PyQt5簡介

PyQt5是一個用於建立圖形使用者介面(GUI)應用程式的跨平臺工具集,它將Qt庫(廣泛用於C++程式語言中建立豐富的GUI應用程式)的功能包裝給Python使用者。PyQt5是由Riverbank Computing開發的,並且可以在所有主流作業系統上執行,包含Windows、macOS和Linux。

PyQt5包括了超過620個類和6000個函式和方法。這個框架支援包括SQL資料庫、執行緒、Unicode、正規表示式、網路程式設計等高階功能。除了GUI功能外,PyQt5還允許使用者訪問Qt的模型/檢視架構和QML(Qt Modeling Language),這是一種專門為建立動態和自定義使用者介面而設計的語言。

二.環境搭建

1.終端使用pip安裝PyQt5庫

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5

2.如果出現Could not build wheels for PyQt5_sip, which is required to install pyproject.toml-based projects報錯資訊

3.先安裝 Visual Studio 後再安裝PyQt5即可,終端執行如下指令

wget https://aka.ms/vs/17/release/vs_BuildTools.exe -o vs_BuildTools.exe ; cmd /c vs_BuildTools.exe

勾選C++/CLI後安裝就行

三.基本用法

1.PyQt5常見的模組

QApplication 這個類管理GUI應用程式的控制流和主要設定,並且是每個PyQt5應用程式中必須有的部分
QWidget 所有使用者介面物件的基類。當你想建立一個自定義的視窗時,你會使用或者繼承這個類
QLabel 用於展示文字或圖片的類
QtCore 其他模組使用的核心非 GUI 類
QAction 用於處理選單欄、工具欄或快捷鍵等的動作。
QtSql 使用 SQL 進行資料庫整合的類
QtXml 處理 XML 的類
QSlider 滑動條,讓使用者透過滑動選擇一個數值。

2.一個簡單的視窗建立

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QWidget, QLabel, QMessageBox, QApplication


def windows():
    # 建立一個 QApplication 類的應用程式物件
    app = QApplication(sys.argv)
    # 基於QWidget類宣告視窗
    w = QWidget()
    # 新增一個QLabel物件,並將標籤新增“helloworld”文字。
    b = QLabel(w)
    b.setText("Hello World!")
    # 設定文字控制元件在視窗中的位置(x,y)
    b.move(50, 50)
    # 設定label控制元件的長和寬
    b.resize(100,20)
    # 設定字型樣式大小
    font = QFont()
    font.setFamily("Arial")  # 字型樣式,中文英文都可(“楷體”)
    font.setPointSize(20)  # 字型大小
    b.setFont(font)
    # 透過 setGeometry() 方法定義視窗的大小和位置(x,y,w,h)
    w.setGeometry(100, 100, 500, 1000)
    # 設定視窗標題
    w.setWindowTitle("PyQt5")

    # 顯示視窗
    w.show()
    # 進入應用程式的主迴圈app.exec_()方法(視窗一直顯示)
    sys.exit(app.exec_())


if __name__ == '__main__':
    windows()

備註寫的很詳細了,這裡就不一一介紹每行程式碼的意思了。

3.視窗icon設定

import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QWidget, QApplication  # 匯入儘量用具體類,不用*


class Window(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.initUI()
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle("PyQt5")

    # 設定icon
    def initUI(self):
        self.setWindowIcon(QIcon('./2.jpg'))  # 設定視窗左上角icon

def main():
    app = QApplication(sys.argv)
    ex = Window()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

上述程式碼中,我們在initUI函式中,呼叫父類setWindowIcon()方法去設定視窗icon,在Window類中初始化時去呼叫initUI函式來實現設定icon。

4.QLabel控制元件

    def qlabel(self):
        font = QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        label = QLabel(self)
        label.setText("Hello World")  # 設定文字
        label.setFont(font)  # 設定文字字型型別及大小
        label.move(50, 20)  # 控制元件在視窗的位置

這裡和如上寫法一致,在Window類中寫一個qlabel函式,裡面去呼叫QLabel,再在Window類中初始化時呼叫這個函式即可(使用QLabel模組時需提前匯入該模組),我們來看下結果。

5.tips資訊提示框

    def tips(self):
        # 建立一個按鈕控制元件
        btn = QPushButton('Button', self)
        # 設定文字字型及大小
        btn.setFont(QFont('SansSerif', 50))
        # 設定tips
        btn.setToolTip('This is a widget')
        # 設定按鈕在視窗的位置
        btn.move(100, 100)

效果如下,滑鼠懸浮在button上時,會出現tips資訊彈框。

6.關閉二次確定彈框

主動關閉視窗(即點選視窗右上角X),彈出二次確定彈框,提示是否關閉。

import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QWidget, QApplication, QMessageBox, QDesktopWidget  # 匯入儘量用具體類,不用*


class Window(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.initUI()
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle("PyQt5")
        self.center()

    # 設定icon
    def initUI(self):
        self.setWindowIcon(QIcon('./2.jpg'))

    def closeEvent(self, event):  # 關閉二次確定彈框
        reply = QMessageBox.question(self, '是否關閉',
                                     "Are you sure to quit?", QMessageBox.Yes, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()  # 關閉視窗
        else:
            event.ignore()  # 不關閉

    def center(self):  # 設定視窗居中
        qt = self.frameGeometry()   # 獲取需要操作的視窗位置,長寬(即設定的setGeometry)
        cp = QDesktopWidget().availableGeometry().center()  # 獲取電腦解析度
        qt.moveCenter(cp)  # 獲取電腦中間位置
        self.move(qt.topLeft())  # 將視窗移動到中間位置


def main():
    app = QApplication(sys.argv)
    ex = Window()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

上述程式碼中重寫了父類中的closeEvent方法,透過QMessageBox.question()來獲取使用者行為,event.accept()來確定關閉視窗。

7.關閉視窗事件

    def clos(self):
        qbtn = QPushButton('Quit', self)  # 建立一個按鈕
        qbtn.clicked.connect(QCoreApplication.instance().quit)  # 回撥關閉事件
        qbtn.setToolTip("點選關閉視窗")  # tips提示
        qbtn.move(0, 0)

如下圖效果,滑鼠點選Quit按鈕後視窗關閉,其效果和關閉按鈕X一致。

8.選單欄和工具欄

QMainWindow用於建立主應用程式視窗的類。它是 QWidget 的一個子類,提供了建立具有選單欄、工具欄、狀態列等的主視窗所需的功能。

1)狀態列

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication

class Example(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')
        self.statusBar().showMessage("狀態列")  # 設定狀態列

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

狀態列的設定很簡單,透過呼叫QMainWindow的statusBar()方法建立狀態列,showMessage()來設定狀態列顯示的文字。

2)選單欄

    def bar(self):
        action = QAction(QIcon('./2.jpg'), '登入', self)  # 建立QAction例項
        action.setShortcut('Ctrl+a')  # 設定快捷鍵操作
        action.setStatusTip('登入')  # 狀態列提示,視窗的左下角出現,滑鼠懸停在選項上會出現
        action.triggered.connect(qApp.quit)  # 點選事件後回撥的方法(qApp.quit關閉視窗)

        menubar = self.menuBar()  # 建立一個選單欄
        menu = menubar.addMenu('File')  # 設定選單欄tab

        menu.addAction(action)  # 關聯事件

用過menuBar()建立一個選單欄,並新增addMenu()tab項,透過addAction()新增QAction行為動作,具體效果如下。

triggered.connect(qApp.quit)設定了觸發動作後回撥事件,即點選登入選項或快捷鍵Ctrl+A時會觸發qApp.quit關閉視窗。上訴中我們只建立了一個選單欄並只繫結了一個QAction如果想要多個選單欄多個動作,可以建立多個addMenu(),下面看下具體例項。

   def bar(self):
        action = QAction(QIcon('./2.jpg'), '登入', self)  # 建立QAction例項
        action.setShortcut('Ctrl+a')  # 設定快捷鍵操作
        action.setStatusTip('登入')  # 狀態列提示,視窗的左下角出現,滑鼠懸停在選項上會出現
        action.triggered.connect(qApp.quit)  # 點選事件後回撥的方法(qApp.quit關閉視窗)

        action1 = QAction(QIcon('./2.jpg'), '登入', self)  # 建立QAction例項
        action1.setShortcut('Ctrl+a')  # 設定快捷鍵操作
        action1.setStatusTip('退出')  # 狀態列提示,視窗的左下角出現,滑鼠懸停在選項上會出現
        action1.triggered.connect(qApp.quit)  # 點選事件後回撥的方法(qApp.quit關閉視窗)

        menubar = self.menuBar()  # 建立一個選單欄
        menu = menubar.addMenu('File')  # 設定選單欄tab
        menubar1 = self.menuBar()  # 建立一個選單欄
        menu1 = menubar1.addMenu('File1')  # 設定選單欄tab

        menu.addAction(action)  # 關聯事件
        menu.addAction(action1)  # 關聯事件

3)子選單欄

上面我們只是實現了一級選單欄,那麼在需求中要求建立二級,三級或者多級選單,此時就需要用到QMenu()來建立下拉選單欄了,我們先來看下二級選單欄的建立。

    # 建立子選單
    def bar_z(self):
        menubar = self.menuBar()  # 建立選單欄
        menu = menubar.addMenu('File')  # 設定選單欄tab

        newmenu = QMenu('一級下拉框', self)  # 建立一個下拉選單
        impAct = QAction('二級目錄', self)  # 設定一個動作
        impAct.triggered.connect(self.btn)  # 點選事件後回撥的方法
        newmenu.addAction(impAct)  # 新增動作到下選單中

        newact = QAction('一級目錄', self)  # 建立動作

        menu.addAction(newact)  # 新增動作到選單欄
        menu.addMenu(newmenu)  # 新增下拉選單到選單欄

    def btn(self):
        # 建立一個按鈕控制元件
        btn = QPushButton('Button', self)
        # btn.setGeometry(100, 100, 80, 30)
        btn.move(100, 100)
        btn.setToolTip("button")
        btn.show()

如果我們想建立三級目錄甚至更多級的目錄,可以建立多個下拉選單欄,並透過addMenu()新增進去,下面看下具體實現。

# 建立子選單
    def bar_z(self):
        menubar = self.menuBar()  # 建立選單欄
        menu = menubar.addMenu('File')  # 設定選單欄tab

        newmenu1 = QMenu('二級下拉框', self)  # 建立一個下拉選單
        impAct1 = QAction('三級目錄', self)  # 設定一個動作
        impAct1.triggered.connect(self.btn)  # 點選事件後回撥的方法
        newmenu1.addAction(impAct1)  # 新增動作到下選單中

        newmenu = QMenu('一級下拉框', self)  # 建立一個下拉選單
        impAct = QAction('二級目錄', self)  # 設定一個動作
        impAct.triggered.connect(self.btn)  # 點選事件後回撥的方法
        newmenu.addAction(impAct)  # 新增動作到下選單中
        newmenu.addMenu(newmenu1)  # 新增下拉選單欄到二級選單下

        newact = QAction('一級目錄', self)  # 建立動作

        menu.addAction(newact)  # 新增動作到選單欄
        menu.addMenu(newmenu)  # 新增下拉選單到選單欄

4)帶核取方塊的選單

    def bar_checkable(self):
        menubar = self.menuBar()
        bar_menu = menubar.addMenu('View')  # 新增選單欄
        statact = QAction('核取方塊', self, checkable=True)  # 建立一個可以勾選的動作
        statact.setStatusTip('View statusbar')
        statact.setChecked(True)  # 設定預設選中
        statact.triggered.connect(self.menu)
        bar_menu.addAction(statact)
    def menu(self, state):
        if state:
            print("勾選後執行的事件")  # 勾選了
        else:
            print("取消勾選執行的事件")  # 取消勾選

QAction()中,checkable=True表示可以勾選的動作。

5)右鍵欄

滑鼠懸浮再視窗上,右擊開啟的選單欄,此功能需要重寫父類中contextMenuEvent()方法,看下程式碼演示。

    def contextMenuEvent(self, event):
        rightmenu = QMenu(self)  # 建立一個下拉選單
        # 新增動作
        d = rightmenu.addAction("列印")
        q = rightmenu.addAction("退出")
        ture = rightmenu.addAction("確定")
        action = rightmenu.exec_(self.mapToGlobal(event.pos()))  # exec_()顯示選單。獲取動作行為
        if action == d:
            self.btn()
        elif action == q:
            qApp.quit()  # 關閉視窗
        else:
            print("無確定內容")

6)工具欄

工具欄可以理解為是多個動作的集合,可以將多個QAction()新增展示出來。

    def bar_tool(self):  # 多個動作集合
        action = QAction("工具1",self)
        action2 = QAction("工具2",self)
        action.setStatusTip("點選退出")
        action.triggered.connect(qApp.quit)
        toolbat = self.addToolBar("工具欄")  # 建立一個工具欄
        toolbat.addAction(action)  # 將動作新增到工具欄
        toolbat.addAction(action2)  # 將動作新增到工具欄

7)主視窗顯示

這個就不做過多介紹,在初始__init__中呼叫上訴幾種方法即可,預設選單欄在最頂部,新增的動作會更加呼叫的先後從左到右排列,工具欄預設在選單欄下發,這裡只看下效果截圖。

9.頁面佈局

1)座標佈局

PyQt5 GUI程式設計
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QLabel, QApplication, QWidget


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')
        q1 = QLabel("quit", self)
        q2 = QLabel("quit2", self)
        q3 = QLabel("quit3", self)
        q1.move(20, 20)  # 座標佈局
        q2.move(20, 80)  # 座標佈局
        q3.move(20, 140)  # 座標佈局


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
座標佈局

上述中透過move(x, y)方法來設定qlable的位置

2)介面比例佈局

PyQt5 GUI程式設計
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QWidget


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.button()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')

    def button(self):  # 比例佈局
        ok = QPushButton("ok")  # 建立三個按鈕
        cancel = QPushButton("cancel")
        cancel1 = QPushButton("cancel1")

        hbox1 = QHBoxLayout()  # 建立一個水平佈局
        hbox1.addWidget(ok)  # 新增按鈕到水平佈局中
        hbox1.addStretch(1)  # 設定水平比例間距

        hbox1.addWidget(cancel)  # 新增按鈕到水平佈局中
        hbox1.addStretch(1)  # 設定水平比例間距
        hbox1.addWidget(cancel1)
        hbox1.addStretch(6)

        self.setLayout(hbox1)  # 新增到佈局器


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
水平佈局

上面程式碼中透過QHBoxLayout() 建立一個水平佈局,addWidget()將按鈕新增到佈局中,再透過addStretch()來設定比例間距,可以看到設定的比例為1:1:6

PyQt5 GUI程式設計
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QVBoxLayout, QWidget


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.button()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')

    def button(self):  # 比例佈局
        ok = QPushButton("ok")  # 建立三個按鈕
        cancel = QPushButton("cancel")
        cancel1 = QPushButton("cancel1")

        hbox = QHBoxLayout()  # 建立一個水平佈局
        hbox.addStretch(1)  # 設定水平比例間距(只設定一個stretch,會將按鈕擠到最右側。若stretch寫在addWidget下面,則按鈕會被寄到最左側)
        hbox.addWidget(ok)  # 新增按鈕到水平佈局中
        hbox.addWidget(cancel)

        vbox = QVBoxLayout()  # 建立一個垂直佈局
        vbox.addStretch(1)  # 設定垂直比例間距(只設定一個stretch,會將按鈕擠到最下面。若stretch寫在addlayout下面,則按鈕會被寄到最下面)
        vbox.addLayout(hbox)  # 將剛剛建立的水平佈局新增到垂直佈局中

        self.setLayout(vbox)  # 將垂直佈局加到佈局器中(按鈕位於頁面右下角)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
垂直佈局

3)柵格化佈局

PyQt5 GUI程式設計
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QGridLayout


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.Grid()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')

    def Grid(self):  # 柵格化的按鈕
        grid = QGridLayout()  # 建立一個柵格化佈局
        name = ["7", "8", "9", "/",
                "4", "5", "6", "x",
                "1", "2", "3", "-",
                "清除", "0", ".", "="]
        # 列表推導式
        pos = [(x, y) for x in range(4) for y in range(4)]
        for names, p in zip(name, pos):  # 同時迭代兩個序列
            button = QPushButton(names)  # 建立按鈕
            grid.setSpacing(10)  # 設定各個單元格之間的間距
            grid.addWidget(button, *p)  # 新增到柵格化佈局中
        self.setLayout(grid)  # 將柵格化佈局加到佈局器


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
柵格化佈局

效果圖

柵格化佈局理論上也是透過座標來定位的,透過列表推導式可到得到幾個座標(0,0)(0,1)(0,2)(1,0)(1,1)(1,2)..........,然後再透過座標去逐個新增。

4)例項

PyQt5 GUI程式設計
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QLabel, QApplication,QWidget, QGridLayout, \
    QLineEdit, QTextEdit


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.input()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')

    def input(self):
        grid = QGridLayout()

        # 設定標籤
        title = QLabel("title")
        Author = QLabel("Author")
        Review = QLabel("Review")

        # 設定輸入框
        titleEdit = QLineEdit()  # 行編輯
        authorEdit = QLineEdit()
        reviewEdit = QTextEdit()  # 文版編輯

        grid.setSpacing(10)  # 設定間距

        grid.addWidget(title, 0, 0)
        grid.addWidget(titleEdit, 0, 1)
        grid.addWidget(Author, 1, 0)
        grid.addWidget(authorEdit, 1, 1)
        grid.addWidget(Review, 2, 0)
        grid.addWidget(reviewEdit, 2, 1)

        self.setLayout(grid)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
例項

上述中例項透過QGridLayout()來將QLabel(), QLineEdit(行編輯) ,QTextEdit(文版編輯) 進行的整合使用,下面看下結果。

四.例項

以一個簡單計算器功能為例,先來看下程式碼實現和效果展示

PyQt5 GUI程式設計
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QGridLayout, \
    QLineEdit


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.Grid()

    def initUI(self):
        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle('Statusbar')

    def Grid(self):  # 柵格化的按鈕
        grid = QGridLayout()
        hbox = QLineEdit()
        grid.addWidget(hbox, 0, 0, 1, 4)
        name = [
            "7", "8", "9", "/",
            "4", "5", "6", "*",
            "1", "2", "3", "-",
            "清除", "0", ".", "="]
        # 列表推導式
        pos = [(x, y) for x in range(1,5) for y in range(4)]
        for names, p in zip(name, pos):  # 同時迭代兩個序列
            if names == "":
                continue
            elif names == "hbox":
                grid.addWidget(hbox, *p)
            else:
                button = QPushButton(names)
                grid.addWidget(button, *p)
                button.clicked.connect(lambda checked, btn_text=names: on_button_clicked(btn_text))
            grid.setSpacing(10)  # 設定各個單元格之間的間距

        self.setLayout(grid)

        def on_button_clicked(btn_text):
            try:
                if btn_text == "清除":
                    hbox.clear()
                elif btn_text == "=":
                    str_num = eval(hbox.text())
                    hbox.clear()
                    hbox.insert(str(str_num))
                else:
                    hbox.insert(btn_text)
            except:
                hbox.insert("error")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
計算器

使用addWidget將輸入框新增到柵格化佈局中,後面無個引數分別表示:(新增物件,x位置,y位置,佔據的單元格高度,佔據的單元格寬度)。

grid.addWidget(hbox, 0, 0, 1, 4)

QLineEdit()幾個常用的方法

        hbox = QLineEdit()
        hbox.setText("預設文案")  # 設定預設文案
        hbox.setPlaceholderText("暗文")  # 當輸入框內容為空時顯示該文案
        hbox.insert("243")  # 新增
        print(hbox.text())  # 獲取框內容
        hbox.clear()  # 清空

五.打包

可參考:https://www.cnblogs.com/lihongtaoya/p/17349911.html

文章來源:https://www.cnblogs.com/lihongtaoya/ ,請勿轉載

相關文章