2009-12-24 67 views
40

Giả sử mô hình của tôi có mục có chuỗi sau đây cho Qt :: DisplayRoleLàm thế nào để làm cho xem mục làm giàu (html) văn bản trong Qt

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

Tôi muốn QTreeView (trên thực tế, bất kỳ xem mục) để render nó như một văn bản phong phú. Thay vào đó, chế độ xem mục hiển thị nó giống như văn bản thuần túy theo mặc định. Làm thế nào để đạt được kết xuất mong muốn?


Thực ra, đây là mô hình kết quả tìm kiếm. Người dùng nhập văn bản, một số tài liệu được tìm kiếm dựa vào văn bản đó và người dùng được trình bày với kết quả tìm kiếm, nơi các từ được tìm kiếm sẽ đậm hơn văn bản xung quanh.

Trả lời

19

Câu trả lời của tôi chủ yếu được lấy cảm hứng từ @ serge_gubenko. Tuy nhiên, đã có một số cải tiến để mã cuối cùng cũng hữu ích trong ứng dụng của tôi.

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()); 
} 
+0

lưu ý rằng phần ctx.palette.setcolor cần thêm lồng nhau nếu tài khoản cho tùy chọnV4.state không hoạt động.Nếu không, khi bạn di chuyển đến một cửa sổ khác, văn bản trở nên gần như không đọc được. Hoạt động tuyệt vời nếu không. Cảm ơn – mmccoo

+3

Lưu ý màu văn bản: Sử dụng 'else ctx.palette.setColor (QPalette :: Văn bản, tùy chọnV4.palette.color (QPalette :: Hoạt động, QPalette :: Văn bản));' để đảm bảo màu văn bản được đặt chính xác. Cần thiết khi sử dụng màu văn bản không mặc định thông qua biểu định kiểu. –

+2

Thiết lập QTextDocument: Nếu bạn thêm 'doc.setDocumentMargin (0); doc.setDefaultFont (optionV4.font); '(thêm nó vào cả paint & sizeHint) thì các phông chữ sẽ đúng khi bạn thay đổi chúng thông qua stylesheet. Ngoài ra, các cuộc gọi 'doc.setTextWidth' trong thói quen sizeHint dường như không làm gì cả. Nếu bạn đặt nó trong cả hai phương thức 'sizeHint' và' paint' thì bạn có thể có các từ biến mất thay vì bị cắt bỏ khi cột của mục co lại. –

34

Tôi đoán bạn có thể sử dụng phương thức setItemDelegate của treeview để thiết lập họa sĩ tùy chỉnh cho các mục treeview của bạn. Trong phương thức vẽ của đại biểu, bạn có thể sử dụng QTextDocument để tải văn bản của mục dưới dạng html và hiển thị nó. Hãy kiểm tra xem một ví dụ dưới đây sẽ làm việc cho bạn:

treeview khởi:

... 
    // 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); 
... 

thực hiện tùy chỉnh đại biểu

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()); 
} 

hy vọng điều này giúp, coi

update0: thay đổi HTMLĐăng ký để hiển thị các biểu tượng và màu bút khác nhau cho các mục được chọn

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(); 
} 
+0

Cảm ơn câu trả lời của bạn. Trên thực tế, tôi đã chơi với đại biểu quan trọng và QTextDocument. Tuy nhiên, đã xảy ra sự cố với kích thước của các mục. Câu trả lời của bạn đã chỉ cho tôi 'initStyleOption' và' widget-> style() -> drawControl'. Giải pháp của bạn tuyệt vời trừ hai vấn đề. 1. Văn bản đang được vẽ trên biểu tượng mục 2. Mục được chọn phải có màu văn bản khác. Cố gắng tìm ra cách khắc phục chúng. –

+0

hãy kiểm tra bản cập nhật0 cho bài đăng gốc; thay đổi nằm trong phương thức HTMLDelegate :: paint. Để hiển thị biểu tượng, tôi chỉ cần di chuyển văn bản sang phải chiều rộng của biểu tượng. Đối với màu văn bản, tôi đã phải thay đổi các thiết lập bảng màu cho màu văn bản của đối tượng bối cảnh sơn. Hy vọng đây là những gì bạn đang tìm kiếm, liên quan đến –

+0

@Anton bạn có tìm ra cách sửa đổi màu văn bản đã chọn không? – To1ne

15

Đây là chuyển đổi PyQt kết hợp các câu trả lời ở trên phù hợp với tôi. Tôi hy vọng điều này sẽ hoạt động gần như giống hệt với 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()) 
+1

Thật là một hack! Ugh, nhưng cảm ơn. Đánh dấu: nếu options.state & QtGui.QStyle.State_Selected: ctx.palette.setColor (QtGui.QPalette.Text, options.palette.color (QtGui.QPalette.Active, QtGui.QPalette.HighlightedText)) – Pepijn

+3

Sau dòng: ' doc.setHtml (options.text) ', bạn cũng cần phải đặt' doc.setTextWidth (option.rect.width()) ', nếu không ủy nhiệm sẽ không hiển thị nội dung dài hơn một cách chính xác trong vùng vẽ mục tiêu. Ví dụ không bao bọc các từ trong QListView. – Timo

4

Đây là một trong PySide. Thay vì làm nhiều bản vẽ tùy chỉnh, tôi chuyển QPainter đến QLabel và làm cho nó vẽ chính nó. Mã đánh dấu được mượn từ các câu trả lời khác.

from PySide import QtGui 

class TaskDelegate(QtGui.QItemDelegate): 
    #http://doc.qt.nokia.com/4.7/qitemdelegate.html#drawDisplay 
    #http://doc.qt.nokia.com/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) 
+1

Không làm việc cho tôi, tôi chỉ thấy một phần rất nhỏ của văn bản, ngẫu nhiên và một số mục. – WhyNotHugo

+0

Đối với những người cần nó: Tôi sửa đổi @Pepijn trả lời một chút để cũng bao gồm các nhãn nhiều dòng trong http://stackoverflow.com/a/38028318/1504082 – maggie

Các vấn đề liên quan