0

I need to create a list of custom drawn messages. After failing with QStyledItemDelegate for reasons described in this question QStyledItemDelegate's option is not updating I am trying to use QListWidget for this. However I don't understand how should I change the size of widgets in it. For example, I narrow down the window, so the widgets have to gain height, but the sizeHint function of my custom widget is called only twice in the beginning and never after that. This is the minimal reproducible example, which I use:

import sys
from PyQt5.QtCore import (
    Qt,
    QSize,
    QRect,
    QRectF,
)
from PyQt5.QtGui import (
    QPainter,
    QFontMetrics,
    QFont,
    QTextDocument,
    QTextOption,
    QPen,
)
from PyQt5.QtWidgets import (
    QApplication,
    QListView,
    QMainWindow,
    QListWidget,
    QListWidgetItem,
    QWidget,
)

frame_width = 0

class MessageWidget(QWidget):

    def __init__(self, msg):
        super(MessageWidget, self).__init__()
        self.msg = msg
        self.font = QFont("Times", 14)

    def paintEvent(self, event):
        field = QRect(0, 0, self.width(), self.height())
        doc = QTextDocument(self.msg)
        doc.setDocumentMargin(0)
        opt = QTextOption()
        opt.setWrapMode(opt.WrapAtWordBoundaryOrAnywhere)
        doc.setDefaultTextOption(opt)
        doc.setDefaultFont(self.font)
        doc.setTextWidth(field.size().width())
        field.setHeight(int(doc.size().height()))
        field.setWidth(int(doc.idealWidth()))
        painter = QPainter(self)
        painter.setPen(Qt.gray)
        painter.setFont(self.font)
        painter.translate(field.x(), field.y())
        textrectf = QRectF(field)
        textrectf.moveTo(0, 0)
        doc.drawContents(painter, textrectf)
        painter.translate(-field.x(), -field.y())

    def sizeHint(self):
        print("Here")
        global frame_width
        doc = QTextDocument(self.msg)
        doc.setDocumentMargin(0)
        opt = QTextOption()
        opt.setWrapMode(opt.WrapAtWordBoundaryOrAnywhere)
        doc.setDefaultTextOption(opt)
        doc.setDefaultFont(self.font)
        doc.setTextWidth(frame_width)
        return QSize(0, int(doc.size().height()))


class Dialog(QMainWindow):

    def __init__(self):
        global frame_width
        super(Dialog, self).__init__()
        self.setMinimumSize(int(QApplication.primaryScreen().size().width() * 0.1), int(QApplication.primaryScreen().size().height() * 0.2))
        self.resize(int(QApplication.primaryScreen().size().width() * 0.3), int(QApplication.primaryScreen().size().height() * 0.5))
        self.messages = QListWidget()
        frame_width = self.messages.size().width()
        self.message_array = []
        self.message_array.append("qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty qwerty")
        self.message_array.append("abcdef")
        for i in range(len(self.message_array)):
            item = QListWidgetItem()
            widget = MessageWidget(self.message_array[i])
            item.setSizeHint(widget.sizeHint())
            self.messages.addItem(item)
            self.messages.setItemWidget(item, widget)
        self.messages.setResizeMode(QListView.Adjust)
        self.setCentralWidget(self.messages)

    def resizeEvent(self, event):
        global frame_width
        super(Dialog, self).resizeEvent(event)
        frame_width = int(self.messages.size().width())

app = QApplication(sys.argv)
window = Dialog()
window.show()
app.exec_()

I am not sure if I am using items and widgets properly here, but as I said in this example "Here" (printed in the beginning of sizeHint) is only printed 4 times when the program is started. And then no matter how I resize the window, sizeHint isn't called, and hence size of widgets isn't modified.

Vladislav
  • 35
  • 7
  • The "hint" has no defined behavior (Qt does not promise even to use it) as it is a hint. May or may not be even requested. Try to specify the size for the widget explicitly as well. When the parent widget knows the explicit size then it may request a hint too. – Alexander V May 07 '21 at 18:27
  • @AlexanderV should I specify the size of widgets or the size of items? And how should I do it? Using the `resize` method? – Vladislav May 08 '21 at 15:29
  • Yes, Vlad, make sure there is a size. Usually minimum size is working with the hint. – Alexander V May 09 '21 at 14:53

0 Answers0