汪群超 Chun-Chao Wang

Dept. of Statistics, National Taipei University, Taiwan

Qt Designer 設計概念及與 PyQt 結合的技術(一)

本單元起,必須安裝 Qt Designer 作為設計 GUI 的布局之用。安裝 Qt Designer 最簡便的方式:

在 Python 環境: > pip install pyqt6-tools
當然,之前必須先安裝 PyQt6 (> pip install pyqt6)。安裝完 pyqt6_tools 之後的 Designer 應用程式會被安置在 python 下的路徑。譬如,C:\Users\...\AppData\Local\Programs\Python\Python39\Lib\site-packages\qt6_applications\Qt\bin\designer.exe
為方便未來使用,可以為 designer.exe 建立桌面捷徑。

在 Anaconda 環境:在之前的單元安裝過 pyqt 之後,已經在 Anaconda 的路徑上安裝了 Designer,請循線找到 Designer (譬如在 Mac 的路徑:/Users/your_user_name/opt/anaconda3/bin/)。

在某些情況下,安裝 pyqt6-tools 或甚至降到 pyqt5-tools 不成功者,可以只安裝獨立的 Qt Designer 軟體。下載點:https://build-system.fman.io/qt-designer-download

Objective:

  1. 學習如何使用 Qt Designer 設計 Python GUI 應用程式的介面。
  2. 學習如何將設計好的介面檔案(*.ui)與 Python 主檔案(*.py)結合,並能操控元件之間的互動。
Qt Designer 為開發 GUI 程式介面應用軟體,為開發 Qt 的公司 Digia 的產品,透過 PyQt6 或 PySide6 並結合繪圖的 pyqtgraph 成為 Python GUI 的主流開發工具。

Prerequisite:

  1. Lesson 1, 2 的觀念與技術。
  2. 查詢與閱讀手冊的能力。

範例 1:使用 Designer 設計一個簡單的 GUI,視窗如下右圖。

使用元件:comboBox, lineEdit, label, pushbutton

注意事項:

  1. 下載本範例使用的 PyQtDesigner_1.ui 檔案 (解壓縮後,移到程式所在的目錄)

  2. 前一個單元刻意使用指令來佈建 GUI,屬於後臺編輯的概念,對一般初學者而言,門檻太高,不易親近,只適合解說 GUI 程式的概念與動線流程。Qt Designer 則是提供接近前台編輯的介面,讓設計者專心於元件的佈建,只需拖曳、安排、設定 properties 即可輕鬆完成複雜的 GUI 視窗。接著再交由 python 程式串聯元件之間的溝通與功能的呈現。也就是,設計者應該將大部分的時間花在這裡,而不是被元件佈建的瑣碎細節所牽絆。

  3. GUI 應用程式牽涉到使用者介面(Graphical User Interface)的設計與程式撰寫,兩方面都需要足夠的經驗,才能完成一個堪用的軟體。而獲取經驗的方式,便是不斷地練習、模仿與創作自己心目中想製作的應用軟體。

  4. 在此無法詳述 Designer 的設計細節,只能透過上課的實作演練去熟悉 Designer 的環境,多做練習,很快便能上手。

  5. 本範例刻意與前一單元的範例三相同,呈現兩種不同的做法。因此元件的變數名稱都設定相同,使前一個範例的大部分程式碼能在此直接使用。兩個程式最大的差異在元件的建立、特性的設定。利用 Designer 設計的 GUI 程式以 *.ui 為副檔名,內涵元件佈建的指令。在下列程式中,被 load 進來,成為程式的一部分。指令為 ui.loadUi(‘檔名’, self)。在此,檔名為 PyQtDesigner_1.ui

  6. 讀者可以比對下列程式碼與前一單元範例三的程式碼,便能理解 Designer 的作用。

from PyQt6 import QtWidgets, uic
import sys

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        #Load the UI Page by PyQt6
        uic.loadUi('PyQtDesigner_1.ui', self)
        self.setWindowTitle('Add more components')
        
        # signal
        self.go_button.clicked.connect(self.go)
    
    # slot
    def go(self):
        str1 = self.greeting.currentText()
        str2 = self.recipient.text()
        self.greet_rep.setText(str1 + ' ' + str2)

def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

練習:使用 Designer 設計如下右圖的 GUI 介面。

內容取自 PyQt6 Tutorial / Creating applications with Qt Designer (有製作過程影片與文字說明)

注意事項:

  1. 下圖的 GUI 設計只是練習排列的技巧,label 的文字或其他元件的內容並不重要。建立視窗時,採 Dialog 模式,自動具備最下面的兩個按鈕。

  2. 這個練習的重點是利用現成的布局功能,將多個元件迅速地排列整齊。而非手動一一對齊。

  3. 請先看完製作過程的影片,再自行模仿一次。這裡牽涉到好幾個布局的技巧,非常值得收藏。

  4. 下圖右側的 Note 將幾個重點題列出來,方便迅速提醒。


範例 2:使用 Designer 設計如下右圖的 GUI 視窗。這是個簡單的圖形展示工具,透過 comboBox 元件選擇欲呈現的圖形,並將圖形呈現在 label 元件,順便置換上面的文字。

