I want to create a GUI that lists images in a directory along with a description for the images. So far I've been able to create a custom delegate for a QListView
to draw the image onto each list item, but any description longer than the designated size of a list item is truncated, how do I have it be scrollable? And also preferably selectable.
My code so far:
import os
from typing import Union
from PySide6 import QtWidgets as qtw
from PySide6 import QtGui as qtg
from PySide6 import QtCore as qtc
ITEMS_SPACING = 10
THUMBNAIL_SIZE = (200, 200)
class Delegate(qtw.QAbstractItemDelegate):
def paint(
self,
painter: qtg.QPainter,
option: qtw.QStyleOptionViewItem,
index: qtc.QModelIndex
) -> None:
thumbnail: qtg.QImage = index.model().data(
index, qtc.Qt.ItemDataRole.DecorationRole
)
description: str = index.model().data(
index, qtc.Qt.ItemDataRole.DisplayRole
)
if thumbnail is None:
return
old_painter = painter.device()
painter.drawImage(
qtc.QRect(
option.rect.left(),
option.rect.top(),
*THUMBNAIL_SIZE
),
thumbnail
)
painter.end()
text_edit = qtw.QPlainTextEdit(self.parent())
text_edit.setPlainText(description)
text_edit.setFixedSize(
option.rect.width() - THUMBNAIL_SIZE[0] - (ITEMS_SPACING * 2),
THUMBNAIL_SIZE[1]
)
text_edit.render(
painter.device(),
qtc.QPoint(
option.rect.left() + THUMBNAIL_SIZE[0] + 20,
option.rect.top()
)
)
painter.begin(old_painter)
def sizeHint(
self, option: qtw.QStyleOptionViewItem, index: qtc.QModelIndex
) -> int:
return qtc.QSize(*THUMBNAIL_SIZE)
class Model(qtc.QAbstractListModel):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._thumbnails = [
qtg.QImage(filename) for filename in os.listdir('.')
]
self._descriptions = ["this is text" * 5000 for _ in range(len(self._thumbnails))]
def rowCount(self, _: qtc.QModelIndex) -> int:
return len(self._thumbnails)
def data(
self, index: qtc.QModelIndex, role: qtc.Qt.ItemDataRole
) -> Union[int, None]:
if not index.isValid():
return None
if role == qtc.Qt.ItemDataRole.DisplayRole:
return self._descriptions[index.row()]
elif role == qtc.Qt.ItemDataRole.DecorationRole:
return self._thumbnails[index.row()]
return None
class MainWindow(qtw.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
delegate = Delegate(self)
self._model = Model()
self._view = qtw.QListView(self)
self._view.setSpacing(ITEMS_SPACING)
self._view.setModel(self._model)
self._view.setItemDelegate(delegate)
self.setCentralWidget(self._view)
self.show()
app = qtw.QApplication()
mw = MainWindow()
app.exec()
Edit:
Why the code doesn't work:
I can't scroll the rendered QTextEdit
nor can I select the text. It's basically the same as painter.drawText
but with a scroll bar drawn below the text. Further more, in my actual code I can't get the QTextEdit
to align with the images, even though it has the same code as the one provided above. Also, the QTextArea
(s) seemingly randomly disappear/reappear following a paint event.