如何使项目视图在 Qt 中呈现富(html)文本

发布于 2024-08-16 04:07:00 字数 296 浏览 7 评论 0原文

假设我的模型具有以下 Qt::DisplayRole 字符串的项目,

<span>blah-blah <b>some text</b> other blah</span>

我希望 QTreeView (实际上,任何项目视图)将其呈现为富文本。相反,项目视图默认将其呈现为纯文本。如何达到想要的渲染效果?


实际上,这是一个搜索结果模型。用户输入文本,根据该文本搜索某些文档,并向用户呈现搜索结果,其中正在搜索的单词应比周围的文本更粗体。

Suppose my model has items with the following string for Qt::DisplayRole

<span>blah-blah <b>some text</b> other blah</span>

I want QTreeView (actually, any item view) to render it like a rich text. Instead, item views render it like a pure text by default. How to achieve the desired rendering?


Actually, this is a search results model. User enters a text, some document is searched against that text and the user is presented with search results, where the words being searched should be bolder than surrounding text.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

挽梦忆笙歌 2024-08-23 04:07:00

我想您可以使用树视图的 setItemDelegate 方法来设置自定义为您的树视图项目绘制。在委托的绘制方法中,您可以使用 QTextDocument 将项目的文本加载为 html 并渲染它。请检查下面的示例是否适合您:

树视图初始化:

...
    // create simple model for a tree view
    QStandardItemModel *model = new QStandardItemModel();
    QModelIndex parentItem;
    for (int i = 0; i < 4; ++i)
    {
        parentItem = model->index(0, 0, parentItem);
        model->insertRows(0, 1, parentItem);
        model->insertColumns(0, 1, parentItem);
        QModelIndex index = model->index(0, 0, parentItem);
        model->setData(index, "<span>blah-blah <b>some text</b> other blah</span>");
    }
    // create custom delegate
    HTMLDelegate* delegate = new HTMLDelegate();
    // set model and delegate to the treeview object
    ui->treeView->setModel(model);
    ui->treeView->setItemDelegate(delegate);
...

自定义委托实现

class HTMLDelegate : public QStyledItemDelegate
{
protected:
    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
};

void HTMLDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 options = option;
    initStyleOption(&options, index);

    painter->save();

    QTextDocument doc;
    doc.setHtml(options.text);

    options.text = "";
    options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);

    painter->translate(options.rect.left(), options.rect.top());
    QRect clip(0, 0, options.rect.width(), options.rect.height());
    doc.drawContents(painter, clip);

    painter->restore();
}

QSize HTMLDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
    QStyleOptionViewItemV4 options = option;
    initStyleOption(&options, index);

    QTextDocument doc;
    doc.setHtml(options.text);
    doc.setTextWidth(options.rect.width());
    return QSize(doc.idealWidth(), doc.size().height());
}

希望这有帮助,注意

update0:更改 HTMLDelegate 以使图标可见并为所选项目提供不同的笔颜色

void HTMLDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 options = option;
    initStyleOption(&options, index);

    painter->save();

    QTextDocument doc;
    doc.setHtml(options.text);

    options.text = "";
    options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);

    // shift text right to make icon visible
    QSize iconSize = options.icon.actualSize(options.rect.size());
    painter->translate(options.rect.left()+iconSize.width(), options.rect.top());
    QRect clip(0, 0, options.rect.width()+iconSize.width(), options.rect.height());

    //doc.drawContents(painter, clip);

    painter->setClipRect(clip);
    QAbstractTextDocumentLayout::PaintContext ctx;
    // set text color to red for selected item
    if (option.state & QStyle::State_Selected)
        ctx.palette.setColor(QPalette::Text, QColor("red"));
    ctx.clip = clip;
    doc.documentLayout()->draw(painter, ctx);

    painter->restore();
}

I guess you can use setItemDelegate method of the treeview to setup custom painter for your treeview items. In the delegate's paint method you can use QTextDocument to load item's text as html and render it. Please check if an example below would work for you:

treeview initialization:

...
    // create simple model for a tree view
    QStandardItemModel *model = new QStandardItemModel();
    QModelIndex parentItem;
    for (int i = 0; i < 4; ++i)
    {
        parentItem = model->index(0, 0, parentItem);
        model->insertRows(0, 1, parentItem);
        model->insertColumns(0, 1, parentItem);
        QModelIndex index = model->index(0, 0, parentItem);
        model->setData(index, "<span>blah-blah <b>some text</b> other blah</span>");
    }
    // create custom delegate
    HTMLDelegate* delegate = new HTMLDelegate();
    // set model and delegate to the treeview object
    ui->treeView->setModel(model);
    ui->treeView->setItemDelegate(delegate);
