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

Share on:

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

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

モデルへQPixmapを追加

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

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

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

 1class Delegate(QtWidgets.QStyledItemDelegate):
 2    def __init__(self, parent=None, setModelDataEvent=None):
 3        super(Delegate, self).__init__(parent)
 4
 5    def paint(self, painter, option, index):
 6        data = index.model().data(index)
 7
 8        if type(data) is QtGui.QPixmap:
 9            r = option.rect
10            painter.drawPixmap( 
11                r.x(), r.y(), r.width(), r.height(), data
12            )
13
14        super(Delegate, self).paint(painter, option, index)

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

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

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

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

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

 1class Delegate(QtWidgets.QStyledItemDelegate):
 2    def __init__(self, parent=None, setModelDataEvent=None):
 3        super(Delegate, self).__init__(parent)
 4        
 5        .
 6        .
 7        .
 8
 9    def paint(self, painter, option, index):
10        data = index.model().data(index)
11
12        if type(data) is QtGui.QPixmap:
13
14            if option.rect.width() / option.rect.height() < data.size().width() / data.size().height():
15                scaled = data.scaledToWidth( option.rect.width() )
16            else:
17                scaled = data.scaledToHeight( option.rect.height() )
18            
19            painter.drawPixmap( 
20                option.rect.x(), option.rect.y(), 
21                scaled.size().width(), scaled.size().height(),
22                scaled 
23            )
24
25        super(Delegate, self).paint(painter, option, index)

ソースコード

github

関連記事