PyQt5 QTableViewのセルに画像を表示する

QTableViewのサンプルのセルに画像を表示するプログラムを作成しました。



表示している画像は下記のPNG画像5個です。グレーとオレンジは長方形でその他は正方形の画像です。

モデルへQPixmapを追加

作成したプログラムではItemという自作クラスを作ってQAbstractItemModelに追加していくことでデータを管理しています。QAbstractItemModelを継承したModelクラスはQTreeViewでも使えるように作成したものを使用しているので、Itemクラスは子を持てるように作っています。Itemクラスにはいろいろ書いていますが、実際のデータはただの辞書でitem.set_data()でデータを追加するだけです。

for filename in ['_green.png', '_blue.png', '_yellow.png', '_orange.png', '_gray.png']:
    self.model.insertRows(self.model.rowCount(), 1)
    item = self.model.root_item.children()[-1]
    pixmap = QtGui.QPixmap(filename)
    item.set_data('Image', pixmap)
    item.set_data('File name', filename)

セルに画像を表示するにはQStyledItemDelegateのpaintメソッドをオーバーライドします。paintメソッドにはpainter.drawPixmap()を使ってQPainterでPixmapを描画する処理を追加します。これでセルに画像が表示されるようになります。

class Delegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None, setModelDataEvent=None):
        super(Delegate, self).__init__(parent)

    def paint(self, painter, option, index):
        data = index.model().data(index)

        if type(data) is QtGui.QPixmap:
            r = option.rect
            painter.drawPixmap( 
                r.x(), r.y(), r.width(), r.height(), data
            )

        super(Delegate, self).paint(painter, option, index)



画像のアスペクト比を維持する

上記コードのようにそのままPixmapを渡すと、下記画像のように画像がセルサイズにフィットした状態で表示されてしまいます。

このように表示したい場合もあるかもしれませんが、今回はセルサイズが変わっても画像のアスペクト比は変わらないようにしたかったので、セルのアスペクト比と画像のアスペクト比を比較して、それに合わせてpixmapをスケールする処理を加えました。

if option.rect.width() / option.rect.height() < data.size().width() / data.size().height():
    scaled = data.scaledToWidth( option.rect.width() )
else:
    scaled = data.scaledToHeight( option.rect.height() )

Delegateクラスのpaintメソッドは下記のようになります。これでセルサイズが変わっても画像のアスペクト比は維持されるようになりました。

class Delegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None, setModelDataEvent=None):
        super(Delegate, self).__init__(parent)
        
        .
        .
        .

    def paint(self, painter, option, index):
        data = index.model().data(index)

        if type(data) is QtGui.QPixmap:

            if option.rect.width() / option.rect.height() < data.size().width() / data.size().height():
                scaled = data.scaledToWidth( option.rect.width() )
            else:
                scaled = data.scaledToHeight( option.rect.height() )
            
            painter.drawPixmap( 
                option.rect.x(), option.rect.y(), 
                scaled.size().width(), scaled.size().height(),
                scaled 
            )

        super(Delegate, self).paint(painter, option, index)



ソースコード

github

コメント

タイトルとURLをコピーしました