...

custom delegate implementation

class HTMLDelegate : public QStyledItemDelegate
{
protected:
    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
};

void HTMLDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 options = option;
    initStyleOption(&options, index);

    painter->save();

    QTextDocument doc;
    doc.setHtml(options.text);

    options.text = "";
    options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);

    painter->translate(options.rect.left(), options.rect.top());
    QRect clip(0, 0, options.rect.width(), options.rect.height());
    doc.drawContents(painter, clip);

    painter->restore();
}

QSize HTMLDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
    QStyleOptionViewItemV4 options = option;
    initStyleOption(&options, index);

    QTextDocument doc;
    doc.setHtml(options.text);
    doc.setTextWidth(options.rect.width());
    return QSize(doc.idealWidth(), doc.size().height());
}

hope this helps, regards

update0: changes to HTMLDelegate to make icons visible and different pen color for selected items

void HTMLDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 options = option;
    initStyleOption(&options, index);

    painter->save();

    QTextDocument doc;
    doc.setHtml(options.text);

    options.text = "";
    options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);

    // shift text right to make icon visible
    QSize iconSize = options.icon.actualSize(options.rect.size());
    painter->translate(options.rect.left()+iconSize.width(), options.rect.top());
    QRect clip(0, 0, options.rect.width()+iconSize.width(), options.rect.height());

    //doc.drawContents(painter, clip);

    painter->setClipRect(clip);
    QAbstractTextDocumentLayout::PaintContext ctx;
    // set text color to red for selected item
    if (option.state & QStyle::State_Selected)
        ctx.palette.setColor(QPalette::Text, QColor("red"));
    ctx.clip = clip;
    doc.documentLayout()->draw(painter, ctx);

    painter->restore();
}
两人的回忆 2024-08-23 04:07:00

我的回答主要受到@serge_gubenko 的启发。但是,进行了一些改进,使代码最终在我的应用程序中有用。

class HtmlDelegate : public QStyledItemDelegate
{
protected:
    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
};

void HtmlDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 optionV4 = option;
    initStyleOption(&optionV4, index);

    QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style();

    QTextDocument doc;
    doc.setHtml(optionV4.text);

    /// Painting item without text
    optionV4.text = QString();
    style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter);

    QAbstractTextDocumentLayout::PaintContext ctx;

    // Highlighting text if item is selected
    if (optionV4.state & QStyle::State_Selected)
        ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));

    QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4);
    painter->save();
    painter->translate(textRect.topLeft());
    painter->setClipRect(textRect.translated(-textRect.topLeft()));
    doc.documentLayout()->draw(painter, ctx);
    painter->restore();
}

QSize HtmlDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 optionV4 = option;
    initStyleOption(&optionV4, index);

    QTextDocument doc;
    doc.setHtml(optionV4.text);
    doc.setTextWidth(optionV4.rect.width());
    return QSize(doc.idealWidth(), doc.size().height());
}

My answer is mostly inspired by @serge_gubenko's one. However, there were made several improvements so that the code is finally useful in my application.

class HtmlDelegate : public QStyledItemDelegate
{
protected:
    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
};

void HtmlDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 optionV4 = option;
    initStyleOption(&optionV4, index);

    QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style();

    QTextDocument doc;
    doc.setHtml(optionV4.text);

    /// Painting item without text
    optionV4.text = QString();
    style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter);

    QAbstractTextDocumentLayout::PaintContext ctx;

    // Highlighting text if item is selected
    if (optionV4.state & QStyle::State_Selected)
        ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));

    QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4);
    painter->save();
    painter->translate(textRect.topLeft());
    painter->setClipRect(textRect.translated(-textRect.topLeft()));
    doc.documentLayout()->draw(painter, ctx);
    painter->restore();
}

QSize HtmlDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItemV4 optionV4 = option;
    initStyleOption(&optionV4, index);

    QTextDocument doc;
    doc.setHtml(optionV4.text);
    doc.setTextWidth(optionV4.rect.width());
    return QSize(doc.idealWidth(), doc.size().height());
}
紫瑟鸿黎 2024-08-23 04:07:00

这是对我有用的上述答案组合的 PyQt 转换。我希望 PySide 也能以同样的方式工作。

from PyQt4 import QtCore, QtGui

