# 利用PyQt5建立GUI介面
**PyQt5詳細資料可參考:**
https://steam.oxxostudio.tw/category/python/pyqt5/index.html
**CSS詳細資料可參考:**
https://developer.mozilla.org/zh-TW/docs/Learn/CSS
## 1.建立視窗
```python=
from PyQt5 import QtWidgets
import sys
'''=====================GUI============================'''
class MainWindow(QtWidgets.QWidget): # 建立視窗基底
def __init__(self):
super().__init__()
self.initUI()
self.setWindowTitle("視窗名稱") # 設定視窗標題
self.resize(1320,720) # 設定視窗大小(width,height)
# self.setStyleSheet("") # 使用階層式樣式表(CSS)編輯
def initUI(self):
layout = QtWidgets.QVBoxLayout()
#內容
pass # 將pass替換成介面內容
self.setLayout(layout) # 把建立好的內容放上視窗
self.show # 秀出視窗
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
```
## 2.常用功能
### a) 標籤 QLabel
可用來放置文字或圖片,利用setText()加入文字,可透過QtGui.QFont()設定字體、QtCore設定對齊,利用setPixmap()加入圖片,可透過QtGui.QImage()讀取圖片。(若有使用到,記得import)
``` python=
from PyQt5 import QtWidgets, QtGui, QtCore
QLabel = QtWidgets.QLabel
font = QtGui.QFont
"=================文字========================="
label1 = QLabel(self) # 創立label1
label1.setText("輸入文字") # 在label1上輸入文字
QLabel.setGeometry(0,0,0,0) # 設定位置
QLabel.setWordWrap(True) # 可以換行
QLabel.setAlignment(QtCore.Qt.AlignCenter) # 對齊方式
font = QtGui.QFont() # 加入文字設定
font.setFamily('Verdana') # 設定字體
font.setPointSize(20) # 文字大小
font.setBold(True) # 粗體
font.setItalic(True) # 斜體
font.setStrikeOut(True) # 刪除線
font.setUnderline(True) # 底線
QLabel.setFont(font)
"=================圖片========================="
label2 = QLabel(self) # 創立label2
img = QtGui.QImage('image') # 讀取圖片
label2.setPixmap(QtGui.QPixmap.fromImage(img)) # 在label2上加入圖片
```
QLabel放置圖片時對格式有所限制,須為numpy array,可用以下方式調整。
```python=
img = cv2.imread(image_path, 0)
#將圖片灰度標準化,並調整為uint8的儲存格式
norm_img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX)
uint_img = norm_img.astype(np.uint8)
h, w = img.shape
bytes_per_line = w
convert_to_Qt_format = QtGui.QImage(
uint_img.data, w, h, bytes_per_line, QtGui.QImage.Format_Grayscale8
)#圖片儲存格式需為uint8
p = convert_to_Qt_format.scaled(600, 300, Qt.KeepAspectRatio)#調整成合適大小
label.setPixmap(QtGui.QPixmap.fromImage(p))#放置圖片於label
```
### b) 按鈕 QPushButton
``` python=
QPushButton = QWidgets.QPushButton
self.firstButton = QPushButton("Button One", self) # 建立名為firstButton的按鈕並貼上"Button One"的標籤
self.firstButton.clicked.connect(lambda: buttone_to_do(self)) # 點擊此按鈕執行函式button_to_do
```
>亦可用setText('')設定按鈕標籤
### c) 數值調整元件 QSpinBox、QDoubleSpinBox
QSpinBox只能調整整數,QDoubleSpinBox可以調整小數(浮點)數。
``` python=
QSpinBox = QtWidgets.QSpinBox
self.box1 = QSpinBox(self)
self.box1.setRange(0,100) # 調整範圍最大100,最小0
self.box1.setSingleStep(5) # 每次調整間距
self.box1.setValue(50) # 數值調整的預設值
```
> 其他常用方法
>> value() -->數值調整目前的數值
>> ValueChanged.connect() -->調整數值時執行函數
### d) 下拉選單 QComboBox
``` python=
QComboBox = QtWidgets.QComboBox
self.box2 = QComboBox(self) # 創造一個名為box2的下拉選單
self.box2.addItems(['A','B','C','D']) # 以串列方式增加多個選項
```
>其他常用方法
>>setCurrentIndex(index) -->預設定為第幾個選項(0代表地1個)
>>setCurrentText(str) -->指定選項文字為str的為預設選項
>>addItem() -->從選單最後面增加一個選項
>>addItems() -->從選單最後面增加多個選項
>>insertItem() -->在選單的指定位置增加一個選項(從0開始)
>>insertItems() -->在選單的指定位置以陣列增加多個選項
>>removeItem() -->移除指定項目()
>>currentText() -->選擇項目的文字
>>currentIndex() -->選擇項目的索引值
>>currentIndexChanged.connect() -->改變選項時要執行的函式
### e) 選擇檔案對話視窗 QFileDialog
通常會搭配按鈕或選單進行開啟檔案的動作,在此用按鈕作為範例。
``` python=
from PyQt5 import QtWidgets
import sys
'''=================QFileDialog========================'''
QFileDialog = QtWidgets.QFileDialog
def open_file(gui_instance):
file_path, file_type = QFileDialog.getOpenFileName(parent = None, caption = "choose file", directory = "", filter = 'TXT(*.txt)') # 選取檔案
file = open(file_path,'r') # 根據檔案路徑開啟檔案
text = file.read() # 讀取檔案內容
input.setPlainText(text) # 設定變數為檔案內容
file.close() # 關閉檔案
def open_folder(gui_instance):
folder_path = QFileDialog.getExistingDirectory() # 選取特定資料夾
print(folder_path)
'''=====================GUI============================'''
class MainWindow(QtWidgets.QWidget)
def __init__(self):
super().__init__()
self.initUI()
self.setWindowTitle("視窗名稱")
self.resize(1320,720)
def initUI(self):
layout = QWidgets.QVBoxLayout()
QPushButton = QWidgets.QPushButton
self.firstButton = QPushButton("Button One", self)
self.firstButton.clicked.connect(lambda: open_file(self))
layout.addWidget(self.firstButton)
self.secondButton = QPushButton("Button Second", self)
self.secondButton.clicked.connect(lambda: open_folder(self))
layout.addWidget(self.secondButton)
self.setLayout(layout)
self.show
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
```
其中要注意,QFileDialog可以透過3種方式選擇檔案
>getOpenFileName() -->選擇單一檔案
>getOpenFileNames() -->選擇多個檔案,以串列回傳
>getExistingDirectory() -->選擇一個資料夾
又,使用QFileDialog開啟檔案時,能夠設定4個參數
>parent -->父元件
>caption -->對話視窗標題
>directory -->開啟目錄位置(若沒設定則使用py檔案所在目錄)
>filter -->檔案篩選器(非指定檔案類型無法選擇)
附上常使用的相片加載(loadImage)和影片加載(loadVideo)
``` python=
def loadimage(gui_instance):
QFileDialog = QtWidgets.QFileDialog
image_path, _ = QFileDialog.getOpenFileName(
None, "Load Image", "", "Figure Files ( *.jfif *.jpg *.png)"
)
if image_path:
print(f"image is loaded from {image_path}")
img = cv2.imread(image_path, 0)
def loadvideo(gui_instance):
QFileDialog = QtWidgets.QFileDialog
video_path, _ = QFileDialog.getOpenFileName(
None, "Load Video", "", "Video Files ( *.mp4 *.avi *.mov)"
)
if video_path:
print(f"video is loaded from {video_path}")
video = cv2.VideoCapture(video_path)
```
## 3.放置內容
假設已建立一個名為firstButton的按鈕,有3種方法將其放入介面中,以下將舉例說明。
### a) move()
參數為(x,y),可以指定其擺放的位置,其中x向右為正,y向下為正。
``` python=
firstButton.move(50,40)
```
### b) setGeometry()
參數為(x,y,w,h),可以指定其擺放位置及按鈕大小,其中x向右為正,y向下為正,w為按鈕長度,h為按鈕寬度。
``` python=
firstButton.setGeometry(50,80,100,30)
```
### c) layout.addWidget()
按鈕按順序自動排入適當的位置,並按照按鈕上標籤長度設置適合的按鈕大小。
要注意,此函數是從QtWidgets.QVBoxLayout()中得到。
``` python=
layout.addWidget(self.firstButton)
```