Search code examples
c++qtqt5qstyleditemdelegateqtextdocument

Displaying QTableWidgetItem's text with different colors via a QStyledItemDelegate


I want to display parts of the text of a QTableWidgetItem in different colors (a part of it should be displayed red).

What I found is using a QStyledItemDelegate, reimplementing the paint function and display a QTextDocument that uses the the item text and added HTML.

This enables HTML for the text:

void DifferencesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                const QModelIndex &index) const
{
    painter->save();

    QTextDocument document;
    document.setHtml(index.data().toString());
    document.setPageSize(option.rect.size());

    QAbstractTextDocumentLayout::PaintContext context;
    painter->translate(option.rect.x(), option.rect.y());
    document.documentLayout()->draw(painter, context);

    painter->restore();
}

However, the result has some pixels offset compared to the "normal" display (which could most probably fixed somehow in a consistent way), but I wonder if there's a simpler method. I do not need HTML at all, I just want to change the color of some part of the text.

So is it possible to draw the item's text (letter by letter) and to set the color for each letter without having to use a QTextDocument?


Solution

  • I think there is no standard way to paint such things in Qt. Look at the code below. You can draw each particular character of the text. In this case you should calculate the character paint place opt.rect manually. But it works. In the example characters have red and green colors.

    void DifferencesDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, 
                                     const QModelIndex& index ) const
    {
      painter->save();
    
      QColor colors[2] = {Qt::red, Qt::green};
      QStyleOptionViewItem opt = option;
      initStyleOption(&opt, index);
      opt.text.clear();
    
      QStyle* style = opt.widget ? opt.widget->style() : QApplication::style();
      style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
    
      QString text = index.data().toString();
    
      for (int i = 0, t = text.count(); i < t; ++i)
      {
        opt.text = text[i];
        painter->setPen(QColor(colors[i % 2]));
        opt.rect.moveRight(opt.rect.right() + 10); // <-- calculate the character paint place
        style->drawItemText(painter, opt.rect, opt.displayAlignment, opt.palette, true, 
                            opt.text);
      }
    
      painter->restore();
    }