class HTMLDelegate(QtGui.QStyledItemDelegate):
    def paint(self, painter, option, index):
        options = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(options,index)

        style = QtGui.QApplication.style() if options.widget is None else options.widget.style()

        doc = QtGui.QTextDocument()
        doc.setHtml(options.text)

        options.text = ""
        style.drawControl(QtGui.QStyle.CE_ItemViewItem, options, painter);

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()

        # Highlighting text if item is selected
        #if (optionV4.state & QStyle::State_Selected)
            #ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));

        textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, options)
        painter.save()
        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        doc.documentLayout().draw(painter, ctx)

        painter.restore()

    def sizeHint(self, option, index):
        options = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(options,index)

        doc = QtGui.QTextDocument()
        doc.setHtml(options.text)
        doc.setTextWidth(options.rect.width())
        return QtCore.QSize(doc.idealWidth(), doc.size().height())

Here's the PyQt conversion of the combination of the above answers that worked for me. I would expect this to work virtually identically for PySide as well.

from PyQt4 import QtCore, QtGui

class HTMLDelegate(QtGui.QStyledItemDelegate):
    def paint(self, painter, option, index):
        options = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(options,index)

        style = QtGui.QApplication.style() if options.widget is None else options.widget.style()

        doc = QtGui.QTextDocument()
        doc.setHtml(options.text)

        options.text = ""
        style.drawControl(QtGui.QStyle.CE_ItemViewItem, options, painter);

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()

        # Highlighting text if item is selected
        #if (optionV4.state & QStyle::State_Selected)
            #ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));

        textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, options)
        painter.save()
        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        doc.documentLayout().draw(painter, ctx)

        painter.restore()

    def sizeHint(self, option, index):
        options = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(options,index)

        doc = QtGui.QTextDocument()
        doc.setHtml(options.text)
        doc.setTextWidth(options.rect.width())
        return QtCore.QSize(doc.idealWidth(), doc.size().height())
成熟稳重的好男人 2024-08-23 04:07:00

写出另一个关于如何在 C++ 中完成此操作的答案。与到目前为止提供的答案的区别在于,这是针对 Qt5 而不是 Qt4。然而最重要的是,前面的答案忽略了项目委托应该能够按照指定的方式对齐文本(例如在QTreeWidget中)。此外,我还实现了一种删除富文本的方法,以便获得与纯文本委托(在 ItemView 中)一致的感觉。

言归正传,下面是我的 RichTextDelegate 代码:

void RichTextItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &inOption,
                                 const QModelIndex &index) const {
    QStyleOptionViewItem option = inOption;
    initStyleOption(&option, index);

    if (option.text.isEmpty()) {
        // This is nothing this function is supposed to handle
        QStyledItemDelegate::paint(painter, inOption, index);

        return;
    }

    QStyle *style = option.widget ? option.widget->style() : QApplication::style();

    QTextOption textOption;
    textOption.setWrapMode(option.features & QStyleOptionViewItem::WrapText ? QTextOption::WordWrap
                                                                            : QTextOption::ManualWrap);
    textOption.setTextDirection(option.direction);

    QTextDocument doc;
    doc.setDefaultTextOption(textOption);
    doc.setHtml(option.text);
    doc.setDefaultFont(option.font);
    doc.setDocumentMargin(0);
    doc.setTextWidth(option.rect.width());
    doc.adjustSize();

    if (doc.size().width() > option.rect.width()) {
        // Elide text
        QTextCursor cursor(&doc);
        cursor.movePosition(QTextCursor::End);

        const QString elidedPostfix = "...";
        QFontMetrics metric(option.font);
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
        int postfixWidth = metric.horizontalAdvance(elidedPostfix);
#else
        int postfixWidth = metric.width(elidedPostfix);
#endif
        while (doc.size().width() > option.rect.width() - postfixWidth) {
            cursor.deletePreviousChar();
            doc.adjustSize();
        }

        cursor.insertText(elidedPostfix);
    }

    // Painting item without text (this takes care of painting e.g. the highlighted for selected
    // or hovered over items in an ItemView)
    option.text = QString();
    style->drawControl(QStyle::CE_ItemViewItem, &option, painter, inOption.widget);

    // Figure out where to render the text in order to follow the requested alignment
    QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &option);
    QSize documentSize(doc.size().width(), doc.size().height()); // Convert QSizeF to QSize
    QRect layoutRect = QStyle::alignedRect(Qt::LayoutDirectionAuto, option.displayAlignment, documentSize, textRect);

    painter->save();

    // Translate the painter to the origin of the layout rectangle in order for the text to be
    // rendered at the correct position
    painter->translate(layoutRect.topLeft());
    doc.drawContents(painter, textRect.translated(-textRect.topLeft()));

    painter->restore();
}

QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &inOption, const QModelIndex &index) const {
    QStyleOptionViewItem option = inOption;
    initStyleOption(&option, index);

    if (option.text.isEmpty()) {
        // This is nothing this function is supposed to handle
        return QStyledItemDelegate::sizeHint(inOption, index);
    }

    QTextDocument doc;
    doc.setHtml(option.text);
    doc.setTextWidth(option.rect.width());
    doc.setDefaultFont(option.font);
    doc.setDocumentMargin(0);

    return QSize(doc.idealWidth(), doc.size().height());
}

Writing up yet another answer for how this can be done in C++. The difference to the answers provided so far is that this is for Qt5 and not Qt4. Most importantly however the previous answers neglected that the item delegate should be able to align the text as specified (e.g. in a QTreeWidget). Additionally I also implemented a way to elide rich text in order to get a consistent feeling with plaintext delegates (in ItemViews).

So without further ado, here is my code for a RichTextDelegate:

void RichTextItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &inOption,
                                 const QModelIndex &index) const {
    QStyleOptionViewItem option = inOption;
    initStyleOption(&option, index);

    if (option.text.isEmpty()) {
        // This is nothing this function is supposed to handle
        QStyledItemDelegate::paint(painter, inOption, index);

        return;
    }

    QStyle *style = option.widget ? option.widget->style() : QApplication::style();

    QTextOption textOption;
    textOption.setWrapMode(option.features & QStyleOptionViewItem::WrapText ? QTextOption::WordWrap
                                                                            : QTextOption::ManualWrap);
    textOption.setTextDirection(option.direction);

    QTextDocument doc;
    doc.setDefaultTextOption(textOption);
    doc.setHtml(option.text);
    doc.setDefaultFont(option.font);
    doc.setDocumentMargin(0);
    doc.setTextWidth(option.rect.width());
    doc.adjustSize();

    if (doc.size().width() > option.rect.width()) {
        // Elide text
        QTextCursor cursor(&doc);
        cursor.movePosition(QTextCursor::End);

        const QString elidedPostfix = "...";
        QFontMetrics metric(option.font);
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
        int postfixWidth = metric.horizontalAdvance(elidedPostfix);
#else
        int postfixWidth = metric.width(elidedPostfix);
#endif
        while (doc.size().width() > option.rect.width() - postfixWidth) {
            cursor.deletePreviousChar();
            doc.adjustSize();
        }

        cursor.insertText(elidedPostfix);
    }

    // Painting item without text (this takes care of painting e.g. the highlighted for selected
    // or hovered over items in an ItemView)
    option.text = QString();
    style->drawControl(QStyle::CE_ItemViewItem, &option, painter, inOption.widget);

    // Figure out where to render the text in order to follow the requested alignment
    QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &option);
    QSize documentSize(doc.size().width(), doc.size().height()); // Convert QSizeF to QSize
    QRect layoutRect = QStyle::alignedRect(Qt::LayoutDirectionAuto, option.displayAlignment, documentSize, textRect);

    painter->save();

    // Translate the painter to the origin of the layout rectangle in order for the text to be
    // rendered at the correct position
    painter->translate(layoutRect.topLeft());
    doc.drawContents(painter, textRect.translated(-textRect.topLeft()));

    painter->restore();
}

QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &inOption, const QModelIndex &index) const {
    QStyleOptionViewItem option = inOption;
    initStyleOption(&option, index);

    if (option.text.isEmpty()) {
        // This is nothing this function is supposed to handle
        return QStyledItemDelegate::sizeHint(inOption, index);
    }

    QTextDocument doc;
    doc.setHtml(option.text);
    doc.setTextWidth(option.rect.width());
    doc.setDefaultFont(option.font);
    doc.setDocumentMargin(0);

    return QSize(doc.idealWidth(), doc.size().height());
}
丶情人眼里出诗心の 2024-08-23 04:07:00

这个在 PySide 中。我没有进行大量自定义绘图,而是将 QPainter 传递给 QLabel 并使其自行绘制。突出显示从其他答案借用的代码。

from PySide import QtGui

