كيفية جعل عرض العنصر عرض نص غني (HTML) في QT
سؤال
افترض أن النموذج الخاص بي يحتوي على عناصر مع السلسلة التالية لـ QT :: DisplayRole
<span>blah-blah <b>some text</b> other blah</span>
أريد QtreeView (في الواقع ، أي طريقة عرض عنصر) لتقديمه مثل نص غني. بدلاً من ذلك ، تجعل طرق عرض العناصر مثل النص الخالص افتراضيًا. كيف تحقق العرض المطلوب؟
في الواقع ، هذا هو نموذج نتائج البحث. يدخل المستخدم نصًا ، يتم البحث في بعض المستند مقابل هذا النص ويتم تقديم المستخدم مع نتائج البحث ، حيث يجب أن تكون الكلمات التي يتم البحث فيها أكثر جرأة من النص المحيط.
المحلول 2
إجابتي مستوحاة في الغالب من @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());
}
نصائح أخرى
أعتقد أنه يمكنك استخدام SetItemDelegate طريقة TreeView لإعداد رسام مخصص لعناصر TreeView الخاصة بك. في طريقة الطلاء في المندوب ، يمكنك استخدام QTextDocument لتحميل نص العنصر كـ HTML وتقديمه. يرجى التحقق مما إذا كان مثال أدناه سيعمل من أجلك:
تهيئة Treeview:
...
// 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();
}
إليكم تحويل PYQT لمجموعة الإجابات أعلاه التي عملت بالنسبة لي. أتوقع أن يعمل هذا بشكل متطابق تقريبًا مع بيسايد أيضًا.
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())
هذا واحد في بيسايد. بدلاً من القيام بالكثير من الرسم المخصص ، أقوم بتمرير 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)