➣ Reading Time: 12 minutes

看完這篇文章你會得到的成果圖

zoom in

zoom out

前言

我們接下來的討論,會基於讀者已經先讀過我 day5 文章 的架構下去進行程式設計
如果還不清楚我程式設計的邏輯 (UI.py、controller.py、start.py 分別在幹麻)
建議先閱讀 day5 文章後再來閱讀此文。

此篇文章的範例程式碼 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

zoom in 的功能

zoom out 的功能

Reference

⭐Python PyQt5 相關文章整理⭐:
⭐基礎知識與架構篇⭐:
1.【PyQt5】Day 1 – 安裝 PyQt,建立自己的第一支 PyQt5 程式
2.【PyQt5】Day 2 – 利用 Qt designer 建立第一支有自己介面的 PyQt5 程式
3.【PyQt5】Day 4 – 重要的 Qt 程式邏輯觀念,務必先有此觀念後面才會懂自己在幹嘛
4.【PyQt5】Day 5 – 開始來設計我們的 controller.py,改以「程式角度」來說明如何建立 PyQt 的系統
⭐基本介面控制篇⭐:
1.【PyQt5】Day 6 – 我們的第一個 output 手段 – Qlabel
2.【PyQt5】Day 7 – 我們的第一個 input 手段 – QPushButton
3.【PyQt5】Day 8 – 我們的第二個 input 手段 – QLineEdit
4.【PyQt5】Day 9 – 以 QLineEdit, QTextEdit, QPlainTextEdit 作為文字的輸入
5.【PyQt5】Day 10 – 以 QFileDialog 讀取系統的檔案、資料夾
⭐影像處理篇⭐:
1.【PyQt5】Day 11 – 以 Qlabel 在 PyQt 中顯示圖片 (基於 QImage 使用 OpenCV)
2.【PyQt5】Day 12 – 建立一個可以縮放圖片大小的顯示器 (基於 QImage 使用 OpenCV)
3.【PyQt5】Day 13 – 使用 QVBoxLayout, QscrollArea 製作出捲軸,以高解析度檢視圖片 (基於 QImage 使用 OpenCV)
⭐打包程式篇⭐:
1.【PyQt5】Day 3 – 用 pyinstaller 將 python 程式打包,把每天的成果分享給你的親朋好友
⭐【喜歡我的文章嗎? 歡迎幫我按讚~ 讓基金會請創作者喝一杯咖啡!
如果喜歡我的文章,請幫我在下方【按五下Like】 (Google, Facebook 免註冊),會由 「LikeCoin」 贊助作者鼓勵繼續創作,讀者們「只需幫忙按讚,完全不用出錢」哦!

likecoin-steps