Ethan Yeh
INFOR 38th — 學術
2025 IZCC 四校聯合暑訓:夏夜晚楓建景成
INFOR 38th 學術
暑訓執祕之一
通過鍵盤輸入指令,電腦接收後執行
使用者透過圖形元件與電腦互動
Python 的跨平臺 GUI 框架
Qt (C++ 函式庫) 的分支
提供各種元件用於製作各種工具、遊戲等
相較 Tkinter 更為美觀且現代化的介面
可搭配 Qt Designer 更觀地完成設計
| PyQt5 | PyQt6 |
|---|---|
| 穩定版本 | 最新版本 |
| 支援 Python2.7 以上、Python3 | 僅支援 Python3.6 以上 |
| 支援 .exec_()、.exec() | 僅支援 .exec() |
| 支援 Qt's resource | 支援 Qt's resource,可改用 PyInstaller |
| 非預設使用 HiDPI | 預設使用 HiDPI |
Visual Studio Code (文字編輯器)
Python 3
PyQt5 / PyQt6
Qt Designer
或任何你習慣的 IDE (整合開發環境)!如 PyCharm、Visual Studio 等
下載連結:Visual Studio Code
前往官網載點下載安裝程式
一直按下一步就安裝完成了!
下載連結:Python
前往官網載點下載安裝程式
記得打勾 Add Python 3.X to PATH
註:電教電腦皆以安裝 Python,故不必重複安裝
建立專案資料夾
按下 Ctrl + ` 開啟終端機 (Terminal)
輸入以下指令
pip install pyqt6下載連結:Qt Designer
前往官網載點下載安裝程式
一直按下一步就安裝完成了!
from PyQt6 import QtWidgets
import sys # 系統相關
app = QtWidgets.QApplication(sys.argv) # 建立應用程式
window = QtWidgets.QWidget() # 建立視窗
window.show() # 顯示視窗
sys.exit(app.exec()) # 執行應用程式
- 標籤 -
| 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()) # 執行應用程式
- 按鈕 -
| 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())
- 單選按鈕 -
| 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())
- 複選按鈕 -
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())
- 單行輸入框 -
| 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())
- 多行輸入框 -
| 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())
- 多行輸入框 -
| 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())
- 標籤(圖片) -
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()) # 執行應用程式
- 圖片 -
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())
- 圖片(多張) -
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())
- 圖片 -
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() 加入元件
from PyQt6.QtWidgets import QVBoxLayout, QHBoxLayoutfrom 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())
| 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) 加入元件並指定網格位置
from PyQt6.QtWidgets import QGridLayout建立表單佈局
使用 QFormLayout() 建立
預設僅有兩個欄位 (QLabel + 單/多行輸入框)
使用 addRow(text, input) 加入一組元件
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())設計結束後可直接轉換成程式碼!
選擇 Widget 作為基底,並按下 Create
直接拖移左側工具欄中的元件進行設計!
pyuic6 -x X.ui -o X.py3. 轉檔成功!(如右圖)
使用 Qt Designer
可以更快的完成 GUI 的介面設計!
大部分元件都支援的方法,可以使用類似 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 (雙線)
By Ethan Yeh