看完這篇文章你會得到的成果圖
zoom in
zoom out
前言
我們接下來的討論,會基於讀者已經先讀過我 day5 文章 的架構下去進行程式設計
如果還不清楚我程式設計的邏輯 (UI.py、controller.py、start.py 分別在幹麻)
建議先閱讀 day5 文章後再來閱讀此文。
【PyQt5】Day 5 – 開始來設計我們的 controller.py,改以「程式角度」來說明如何建立 PyQt 的系統
此篇文章的範例程式碼 github
https://github.com/howarder3/ironman2021_PyQt5_photoshop/tree/main/day12_img_resize
以 Qlabel 在 PyQt 中顯示圖片
這篇是延續 Day 11 顯示圖片的後續開發,
在 day11 我們只是單純的顯示圖片,
但有碰到了「圖片解析度太大,無法完全顯示」的問題,
今天我們就要加入「zoom in」、「zoom out」的功能,來改善這個問題。
UI 設計部份 (UI.py)
以 Qlabel 作為圖片顯示
我們與之前一樣新增一個 Qlabel,文字可以先不用管他,
這個 Qlabel 是我們等等要作為顯示圖片使用,
因此我們記得要去修改圖片大小,以免顯示的範圍太小。
- 另外我們新增兩個按鈕,作為等等縮放圖片使用。
注意上圖中的圖片大小,另外變數名稱也建議修改。
讀者們可以開始自行設計自己的介面囉,以上為我的示範。
轉換成 UI.py
一樣的編譯指令,我們加上 -x (也可不加),
我們就可以先檢視看看轉換後的視窗是不是跟我們想像的一樣。
轉換 day12.ui -> UI.py
pyuic5 -x day12.ui -o UI.py
執行看看 UI.py 畫面是否如同我們想像
一樣,這程式只有介面 (視覺上的呈現),沒有任何互動功能
- 看看我們製作出來的介面
python UI.py
這樣我們的介面就大致出來囉!
controller 設計部份 (controller.py)
從 UI.py 中找出物件名稱
這次我們有三個物件
- 分別是 zoom in, zoom out 的按鈕:self.btn_zoom_in、self.btn_zoom_out
- 顯示圖片的 Qlabel:self.label
取得名稱後,去修改 controller.py
還記得我們在 day5 中的模板嗎?這邊我們直接複製過來使用並修改。
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QFileDialog
import cv2
from UI import Ui_MainWindow
class MainWindow_controller(QtWidgets.QMainWindow):
def __init__(self):
super().__init__() # in python3, super(Class, self).xxx = super().xxx
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setup_control()
def setup_control(self):
# TODO
self.img_path = 'cat.jpg'
self.ui.btn_zoom_in.clicked.connect(self.func_zoom_in)
self.ui.btn_zoom_out.clicked.connect(self.func_zoom_out)
self.display_img()
def display_img(self):
self.img = cv2.imread(self.img_path)
height, width, channel = self.img.shape
bytesPerline = 3 * width
self.qimg = QImage(self.img, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped()
self.qpixmap = QPixmap.fromImage(self.qimg)
self.qpixmap_height = self.qpixmap.height()
self.ui.label.setPixmap(QPixmap.fromImage(self.qimg))
def func_zoom_in(self):
self.qpixmap_height -= 100
self.resize_image()
def func_zoom_out(self):
self.qpixmap_height += 100
self.resize_image()
def resize_image(self):
scaled_pixmap = self.qpixmap.scaledToHeight(self.qpixmap_height)
self.ui.label.setPixmap(scaled_pixmap)
setup_control() 修改的部份
- 「self.img_path = ‘cat.jpg’」:要顯示圖片的路徑
- 「self.ui.btn_zoom_in.clicked.connect(self.func_zoom_in)」:使按鍵連結 zoom in 的功能
- 「self.ui.btn_zoom_out.clicked.connect(self.func_zoom_out)」:使按鍵連結 zoom out 的功能
- 「self.display_img()」:等等會去 call 我們寫好的顯示圖片的 function
display_img() 的部份
相關的功能我們在 day11,
有介紹的很詳細了,這邊只說我們有修改的部份
會修改的原因主要是我們新增了 zoom in 的功能,
因此我們顯示圖片函式需要調整成可以隨時變動的 (不寫死、保有彈性,可重複使用)
我們把原先的寫的內容拆解,
特別其中的這四行:
self.qimg = QImage(self.img, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped()
self.qpixmap = QPixmap.fromImage(self.qimg)
self.qpixmap_height = self.qpixmap.height()
self.ui.label.setPixmap(QPixmap.fromImage(self.qimg))
第一行一樣我們透過 OpenCV 的方式,轉換成我們要的 Qimage
第二行我們改成獨立從 Qimage 提取出 QPixmap,
這邊我們可以理解為
- QImage 是實際上圖片的內容
- QPixmap 是我們最終用來顯示再畫面上的內容 (可能為了顯示有縮放調整),但不會更改到原圖
我們在第三行取得 QPixmap 的高度,作為我們等等縮放使用
最後第一行一樣就是透過 label 顯示出來。
func_zoom_in()、func_zoom_out() 的部份
這邊我們是去調整「我們想要呈現的」QPixmap 高度,
在接下來的 resize_image() ,讓他依據這個高度自動比例縮放。
resize_image() 的部份
scaled_pixmap = self.qpixmap.scaledToHeight(self.qpixmap_height)
self.ui.label.setPixmap(scaled_pixmap)
這邊的第一行就是讓圖片 (Qpixmap) 自己去適應我們要的圖片高度,做出對應的圖片縮放。
而第二行就是把縮放後的圖片 (Qpixmap) 塞進去我們的 label 當中。
注意:我們從頭到尾都只有更改到 Qpixmap 而沒有改動到 Qimg,
這也表示我們的原圖是一直有被保存下來的。
我們所做的都只是「顯示上的更動」。
執行結果
照我們 day5 的程式架構,我們執行
python start.py