0

I have implemented a multiline text editor for a QTableView as seen here: Make row of QTableView expand as editor grows in height

One issue I have not yet been able to solve is getting full control over the styling of the painted text. A solution for the font color was provided here: Changing the font color of a QTableView after replacing the default editor with an ItemDelegate QTextEdit in PyQt5

I have set a stylesheet for the QTableView:

self.setStyleSheet(
    """font-size: 14px;
    gridline-color: rgb(60, 60, 60);"""
)

And it works for styling the editor as well as the grid. Ideally, I would like the cells to have the same styling as the rest of the application while having some way of making changes to some of the attributes which would then affect both the editor and the way the cells are painted. Everything I have done so far in order to change the styling of the font has been ignored. I have tried changing the initStyleOption, changing the painter's font, changing the option's font and everything else I could think of.

This is the current paint function:

def paint(self, painter, option, index):
    """
    Method override
    """
    # Remove dotted border on cell focus.  https://stackoverflow.com/a/55252650/3620725
    if option.state & QtWidgets.QStyle.State_HasFocus:
        option.state = option.state ^ QtWidgets.QStyle.State_HasFocus

    self.initStyleOption(option, index)
    painter.save()
    doc = QtGui.QTextDocument()
    doc.setDocumentMargin(3)
    doc.setTextWidth(option.rect.width())
    # changed to setPlainText from setHtml because setHtml was removing all newlines
    doc.setPlainText(option.text)
    option.text = ""
    option.widget.style().drawControl(
        QtWidgets.QStyle.CE_ItemViewItem, option, painter
    )
    painter.translate(option.rect.left(), option.rect.top())

    clip = QtCore.QRectF(0, 0, option.rect.width(), option.rect.height())
    painter.setClipRect(clip)

    layout = doc.documentLayout()
    ctx = layout.PaintContext()
    ctx.palette = option.palette
    layout.draw(painter, ctx)
    painter.restore()

An application wide stylesheet is applied when the program is run:

app = QApplication(sys.argv)
app.setStyleSheet(qtstylish.dark())

I believe the spacing is also different between the editor and the painted cell.

Comparison

musicamante
  • 41,230
  • 6
  • 33
  • 58
M D
  • 19
  • 1
  • 6
  • What about [`doc.setDefaultFont(option.font)`](https://doc.qt.io/qt-5/qtextdocument.html#setDefaultFont) (*before* adding the contents)? As said in my previous answer, the QTextDocument created in `paint()` doesn't know anything about the context of the delegate (nor its `option`) because it's a "standalone" one, and it can only use the application defaults; since `QApplication.setStyleSheet()` can only set widget properties, any font value (even if set with the `* {font: ...}` wildcard selector) will be ignored, as an actual global font is only possible through `QApplication.setFont()`. – musicamante Feb 28 '22 at 11:59
  • Also, by "spacing" do you mean the margins between the editor borders and the contents? That can be a bit tricky, and it depends on the style sheet used for the editor (probably using the QAbstractScrollArea selector): if it alters any content aspect (border, margin, padding) the `frameShape()` will always be overridden, and the only way to know that is by checking the widget's content margins - which can obviously be known as soon as an editor is created. – musicamante Feb 28 '22 at 12:08
  • Thank you for helping out once again @musicamante. Using `doc.setDefaultFont(option.font)` worked out for applying the stylesheet. I can't believe I never noticed it when going over that part of the docs. Unfortunately it seems to have broken something else. I have been resizing all rows to contents like so: `def showEvent(self, event: QtGui.QShowEvent) -> None: self.resizeRowsToContents() event.accept()`. Doing so now sets the row height to be too small. I'm looking into finding a solution for that. By spacing I meant the vertical space between lines of text. It's fixed now. – M D Feb 28 '22 at 12:34
  • I'll add a proper answer, then. `resizeRowsToContents()` has nothing to do with the above (painting does nothing to size or size hints: paint functions only draw), so it is related to something with delegate size hint of my related post *and* the aforementioned borders. Note that properly showing multiline text *while* adjusting contents is difficult (if not almost impossible): since you're using rich text, there's no absolute reference for the size (should the height consider the width? and what if you also call `resizeColumnsToContents()`?). In any case, `sizeHint()` should be implemented. – musicamante Feb 28 '22 at 12:45
  • Thank you for pointing me in the right direction. I'll try to make it work. – M D Feb 28 '22 at 12:51
  • Adding `doc.setDefaultFont(option.font)` to the sizeHint function from your related post did the trick. Everything is working as inteneded now. Cheers! – M D Feb 28 '22 at 14:35

1 Answers1

0

When a QTextDocument is created as a standalone object, it can only use the application defaults, including the font.

Note that using a global stylesheet, even with wildcard selectors does not set the default font for the application, but only for the widgets, and since QTextDocument and QAbstractItemDelegate are not widgets, no style sheet font will be applied.

While there is no access to stylesheets, the style option argument of the paint() function can provide such information: the argument of the function will be the default style option for the view (viewOptions()), and initStyleOption() will eventually alter the font as long as FontRole returns a valid QFont.

The solution is then to set the defaultFont() of the document:

def paint(self, painter, option, index):
    # ...
    doc = QtGui.QTextDocument()
    doc.setDefaultFont(option.font)
    # ...
musicamante
  • 41,230
  • 6
  • 33
  • 58