INFOR38th 學術 葉倚誠

2025 IZCC 四校聯合暑訓:夏夜晚楓建景成

  • INFOR 38th 學術

  • 暑訓執祕之一

講師:葉倚誠 (Ethan Yeh)

課程大綱

PyQt 簡介

命令列介面 (CUI)

圖形使用者介面 (GUI)

通過鍵盤輸入指令,電腦接收後執行

使用者透過圖形元件與電腦互動

CUI vs. GUI

PyQt 是什麼?

  • Python 的跨平臺 GUI 框架

  • Qt (C++ 函式庫) 的分支

  • 提供各種元件用於製作各種工具、遊戲等

  • 相較 Tkinter 更為美觀且現代化的介面

  • 可搭配 Qt Designer 更觀地完成設計

PyQt5 vs. PyQt6

PyQt5 PyQt6
穩定版本 最新版本
支援 Python2.7 以上、Python3 僅支援 Python3.6 以上
支援 .exec_()、.exec() 僅支援 .exec()
支援 Qt's resource 支援 Qt's resource,可改用 PyInstaller
非預設使用 HiDPI 預設使用 HiDPI

環境架設

  1. Visual Studio Code (文字編輯器)

  2. Python 3

  3. PyQt5 / PyQt6

  4. Qt Designer

或任何你習慣的 IDE (整合開發環境)!如 PyCharm、Visual Studio 等

Visual Studio Code

下載連結:Visual Studio Code

前往官網載點下載安裝程式

一直按下一步就安裝完成了!

Python 3

下載連結:Python 

前往官網載點下載安裝程式

記得打勾 Add Python 3.X to PATH

註:電教電腦皆以安裝 Python,故不必重複安裝

PyQt5 / PyQt6

建立專案資料夾

