3

I would like to draw a line inside QTableWidgetItem. To draw the line I have reimplemented the QStyledItemDelegate::paint method.

But, when I'm scrolling or selecting an item in the QTableWidget. Some of the items loose their drawing effect.

Here's my paint implementation:

void DrawLineDelegate::paint(QPainter *poPainter, const QStyleOptionViewItem &oOption, const QModelIndex &oIndex) const
{
    // Valid index ?
    if(!oIndex.isValid())
        // Not valid.
        return;

    const QRect oRect( oOption.rect );

    // Painter has certain settings
    poPainter->save();

    // Draw line
    QColor oLineColor (oIndex.data(Qt::UserRole).toString());

    poPainter->setRenderHint(QPainter::Antialiasing);
    poPainter->setPen(QPen(oLineColor, 2, Qt::SolidLine, Qt::RoundCap));
    poPainter->drawLine(oRect.left(),                       // Start X-coordinate
                        oRect.top() - oRect.height() / 2 ,  // Center Height (Y-coordinate)
                        oRect.left() + oRect.width(),       // Line width
                        oRect.top() - oRect.height() / 2);  // Center Height (Y-coordinate)

    poPainter->restore();

    QStyledItemDelegate::paint( poPainter, oOption, oIndex );
}

In the TableWidget init function I set the delegate item like this

ui->tableWidget->setItemDelegateForColumn(2, new DrawLineDelegate(this) );

Note : Each item I store color name as Qt::UserData.

On table init the lines are drawing fine, the bug is when I'm playing with the table.

Here are some screenshots

Before scrolling

After scrolling

After row selection

Any suggestions ?

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Simon
  • 1,522
  • 2
  • 12
  • 24
  • 1
    Why do you think that the styled item delegate should paint *after* you draw the line? The item must have its background painted before you draw the line. Whatever the problem is, potentially overdrawing your line only makes things worse. You should let the styled delegate paint *always*, but do it first. The `return` without calling the base implementation is wrong. – Kuba hasn't forgotten Monica Sep 16 '15 at 12:18
  • Ok, I moved the base QStyledItemDelegate paint function before the drawing, and still have the same problem. – Simon Sep 16 '15 at 12:52

1 Answers1

3

OK, I succeed to solve my problem thanks to Kuba Ober hint.

Fixes:

  1. I missed calculate the line height, cause it to go out of the table item boundary. (so I switched the '-' to '+' in the DrawLine function)
  2. Added row selection highlight handling.
  3. Moved the base QStyledItemDelegate paint function before the drawing.

Here is the complete working answer.

void DrawLineDelegate::paint(QPainter *poPainter, const QStyleOptionViewItem &oOption, const QModelIndex &oIndex) const
{
    QStyle *poStyle;
    bool bSelected;

    // Valid index ?
    if(!oIndex.isValid())
        // Not valid.
        return;

    QStyledItemDelegate::paint( poPainter, oOption, oIndex );

    if (oIndex.column() == COLUMN_COLOR_ID) {

        const QRect oRect( oOption.rect );
        QColor oLineColor (oIndex.data(Qt::UserRole).toString());

        QStyleOptionViewItemV4 oOptv4 = oOption;
        initStyleOption(&oOptv4, oIndex);

        const QWidget *poWidget = oOption.widget;

        // Style option
        poStyle =
                poWidget ? poWidget->style() : QApplication::style();

        // Set pen
        poPainter->setPen(QPen(oLineColor, 2, Qt::SolidLine, Qt::RoundCap));

        // Selection state
        bSelected =
                oOption.state&QStyle::State_Selected;

        // Item selected ?
        if (bSelected)
        {
            poPainter->setBrush(oOption.palette.highlightedText());
            // This call will take care to draw line while selecting
            poStyle->drawControl(QStyle::CE_ItemViewItem, &oOptv4, poPainter, poWidget);
        }

        // Draw line in the middle of the item
        poPainter->drawLine( oRect.left(),                          // Start X-coordinate
                             oRect.top() + oRect.height() / 2,      // Center Height (Y-coordinate)
                             oRect.left() + oRect.width(),          // Line width
                             oRect.top()  + oRect.height() / 2);    // Center Height (Y-coordinate)
    }


}   
Simon
  • 1,522
  • 2
  • 12
  • 24