痞子衡嵌入式:超級好用的視覺化PyQt GUI構建工具(Qt Designer)
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是 PyQt GUI構建工具Qt Designer 。
痞子衡開部落格至今已有好幾年,一直以嵌入式開發相關主題的文章為主線,偶爾穿插一些其他技術或工具的介紹,前段時間因為要做一個跟恩智浦MCU啟動相關的上位機工具 NXP-MCUBootUtility ,網上搜索對比了幾個Python下的GUI框架,最終選擇了wxPython這個成熟穩定的GUI庫,從而接觸到wxFormBuilder這個配套wxPython使用的GUI構建工具。苦於網上關於該構建工具的中文資料不多,所以根據自己使用經驗寫了一篇 極易上手的視覺化wxPython GUI構建工具(wxFormBuilder) ,沒想到該篇部落格很受歡迎,居然目前是痞子衡部落格裡閱讀量最高的一篇部落格,而且也是搜尋 wxFormBuilder 關鍵字出來的中文結果排名第二位的連結,真是萬萬沒想到。
wxPython框架雖然成熟穩定,但是相對最近更火的PyQt框架來說,還是顯得古老了一些,控制元件風格不符合現代審美觀,因此痞子衡決定學習一下PyQt的用法,感受下PyQt做出來的介面效果到底如何。根據wxPython學習經驗,當然首先要從PyQt的視覺化GUI構建工具Qt Designer開始下手,因此便有了本篇部落格。
一、Qt Designer工具背景
Qt Designer從名字上來看顯然就是久負盛名的跨平臺GUI庫Qt的配套設計工具。Qt庫本身是C++語言實現的;Riverbank公司用Python語言對Qt做了一層封裝,封裝後便成了Python版GUI庫PyQt(目前最新的版本是PyQt5);下面是這兩個GUI庫的官方主頁:
- Qt專案官方網站: https://www.qt.io/
- PyQt專案官方主頁: https://www.riverbankcomputing.com/software/pyqt/intro
Qt的各種UI控制元件功能均是通過class來實現的,這個連結 https://doc.qt.io/qt-5/classes.html 列出了Qt裡的所有class。PyQt5其用法基本與Qt一致,這個連結 https://www.riverbankcomputing.com/static/Docs/PyQt5/module_index.html#ref-module-index 列出了PyQt5裡所有的Modules,其中用於設計介面最常用的便是 QtWidgets 模組。
在Qt官網的Tools下面可以看到所有Qt相關的工具,在UI design tools下面可以找到Qt Designer,可見Qt Designer是用於設計GUI介面的工具之一。由於痞子衡介紹的PyQt5下的GUI構建工具,因此本文的Qt Designer並不是直接在Qt官網下載安裝的,具體安裝方法詳見下一章節。
二、Qt Designer快速上手
使用Qt Designer去設計GUI介面可以不用掌握PyQt5裡的各個控制元件class的具體用法,你只需要在Qt Designer軟體裡新增這些控制元件即可,下面痞子衡將簡介Qt Designer的用法:
2.1軟體安裝
簡單瞭解PyQt5的module和class便可以開始設計GUI介面,首先得安裝Qt Designer,在安裝完Python3之後(痞子衡安裝的是Python 3.6),藉助\Python36\Scripts\下的pip.exe工具來分別安裝PyQt5和Qt Designer,命令見如下主頁:
- PyQt5安裝: https://pypi.org/project/PyQt5/
- Qt Designer安裝: https://pypi.org/project/pyqt5-tools/
安裝完成之後開啟\Python36\Lib\site-packages\pyqt5_tools\designer.exe,這便是Qt Designer。
2.2軟體介面
開啟Qt Designer可見到如下介面,介面主要分為四大區:專案區、控制元件區、編輯區、屬性區。軟體使用起來非常簡單,就是在【控制元件區】裡點選新增需要的控制元件,這些控制元件的效果會在【編輯區】裡實時顯示,並在【屬性區】這些控制元件的屬性,【專案區】用於顯示控制元件間的層級關係。
2.3基礎佈局
讓我們開始建立一個GUI的基礎框架,基礎框架包括:Container(區域性外圍輪廓)、Layout(內部控制元件區)、menubar(頂部選單欄)、statusbar(底部狀態列)。
第一步是新增一個Container(此處選擇常用的Frame),這是GUI的輪廓基礎,有了Frame之後還需要在Frame裡新增Layout(此處選擇豎排樣式),用於規範後續控制元件的排列樣式。預設GUI即有menubar和statusbar。
2.4多種控制元件
基礎佈局搞定之後,接下來便是在Layout裡新增控制元件,PyQt5支援的控制元件非常豐富,其中比較常用的是如下幾個:各種Button(按鈕)、Label(靜態顯示文字框)、Text Edit(輸入輸出文字框)、Check Box(選中框)、各種Slider(滑動條)等。由於前面痞子衡選擇的是verticalLayout,因此你會看到控制元件們都是豎著排的。
2.5控制元件屬性
添加了所有控制元件之後,下一步便是分別設定控制元件的屬性,進一步調整控制元件。痞子衡以Push Button屬性為例,痞子衡勾選瞭如下3項比較重要的屬性設定,分別是objectName(button在後續python程式碼的物件名,一般需要按其功能修改,修改後使得程式碼閱讀/修改起來更直觀)、geometry(設定button的尺寸與位置,如果是放在Layout裡,則受限於Layout不可設定)、text(button在GUI裡顯示的標籤名,此處是PushButton,也需要按其功能修改,方便使用者使用軟體)。
2.6儲存為xml程式碼(工程檔案)
當GUI介面佈局全部完成之後,需選擇File->Save As儲存為.ui檔案,該檔案既是Qt Designer的工程檔案也是最終生成的GUI xml程式碼檔案,痞子衡儲存在了my_win.ui檔案裡。
2.7轉換成python程式碼
雖然儲存的my_win.ui檔案裡是可以直接在python程式碼裡被載入使用的,但是更好的辦法是直接將.ui檔案轉換成相應的.py檔案。需要藉助 \Python36\Scripts\pyuic5.exe工具,命令如下:
pyuic5 - o my_win.py my_win.ui
轉換成功後,讓我們開啟my_win.py檔案,可以簡單看一下這個my_win.py裡的內容,程式碼裡首先import了PyQt5相關庫,並定義了名為Ui_MainWindow的class,這個class主要包含兩個函式setupUi()和retranslateUi()。setupUi()裡初始化了各個控制元件成員self.xx,這與我們在Qt Designer裡新增控制元件是對應的。
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file '.\my_win.ui' # # Created by: PyQt5 UI code generator 5.11.3 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(603, 448) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.frame = QtWidgets.QFrame(self.centralwidget) self.frame.setGeometry(QtCore.QRect(100, 80, 361, 211)) self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame.setFrameShadow(QtWidgets.QFrame.Raised) self.frame.setObjectName("frame") self.verticalLayoutWidget = QtWidgets.QWidget(self.frame) self.verticalLayoutWidget.setGeometry(QtCore.QRect(30, 20, 160, 172)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.pushButton = QtWidgets.QPushButton(self.verticalLayoutWidget) self.pushButton.setEnabled(True) self.pushButton.setObjectName("pushButton") self.verticalLayout.addWidget(self.pushButton) self.label = QtWidgets.QLabel(self.verticalLayoutWidget) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) self.textEdit = QtWidgets.QTextEdit(self.verticalLayoutWidget) self.textEdit.setObjectName("textEdit") self.verticalLayout.addWidget(self.textEdit) self.checkBox = QtWidgets.QCheckBox(self.verticalLayoutWidget) self.checkBox.setObjectName("checkBox") self.verticalLayout.addWidget(self.checkBox) self.horizontalSlider = QtWidgets.QSlider(self.verticalLayoutWidget) self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal) self.horizontalSlider.setObjectName("horizontalSlider") self.verticalLayout.addWidget(self.horizontalSlider) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 603, 21)) 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 retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton")) self.label.setText(_translate("MainWindow", "TextLabel")) self.checkBox.setText(_translate("MainWindow", "CheckBox"))
三、使用Qt Designer生成的程式碼
前面已經使用Qt Designer生成GUI介面類Ui_MainWindow並儲存在my_win.py檔案中,此時需要建立一個主函式檔案去呼叫Ui_MainWindow,下面是痞子衡建立的main_win.py中的程式碼:
import sys from PyQt5.QtWidgets import QApplication, QMainWindow # 匯入my_win.py中內容 from my_win import * # 建立mainWin類並傳入Ui_MainWindow class mainWin(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(mainWin, self).__init__(parent) self.setupUi(self) if __name__ == '__main__': # 下面是使用PyQt5的固定用法 app = QApplication(sys.argv) main_win = mainWin() main_win.show() sys.exit(app.exec_())
3.1觸發事件與響應
有了Button,我們肯定希望其能與一個響應函式相聯絡起來,此處痞子衡定義了showMessage()函式,並且將showMessage()與PushButton繫結起來,點選Button便會執行一次這個showMessage()函式。程式碼如下:
class mainWin(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(mainWin, self).__init__(parent) self.setupUi(self) # 將響應函式繫結到指定Button self.pushButton.clicked.connect(self.showMessage) # Button響應函式 def showMessage(self): self.textEdit.setText('hello world')
最後讓我們測試一下這個GUI軟體,在命令列下執行main_win.py
PS D:\my_git_repo\> python .\main_win.py
至此,PyQt5 GUI構建工具Qt Designer痞子衡便介紹完畢了,掌聲在哪裡~~~