使用元件:comboBox, label, pushbutton

注意事項:

  1. 下載本範例之 ui 檔。在使用現成的 ui 檔前,試著先自己從 Designer 製作如下圖的 GUI 檔案。各元件的名稱可以從程式中找到。

  2. 在應用程式上呈現各種圖片是常見的應用。有些圖片只做裝飾或單純呈現,有些則是作為分析圖像的之用。若是前者,通常以 label 元件呈現圖片,如本範例;若是後者,則採 pyqtgraph 的繪圖方式。

  3. 本範例的主角是兩個 signal,一個藉由 comboBox 啟動圖形之開啟與貼上,另一個則是透過 EXIT 按鈕關閉視窗。初學者要掌握的是元件的啟動條件是甚麼?譬如,comboBox 依據選項的改變而啟動,這個機制叫做:currentIndexChanged 後面連接 connect(slot 函數)。另外,按鈕的部分則是 clicked,在前面的單元已經練習過了。

  4. 另一個值得參考的重點是,comboBox 引動的 slot 函數 showImg(slef, s),除了第一個必備的參數 self 之外,還附上第二個取名為 s 的參數。但 signal 呼叫端只是單純的 connect(showImg),並沒有給任何參數。原來,這個額外的參數是 comboBox 自動給出的。那麼 s 的內容是甚麼呢?是選項的數字?還是文字?遇上這種不確定的場合,可以在下面用 print(s) 觀察,或啟動 debug 機制來觀看。

  5. 另,Slot 函數裡第二個指令處裡兩件事:第一、從 comboBox 取得目前被選取的項目的文字(請注意,這裡故意採用與範例 1 不同的 method);第二、將該文字寫在最上面的 label。相關的用法不難直接從指令中窺探。

  6. 這個範例需要準備幾張圖片。下列程式的寫法,是假設所有圖片都放在上一層的目錄:../images/ 之下。圖檔名與其排列都是先安排在 self.picName 變數裡面。

  7. 本範例雖有兩個 signal,卻只有一個對應的 slot,因為 EXIT 按鈕的目的是關閉視窗,因此直接在 signal 處,呼叫關閉視窗的指令,即 self.close。

  8. 這裡也利用 label 元件製作一個超連結,點選後會打開瀏覽器連結到該網頁。製作方式有兩種:若是固定網址,則可以在 Designer 的該 label 屬性編輯器的 text 填入超連結的 HTML 語法,譬如最簡潔的語法為 https://new.ntpu.edu.tw,當然也可以加油添醋做一些表現。接著在 openExternalLinks 的選像打勾,代表會在外面瀏覽器開啟網頁。以上的動作也可以在程式中表達,因此適合網址在設計階段還未知的情況。詳細程式碼如下,在 #Signals 前面被註解的三行。

  9. 本範例的 GUI 視窗最下面還放了一個 Text Broswer 的元件,作為提醒讀者還有哪些功能可以隨後加上,作為後續練習與精進之用。這個文字元件以 Browser 為名,代表可以使用 html 語法,以展現更多元的多媒體表現。

from PyQt6 import QtWidgets, uic
from PyQt6.QtGui import QPixmap
import sys

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.picName = ["NTPU_Campus_1", "NTPU_Campus_2", "NTPU_Campus_3"]

        #Load the UI Page by PyQt6
        uic.loadUi('PyQtDesigner_2.ui', self)
        self.setWindowTitle('Show images on the label widget')
        #url = "https://new.ntpu.edu.tw/"
        #self.label_ntpu.setText(f'<a style="text-decoration: none" href="{url}">{url}</a>')# should have quotes around url, i.e. href="https://...."
        # self.label_ntpu.setOpenExternalLinks(True) # can be set True in Designer

        # Signals
        self.comboBox_ImgName.currentIndexChanged.connect(self.showImg)
        self.pBut_exit.clicked.connect(self.close)

# Slots
    def showImg(self, s):
        self.label_Img.setPixmap(QPixmap(u"../images/" + self.picName[s]))
        self.label_cap.setText(self.comboBox_ImgName.itemText(s)) # set Label text
        # self.label_cap.setText(self.comboBox_ImgName.currentText())
    
def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

練習:模仿上個範例的做法,製作如下圖的應用程式。


注意事項:

  1. 很明顯的,這是個圖片瀏覽器。四個按鈕各有功能,因此必須啟動四個 signal,不過功能的差異只在第幾張圖,也許可以共用 slot 函數。

  2. 多準備幾張圖,讓這個應用程式用起來很像樣。

  3. 在範例程式碼中,儲存圖片檔案採取 hard copy 的方式:self.picName = [“NTPU_Campus_1”, “NTPU_Campus_2”, “NTPU_Campus_3”],這在圖片很多的情況下,是不可行的。下列程式碼介紹正規的作法。假設所有的圖片都放在與程式檔所在目錄平行的目錄 images,則圖片檔名可以這樣取得:

 import os
...
        self.file_src = "../images/"
        self.picName = os.listdir(self.file_src)
...
商學院  7F16
ccw@gm.ntpu.edu.tw
(02)8674-1111 
ext 66777

部落格統計

  • 99,322 點擊次數
%d bloggers like this: