こんにちは、タナカです。
この記事では、PyQt5で画像をウィンドウ上に表示させる方法を紹介します。ちなみに画像を表示させる方法はたくさんありますので、その一例になります。
別の記事では、paintEventを使った方法で画像をウィンドウ上に表示させる方法も解説しています。
- PyQt5を使って画像をウィンドウ上に表示させる方法がわかる
 
1. アウトプット
メニューバーからファイルを選択し、画像をウィンドウ上に表示させる方法を説明します。
最終的なアウトプットはこちらになります。
リンゴの画像はPexelsによるPixabayから引用させていただきました。
2. メニューバーを作成するコードの確認
こちらの記事で作成したコードに追記していく形で書いていきます。前回作成したコードはこちらになります。
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QFileDialog
import sys
class MainWindow(QMainWindow):
    # コンストラクタ
    def __init__(self):
        super(MainWindow, self).__init__()
        # ウィンドウのサイズと表示位置
        # setGeometry(x, y, w, h) x: x位置, y: y位置, w: 幅, h: 高さ
        self.setGeometry(300, 300, 500, 500)
        
        # menubarを作成
        self.createMenubar()
    
    def createMenubar(self):
        # menubar
        self.menubar = self.menuBar()
        # menubarにメニューを追加
        self.filemenu = self.menubar.addMenu('File')
        # アクションの追加
        self.openAction()
    def openAction(self):
        # アクションの作成
        self.open_act = QAction('開く')
        self.open_act.setShortcut('Ctrl+O') # shortcut
        self.open_act.triggered.connect(self.openFile) # open_actとメソッドを紐づける
        # メニューにアクションを割り当てる
        self.filemenu.addAction(self.open_act)
    def openFile(self):
        self.filepath = QFileDialog.getOpenFileName(self, 'open file')[0]
3. Canvasクラスの作成
画像を表示させるために、Canvasクラスを作成していきます。
Canvasクラスのイメージはこのようになります。
MainWindowのレイアウト上(灰色)にCanvas(QWidget)がいるイメージです。
このCanvasにレイアウトを設定したり、画像を表示させるための機能を実装しています。
コードはこのようになります。
from PyQt5.QtWidgets import QWidget, QGridLayout, QGraphicsView, QGraphicsScene
from PyQt5 import QtGui
class Canvas(QWidget):
    def __init__(self):
        super(Canvas, self).__init__()
        # canvasのレイアウト
        self.canvas_layout = QGridLayout()
        
        # canvas_layoutをQWidget(self)にセット
        self.setLayout(self.canvas_layout)
        # 画像を表示するためのviewをレイアウトにセット
        self.view = QGraphicsView()
        self.scene = QGraphicsScene()
        self.view.setScene(self.scene)  
        self.canvas_layout.addWidget(self.view)
    def setImage(self, filepath):
        img = QtGui.QImage()
        
        # 画像ファイルの読み込み
        if not img.load(filepath):
            return False
        # sceneの初期化
        self.scene.clear()
        # QImage -> QPixmap
        self.pixmap = QtGui.QPixmap.fromImage(img)
        # pixmapをsceneに追加
        self.scene.addPixmap(self.pixmap)
        # ウィジェットを更新
        self.update()
        return True
直接MainWindowに画像を表示させる機能を実装してもいいのですが、クラスを分けた方が管理しやすいので、Canvasクラスを作っています。
また、この画像を表示させる部分の補足ですが、私はこのように解釈しています。
# 画像を表示するためのviewをレイアウトにセット
self.view = QGraphicsView()
self.scene = QGraphicsScene()
self.view.setScene(self.scene)  
self.canvas_layout.addWidget(self.view)
・
・
・
self.scene.addPixmap(self.pixmap)
imageをsceneに割り当てる際は、QImageからQPixmapに変換する必要があります。
4. 画像をウィンドウ上に表示する
Canvasクラスを作成できたら、あとはMainWindowクラスにCanvasクラスを実装します。MainWindowクラスのコードはこのようになります。
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QAction, QFileDialog, QGridLayout, QGraphicsView, QGraphicsScene
from PyQt5 import QtGui
import sys
import os
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        # 追加
        # canvas
        self.canvas = Canvas()
        # canvasをMainWindowにセット
        self.setCentralWidget(self.canvas)
        self.setGeometry(300, 300, 500, 500)
        # menubarを作成
        self.createMenubar()
    def createMenubar(self):
        # menubar
        self.menubar = self.menuBar()
        # menubarにメニューを追加
        self.filemenu = self.menubar.addMenu('File')
        # アクションの追加
        self.openAction()
    def openAction(self):
        # アクションの作成
        self.open_act = QAction('開く')
        self.open_act.setShortcut('Ctrl+O') # shortcut
        self.open_act.triggered.connect(self.openFile) # open_actとメソッドを紐づける
        # メニューにアクションを割り当てる
        self.filemenu.addAction(self.open_act)
    def openFile(self):
        self.filepath = QFileDialog.getOpenFileName(self, 'open file', '', 'Images (*.jpeg *.jpg *.png *.bmp)')[0]
        # 追加
        if self.filepath:
            self.canvas.setImage(self.filepath)
            self.resize(self.canvas.pixmap.width(), self.canvas.pixmap.height())
追加したコードの補足をします。
# 追加
if self.filepath:
    self.canvas.setImage(self.filepath)
    self.resize(self.canvas.pixmap.width(), self.canvas.pixmap.height())
メニューバーからファイルを選択し、画像のパスを取得します。取得したパスを使って画像をウィンドウ上に表示させる処理をしています。そのとき、取得した画像のサイズに応じてMainWindowのウィンドウサイズが変わるようにしています。
まとめ
PyQt5で画像をウィンドウ上に表示させる方法を説明しました。
今のままでは、ただ画像を表示させるだけのプログラムなので、大きいサイズの画像を表示させた際に見切れたりします。
今後、ウィンドウサイズに画像がフィットするような改善など修正すべき箇所もありますので、記事にまとめていきたいと思います。
今回の方法以外で、画像を表示させる方法なども紹介したいと思います。
最後に今回使用したすべてのコードを記述しておきます。
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QAction, QFileDialog, QGridLayout, QGraphicsView, QGraphicsScene
from PyQt5 import QtGui
import sys
import os
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        # canvas
        self.canvas = Canvas()
        # canvasをMainWindowにセット
        self.setCentralWidget(self.canvas)
        self.setGeometry(300, 300, 500, 500)
        # menubarを作成
        self.createMenubar()
    def createMenubar(self):
        # menubar
        self.menubar = self.menuBar()
        # menubarにメニューを追加
        self.filemenu = self.menubar.addMenu('File')
        # アクションの追加
        self.openAction()
    def openAction(self):
        # アクションの作成
        self.open_act = QAction('開く')
        self.open_act.setShortcut('Ctrl+O') # shortcut
        self.open_act.triggered.connect(self.openFile) # open_actとメソッドを紐づける
        # メニューにアクションを割り当てる
        self.filemenu.addAction(self.open_act)
    def openFile(self):
        self.filepath = QFileDialog.getOpenFileName(self, 'open file', '', 'Images (*.jpeg *.jpg *.png *.bmp)')[0]
        if self.filepath:
            self.canvas.setImage(self.filepath)
            # 画像のサイズに応じてウィンドウサイズを変更
            self.resize(self.canvas.pixmap.width(), self.canvas.pixmap.height())
class Canvas(QWidget):
    def __init__(self):
        super(Canvas, self).__init__()
        # canvasのレイアウト
        self.canvas_layout = QGridLayout()
        
        # canvas_layoutをQWidget(self)にセット
        self.setLayout(self.canvas_layout)
        # 画像を表示するためのviewをレイアウトにセット
        self.view = QGraphicsView()
        self.scene = QGraphicsScene()
        self.view.setScene(self.scene)  
        self.canvas_layout.addWidget(self.view)
    def setImage(self, filepath):
        img = QtGui.QImage()
        
        # 画像ファイルの読み込み
        if not img.load(filepath):
            return False
        # sceneの初期化
        self.scene.clear()
        # QImage -> QPixmap
        self.pixmap = QtGui.QPixmap.fromImage(img)
        # pixmapをsceneに追加
        self.scene.addPixmap(self.pixmap)
        # ウィジェットを更新
        self.update()
        return True
def main():
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())
main()