按下 Ctrl + ` 開啟終端機 (Terminal)

輸入以下指令

pip install pyqt6

Qt Designer

下載連結:Qt Designer

前往官網載點下載安裝程式

一直按下一步就安裝完成了!

基礎元件

QWidget

  • PyQt 中最基本的 GUI 元件,為所有其它元件的基礎
  • 可以作為視窗或其他元件的容器
from PyQt6 import QtWidgets
import sys # 系統相關

app = QtWidgets.QApplication(sys.argv)  # 建立應用程式
window = QtWidgets.QWidget()  # 建立視窗

window.show()  # 顯示視窗
sys.exit(app.exec())  # 執行應用程式

QLabel

- 標籤 -

setText() / text() 設定/存取文字
setAlignment() 設定文字對齊方式
label.setWordWrap() 開關自動換行
setFont(QFont()) 設定字型
setStyleSheet() 設定樣式
setPixmap(QPixmap())  設定圖片
setGeometry() 設定位置/大小
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
from PyQt6.QtGui import QFont  # 字型模組
from PyQt6.QtCore import Qt
import sys

app = QApplication(sys.argv)  # 建立應用程式
window = QWidget()  # 建立視窗

label1 = QLabel(window)  # 建立標籤
label1.setText("夏夜晚楓建景成")  # 設定標籤文字
label1.setAlignment(Qt.AlignmentFlag.AlignCenter)  # 設定文字對齊方式
label1.setFont(QFont("Arial", 20))  # 設定字型
label1.setGeometry(50, 50, 300, 100)  # 設定大小/位置
label1.setStyleSheet(
    """
    color: rgb(255, 0, 0);
    background-color: rgb(255, 255, 0);
    border: 10px solid black;
"""
) # 設定樣式

window.show()  # 顯示視窗
sys.exit(app.exec())  # 執行應用程式

QPushButton

- 按鈕 -

setIcon(QIcon()) 設定圖標
setEnabled() 開關按鈕
setVisible() 設定按鈕可見性
setDefault() 設為預設按鈕 (使用 Enter 鍵控制)
clicked.connect() 連結按鈕點擊事件
pressed.connect() / released.connect() 連結按鈕按下/釋放點擊事件
setPixmap(QPixmap())  設定圖片
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton
from PyQt6.QtGui import QFont
import sys

app = QApplication(sys.argv) 
window = QWidget()  
button1 = QPushButton("Click Me", window)  # 建立按鈕
button1.setFont(QFont("Arial", 20))
button1.setGeometry(50, 50, 300, 100)
button1.setEnabled(True)  # 啟用按鈕
button1.setVisible(True)  # 設定按鈕可見性
button1.setDefault(True)  # 設定為預設按鈕
button1.setStyleSheet(
    """QPushButton:hover {
    font-size: 40px;
    background-color: lightblue }"""
)  # 設定樣式

button1.clicked.connect(lambda: print("Button clicked!"))  # 連結按鈕點擊事件
button1.pressed.connect(lambda: print("Button pressed!"))  # 連結按鈕按下事件
button1.released.connect(lambda: print("Button released!"))  # 連結按鈕釋放事件

window.show() 
sys.exit(app.exec())

QRadioButton

- 單選按鈕 -

setChecked() 設定預設狀態
toggled.connect() 連結狀態改變事件
clicked.connect() 連結選中事件

- 按鈕群組 -

 QButtonGroup 建立按鈕群組
addButton 綁定按鈕
buttonClicked.connect() 連結群組中按鈕點擊事件
from PyQt6.QtWidgets import QApplication, QWidget, QRadioButton, QButtonGroup
from PyQt6.QtGui import QFont
import sys

app = QApplication(sys.argv)
window = QWidget()

rb1 = QRadioButton("A", window)  # 建立單選按鈕
rb1.setFont(QFont("Arial", 20))
rb1.setGeometry(50, 50, 100, 50)
rb2 = QRadioButton("B", window)
rb2.setFont(QFont("Arial", 20))
rb2.setGeometry(50, 120, 100, 50)

group = QButtonGroup(window)  # 建立按鈕群組
group.addButton(rb1)  # 將按鈕加入群組
group.addButton(rb2)  # 將按鈕加入群組
group.buttonClicked.connect(lambda btn: print(btn.text()))  # 列印選中的按鈕文字

window.show()
sys.exit(app.exec())

QCheckBox

- 複選按鈕 -

from PyQt6.QtWidgets import QApplication, QWidget, QCheckBox, QButtonGroup
from PyQt6.QtGui import QFont
import sys

app = QApplication(sys.argv)
window = QWidget()

cb1 = QCheckBox("A", window)  # 建立複選按鈕
cb1.setGeometry(10, 10, 100, 30)
cb2 = QCheckBox("B", window)
cb2.setGeometry(10, 50, 100, 30)
cb3 = QCheckBox("C", window)
cb3.setGeometry(10, 90, 100, 30)

group = QButtonGroup(window)
group.addButton(cb1)
group.addButton(cb2)
group.addButton(cb3)
group.buttonClicked.connect(lambda btn: print(btn.text()))  # 列印選中的按鈕文字

window.show()
sys.exit(app.exec())

QLineEdit

- 單行輸入框 -

setPlaceholderText() / placeholderText() 設定/存取提示文字
setEchoMode() 設定顯示模式
setReadOnly() 設定唯讀模式
setMaxLength() 設定最大字元數
setFocus() 設定為焦點
textChanged.connect() 連結文字改變事件
editingFinished.connect() 連結編輯完成事件
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit
import sys

app = QApplication(sys.argv)
window = QWidget()

label1 = QLabel(window)
label1.setGeometry(10, 10, 100, 30)
box1 = QLineEdit(window)
box1.setGeometry(120, 10, 200, 30)
box1.setPlaceholderText("請輸入文字")  # 設定提示文字
box1.setEchoMode(QLineEdit.EchoMode.Password)  # 設定為密碼模式
box1.setReadOnly(False)  # 關閉唯讀模式
box1.setMaxLength(20)  # 設定最大字元數為 20

box1.textChanged.connect(lambda: label1.setText(box1.text()))  # 文字編輯時改變標籤內容
box1.editingFinished.connect(lambda: print(box1.text()))  # 編輯完成時列印文字

window.show()
sys.exit(app.exec())

QPlainTextEdit

- 多行輸入框 -

setPlainText() / toPlainText 設定/存取文字
insertPlainText() 在游標處插入文字
appendPlainText(str) 在文末插入文字
setTabStopDistance() 設定 Tab 鍵距離
setLineWrapMode() 開關自動換行
setMaximumBlockCount() 設定最大行數
blockCountChanged.connect() 連結行數改變事件
from PyQt6.QtWidgets import QApplication, QWidget, QPlainTextEdit
import sys

app = QApplication(sys.argv)
window = QWidget()

box1 = QPlainTextEdit(window)
box1.setGeometry(10, 10, 300, 200)
box1.setPlainText("Hello!")
box1.setTabStopDistance(40)  # 設定 Tab 鍵的距離為 40 像素
box1.setLineWrapMode(
    QPlainTextEdit.LineWrapMode.WidgetWidth
)  # 在超過寬度限制時自動換行
box1.setMaximumBlockCount(10)  # 設定最大行數 10

box1.blockCountChanged.connect(
    lambda: print(box1.toPlainText())
)  # 行數改變時列印文本內容

window.show()
sys.exit(app.exec())

QListWidget

- 多行輸入框 -

addItem() / addItems() 加入選項
takeItem() / removeItemWidget() 存取/刪除選項
insertItem(index, item) 在指定索引值插入選項
currentItem().text() / row() / column() 選中選項的文字/列數/欄數
clicked.connect() 連結選項點擊事件
currentItemChanged.connect() 連結選中選項改變事件
setFlow() 設定排列方式
from PyQt6.QtWidgets import QApplication, QWidget, QListWidget
import sys

app = QApplication(sys.argv)
window = QWidget()

list1 = QListWidget(window)
list1.setGeometry(10, 10, 200, 300)
list1.addItems(["A", "B", "C"])  # 加入 A, B, C 選項
list1.insertItem(1, "D")  # 在索引值 1 處插入 D 選項

list1.clicked.connect(
    lambda: print(list1.currentItem().text())
)  # 點擊時列印選中選項的文字

window.show()
sys.exit(app.exec())

基礎元件:多媒體

QLabel

- 標籤(圖片) -

from PyQt6.QtWidgets import QApplication, QWidget, QLabel
from PyQt6.QtGui import QPixmap
import sys

app = QApplication(sys.argv)  # 建立應用程式
window = QWidget()  # 建立視窗

label1 = QLabel(window)  # 建立標籤
label1.setGeometry(10, 10, 300, 300)  # 設定位置/大小
pixmap = QPixmap("img.jpg")  # 加入圖片
label1.setPixmap(pixmap)  # 設定標籤圖片

window.show()  # 顯示視窗
sys.exit(app.exec())  # 執行應用程式

QGraphView + QGraphicsScene

- 圖片 -

from PyQt6.QtWidgets import QApplication, QWidget, QGraphicsView, QGraphicsScene
from PyQt6.QtGui import QPixmap
import sys

app = QApplication(sys.argv)
window = QWidget()

view = QGraphicsView(window)
view.setGeometry(10, 10, 400, 300)
scene = QGraphicsScene()
scene.setSceneRect(0, 0, 400, 300)  # 設定位置/大小
pixmap = QPixmap("img.jpg")  # 加入圖片
pixmap = pixmap.scaled(300, 300)  # 調整圖片大小
scene.addPixmap(pixmap)
view.setScene(scene)

window.show()
sys.exit(app.exec())

QGraphicsPixmapItem

- 圖片(多張) -

from PyQt6.QtWidgets import QApplication, QWidget, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PyQt6.QtGui import QPixmap
import sys

app = QApplication(sys.argv)
window = QWidget()

view = QGraphicsView(window)
view.setGeometry(10, 10, 400, 300)
scene = QGraphicsScene()
scene.setSceneRect(0, 0, 400, 300)  # 設定位置/大小

pixmap1 = QPixmap("img.jpg")  # 加入圖片
item1 = QGraphicsPixmapItem(pixmap1)
item1.setPos(50, 50)  # 設定位置
scene.addItem(item1)
pixmap2 = QPixmap("img1.jpg")
item2 = QGraphicsPixmapItem(pixmap2)
item2.setPos(200, 50)
scene.addItem(item2)

view.setScene(scene)

window.show()
sys.exit(app.exec())

QPainter.drawImage()

- 圖片 -

from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtGui import QPainter, QImage
from PyQt6.QtCore import QRect
import sys

app = QApplication(sys.argv)  # 建立應用程式
window = QMainWindow()


def draw(self):
    painter = QPainter(window)  # 創建畫家物件
    image = QImage("img.jpg")  # 加入圖片
    painter.drawImage(
        QRect(0, 0, image.size().width(), image.size().height()), image
    )  # 繪製圖片
    painter.end()  # 結束繪製

window.paintEvent = draw  # 設定繪製事件

window.show()  # 顯示視窗
sys.exit(app.exec())  # 執行應用程式

佈局管理

  • 分為垂直/水平佈局

  • 使用 QVBoxLayout() / QHBoxLayout() 建立

  • 在佈局裡的元件會依照佈局規則排列

  • 使用 addWidget() 加入元件

Layout 佈局

from PyQt6.QtWidgets import QVBoxLayout, QHBoxLayout
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
import sys

app = QApplication(sys.argv)
window = QWidget()

layout = QVBoxLayout(window)
label1 = QLabel("Label 1")
layout.addWidget(label1)
label2 = QLabel("Label 2")
layout.addWidget(label2)
label3 = QLabel("Label 3")
layout.addWidget(label3)

window.show()
sys.exit(app.exec())

Layout 對齊方式

QtCore.Qt.AlingmentFlag.AlingTop 靠上對齊
QtCore.Qt.AlingmentFlag.AlingBottom 靠下對齊
QtCore.Qt.AlingmentFlag.AlingCenter 置中對齊
QtCore.Qt.AlingmentFlag.AlingLeft 靠左對齊
QtCore.Qt.AlingmentFlag.AlingRight 靠右對齊
QtCore.Qt.AlingmentFlag.AlingVCenter 垂直置中對齊
QtCore.Qt.AlingmentFlag.AlingHCenter 水平置中對齊
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout
from PyQt6.QtCore import Qt
import sys

app = QApplication(sys.argv)
window = QWidget()

main_layout = QVBoxLayout(window) # 建立主佈局

layout1 = QHBoxLayout()
label1 = QLabel("Label 1")
layout1.addWidget(label1)
label2 = QLabel("Label 2")
layout1.addWidget(label2)
label3 = QLabel("Label 3")
layout1.addWidget(label3)
layout1.setAlignment(Qt.AlignmentFlag.AlignTop)

layout2 = QVBoxLayout()
label4 = QLabel("Label 4")
layout2.addWidget(label4)
label5 = QLabel("Label 5")
layout2.addWidget(label5)
label6 = QLabel("Label 6")
layout2.addWidget(label6)
layout2.setAlignment(Qt.AlignmentFlag.AlignLeft)

main_layout.addLayout(layout1)
main_layout.addLayout(layout2)

window.show()
sys.exit(app.exec())
  • 建立網格佈局

  • 使用 QGridLayout() 建立

  • 在佈局裡的元件會依照網格位置排列

  • 使用 addWidget(widget, x, y) 加入元件並指定網格位置

QGridLayout

from PyQt6.QtWidgets import QGridLayout
  • 建立表單佈局

  • 使用 QFormLayout() 建立

  • 預設僅有兩個欄位 (QLabel + 單/多行輸入框)

  • 使用 addRow(text, input) 加入一組元件

QFormLayout

from PyQt6.QtWidgets import QFormLayout
QFormLayout.RowWrapPolicy.DontWrapRows 文字在左,輸入框在右
QFormLayout.RowWrapPolicy.WrapLongRows 同上,但自動換行
QFormLayout.RowWrapPolicy.WraoAllRows 文字在上,輸入框在下

排列方式

from PyQt6.QtWidgets import QApplication, QWidget, QFormLayout, QLabel, QLineEdit
from PyQt6.QtCore import Qt
import sys

app = QApplication(sys.argv)
window = QWidget()

layout = QFormLayout(window)

label1 = QLabel("Name:")
line_edit1 = QLineEdit()
label2 = QLabel("Email:")
line_edit2 = QLineEdit()
layout.addRow(label1, line_edit1) # 添加一行
layout.addRow(label2, line_edit2)

layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight) # 設定排列方式

window.show()
sys.exit(app.exec())

Qt Designer

  • 設計 GUI 時,元件管理及佈局很不直觀
  • Qt Designer 是 Qt 框架中的設計工具,可以達成使用 GUI 設計 GUI

Qt Designer 是什麼?

設計結束後可直接轉換成程式碼!

創建 Widget

選擇 Widget 作為基底,並按下 Create

直接拖移左側工具欄中的元件進行設計!

轉換成 .py 程式碼

  1. 按下 Ctrl + S 儲存 .ui 檔案
  2. 終端機輸入以下指令:
pyuic6 -x X.ui -o X.py

3. 轉檔成功!(如右圖)

使用 Qt Designer
可以更快的完成 GUI 的介面設計!

樣式設定

setStyleSheet()

大部分元件都支援的方法,可以使用類似 CSS 的樣式表 (QSS)

/* 基本語法結構 */

選擇器 {
    屬性名稱: 值;
    屬性名稱: 值;
}
label1.setStyleSheet(
    """
    QLabel {
        color: blue;
        font-size: 20px;
        font-weight: bold;
        font-family: Arial;
        background-color: yellow;
        border: 2px solid black;
    }
    QLabel:hover {
        color: red;
        background-color: lightgray;
        border: 2px solid green;
    }
"""
)

偽狀態

觸法某些事件或進行某些行為後才會生效的樣式

:hover 碰到鼠標
:active 發生某些行為 (通常為點擊)
:focus 成為焦點
:checked 被勾選
:disable / :enable 停用/啟用狀態
:selected 被選取

字體屬性

針對內文的顏色、字型等樣式

font-family 字型
font-size 字體大小
font-weight 字體粗細
font-style 字體樣式
text-align 文字對齊
color 文字顏色

背景屬性

針對背景的顏色、等樣式

background-color 背景顏色
background-image 背景圖片
background-position 圖片位置

邊框屬性

針對邊框的顏色、形狀、粗細等樣式

border-width 背景顏色
border-style 背景圖片
border-color 圖片位置
border-radius 圓角半徑
border-top / bottom / left / right 上/下/左/右邊框

常見邊框樣式:solid (實線)、dashed (虛線)、dotted (點狀)、double (雙線)

實作時間

Made with Slides.com