class TaskDelegate(QtGui.QItemDelegate):
    #https://doc.qt.io/archives/qt-4.7/qitemdelegate.html#drawDisplay
    #https://doc.qt.io/archives/qt-4.7/qwidget.html#render
    def drawDisplay(self, painter, option, rect, text):
        label = QtGui.QLabel(text)

        if option.state & QtGui.QStyle.State_Selected:
            p = option.palette
            p.setColor(QtGui.QPalette.WindowText, p.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))

            label.setPalette(p)

        label.render(painter, rect.topLeft(), renderFlags=QtGui.QWidget.DrawChildren)

This one is in PySide. Rather than doing a lot of custom drawing, I pass the QPainter to the QLabel and make it draw itself. Highlighting code borrowed from other answers.

from PySide import QtGui

class TaskDelegate(QtGui.QItemDelegate):
    #https://doc.qt.io/archives/qt-4.7/qitemdelegate.html#drawDisplay
    #https://doc.qt.io/archives/qt-4.7/qwidget.html#render
    def drawDisplay(self, painter, option, rect, text):
        label = QtGui.QLabel(text)

        if option.state & QtGui.QStyle.State_Selected:
            p = option.palette
            p.setColor(QtGui.QPalette.WindowText, p.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))

            label.setPalette(p)

        label.render(painter, rect.topLeft(), renderFlags=QtGui.QWidget.DrawChildren)
向日葵 2024-08-23 04:07:00

对于 PyQt5,jbmohler 的答案略有更新:一些类显然已转移到 QtWidgets。

这远远超出了我的工资水平(即 PyQt5 背后的具体细节的知识)。

我赞同塞西尔·库里对这个问题的评论中表达的观点。现在已经是 2021 年了,我们似乎仍然需要与这种黑客攻击作斗争。荒谬的。迄今为止,与 JavaFX 相比,Qt5 给我留下了深刻的印象。这种缺陷是令人失望的。

    class HTMLDelegate( QtWidgets.QStyledItemDelegate ):
        def __init__( self ):
            super().__init__()
            # probably better not to create new QTextDocuments every ms
            self.doc = QtGui.QTextDocument()
    
        def paint(self, painter, option, index):
            options = QtWidgets.QStyleOptionViewItem(option)
            self.initStyleOption(options, index)
            painter.save()
            self.doc.setTextWidth(options.rect.width())                
            self.doc.setHtml(options.text)
            self.doc.setDefaultFont(options.font)
            options.text = ''
            options.widget.style().drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)
            painter.translate(options.rect.left(), options.rect.top())
            clip = QtCore.QRectF(0, 0, options.rect.width(), options.rect.height())
            painter.setClipRect(clip)
            ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
            ctx.clip = clip
            self.doc.documentLayout().draw(painter, ctx)
            painter.restore()
    
        def sizeHint( self, option, index ):
            options = QtWidgets.QStyleOptionViewItem(option)
            self.initStyleOption(option, index)
            self.doc.setHtml(option.text)
            self.doc.setTextWidth(option.rect.width())
            return QtCore.QSize(self.doc.idealWidth(), self.doc.size().height())

Just a slight update from jbmohler's answer, for PyQt5: some classes have apparently been shifted to QtWidgets.

This is way beyond my paygrade (i.e. knowledge of the nuts and bolts behind PyQt5).

I echo the sentiment expressed in Cecil Curry's comment to the question. It is now 2021, and we appear still to have to struggle with this sort of hack. Ridiculous. I've been impressed by Qt5 to date, as compared to JavaFX for example. This deficiency is a let-down.

    class HTMLDelegate( QtWidgets.QStyledItemDelegate ):
        def __init__( self ):
            super().__init__()
            # probably better not to create new QTextDocuments every ms
            self.doc = QtGui.QTextDocument()
    
        def paint(self, painter, option, index):
            options = QtWidgets.QStyleOptionViewItem(option)
            self.initStyleOption(options, index)
            painter.save()
            self.doc.setTextWidth(options.rect.width())                
            self.doc.setHtml(options.text)
            self.doc.setDefaultFont(options.font)
            options.text = ''
            options.widget.style().drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)
            painter.translate(options.rect.left(), options.rect.top())
            clip = QtCore.QRectF(0, 0, options.rect.width(), options.rect.height())
            painter.setClipRect(clip)
            ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
            ctx.clip = clip
            self.doc.documentLayout().draw(painter, ctx)
            painter.restore()
    
        def sizeHint( self, option, index ):
            options = QtWidgets.QStyleOptionViewItem(option)
            self.initStyleOption(option, index)
            self.doc.setHtml(option.text)
            self.doc.setTextWidth(option.rect.width())
            return QtCore.QSize(self.doc.idealWidth(), self.doc.size().height())
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文