[SOLVED] Modify QTableWidget's paintEvent()



  • Hello,

    First of all - Happy New Year ;-)

    I'm using a QTableWidget (actually a class based on it) and instances of QTableWidgetItem (also subclassed) in my application. I have a problem modifying QTableWidget's paintEvent(). I'd like to add to the copied cells a rectangle made of Qt::DashDotLine. This is actually my first try to alter ways of stuff being painted on the screen and probably that's why I have no idea how to work with it.

    Code:
    @void myTable::paintEvent(QPaintEvent e)
    {
    QTableWidget::paintEvent(e);
    for(int r = 0; r < rowCount(); r++)
    {
    for(int c = 0; c < columnCount(); c++)
    {
    if(((myCell
    )itemAt(r, c))->isCopied())
    {
    QPainter p(this);
    p.setPen(QPen(Qt::cyan, Qt::DashDotLine));
    p.setBrush(QBrush(Qt::cyan));
    int x = columnViewportPosition(c);
    int y = rowViewportPosition(r);
    int w = columnWidth(c);
    int h = rowHeight(r);
    p.drawRect(QRect(columnViewportPosition(c) + 2, rowViewportPosition(r) + 2, columnWidth(c) - 4, rowHeight(r) - 4));
    }
    }
    }
    }@
    So as you can see first of all I run the default paintEvent() of the widget and then try to apply some changes. I go through all items in the table and check if their copied flag is set to true (this is the only modification I made to QTableWidgetItem class - added that flag ;-) ). If it's true I'd like to paint the rectangle I was talking about.

    What am I doing wrong?

    Thank you in advance for your help,

    Daniel.



  • The actual painting of individual cells is done in an "item delegate":/doc/qt-4.8/model-view-programming.html#delegate-classes. The standard delegate for all Qt builtin item view and item widgets is [[Doc:QStyledItemDelegate]]. I recommend subclassing this one and reimplement its paint method. You can get the data from the QTableWidgetItem by using the data() method on the index passed to paint().



  • Well, it seemed pretty easy as I read what you wrote. It probably is if you know the Model/View programming concept. Since I don't know it and I've spent over two hours trying to find a solution I will ask for your help again.

    I am trying to do what you suggested. The way I wanted to use in my first post gave me access to myCell's object isCopied() method. I have no idea how to access it from the delegate I created (from it's paint() method actually). There's only 3 parameters to this method: a QPainter, a QStyleOptionViewItem and a QModelIndex.

    How can I access isCopied() method of a modified QTableWidgetItem from my delegates paint() method?

    I know I should have read the whole documentation and start from the basics... please don't throw stones at me for that.



  • I would make the implementation of the isCopied() property based on the item views data()/setData() methods. You can start with this sketch:

    In the header of your table widget item subclass add:

    @
    enum MyItemRoles { IsCopiedRole = Qt::UserRole };
    @

    Then change the implementation of isCopied() to:

    @
    bool MyTableWidgetItem::isCopied() const
    {
    QVariant v = data(IsCopiedRole);
    if(v.isValid())
    return v.toBool();
    else
    return false;
    }

    void MyTableWidgetItem::setIsCopied(bool copied)
    {
    setData(UserRole, copied);
    }
    @

    This changes make your implementation use the internal storage already provided by QTableWidgetItem while keeping your sources compatible with the current implementation.

    In your delegate (and in any other spot where you only have a [[Doc:QModelIndex]] at hand, use the following snippet to retrieve the value:

    @
    // assuming you inherit from QStyledItemDelegate

    void MyItemDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
    {
    // call the base class paint method first
    QStyledItemDelegate::paint(painter, option, index);

    // is the current index a copy?
    QVariant isCopyVariant = index.data(MyTableWidgetItem::IsCopiedRole);
    bool isCopied = isCopyVariant.isValid() ? isCopyVariant.toBool() : false;
    
    // your additional drawing code goes here...
    
    if(isCopied) {
        // save the painter's state
        painter->save();
    
        // translate the painter's origin
        painter->translate( option.rect.topLeft() );
    
        // set the painter's pen & brush
        painter->setPen(QPen(Qt::cyan, Qt::DashDotLine));
        painter->setBrush(QBrush(Qt::cyan));
    
        // get the rect of the item to draw:
        QRect rect = option.rect;
    
        // adjust the rect to your needs
        rect.adjust(2, 2, -4, -4);
    
        painter.drawRect(rect);
    
        // restore the painter's state
        painter->restore();
    }
    

    }
    @

    This is from brain to terminal - no guarantee to error-free compilation, but you should get the big picture.



  • What you might do, is to make sure that you define your own data role that will provide that information for your item. You can access the data from the item using the QModelIndex.



  • Aah, alright. That's brilliant. I really have to read about and learn Model/View architecture. Thank you very much Volker and Andre. I actually had a look at data() and setData() methods but after a short read, for some reason, I decided they won't help me ;-).

    Once again - thank you!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.