QWidget paint event draw over children



  • I have a custom subclass of QTabWidget. The tab widget contains QTextEdit widgets as children. I would like to render rectangles on the side of my tab widget to indicate when a drop action is possible. For that purpose, I overwrite the QTabWidget::paintEvent() function:

    void TabWidget::paintEvent(QPaintEvent* event)
    {
        // Default rendered
        QTabWidget::paintEvent(event);
    
        // Render the drop zone rect (if any)
        if (!_dropZoneRect.isNull()) {
            QPainter painter(this);
    
            painter.setPen(Qt::NoPen);
            painter.setBrush(QBrush(Qt::lightGray));
            painter.drawRect(_dropZoneRect);
        }
    }
    

    The problem that I am facing is that it appears that the children of the tab widget are getting painted AFTER the TabWidget::paintEvent() function has been called. Therefore, I see my rectangle around the border of the TabWidget but the QTextEdit children are painted above that.
    How can I paint something above my custom QTabWidget so that it covers the child widget too?

    Thanks for the help.


  • Moderators

    There's no way to paint over child widgets in the parent class (that I know of). You would need an "overlay" widget i.e. a widget that is positioned exactly above your tab widget and draw the rectangle there (something like what QRubberBand does). Since you use it only while a drag is happening it shouldn't be a problem. No need to worry about resizing and other events since a drag is happening.



  • Well that's unexpected...
    May I ask what the reason for this behavior is? I would have expected that the QTabWidget::paintEvent() renders the tab widget and it's children and after that I can perform my drawing operation which will (obviously?) occur above what has been drawn before.

    Anyway, I got it doing what I want it to do by following your advice of rendering a widget on top of the tab widget. For some reason I don't like this solution but as long as that is the way that I am supposed to do it I can life with it :)


  • Qt Champions 2016

    @Joel-Bodenmann said:

    May I ask what the reason for this behavior is?

    This might be answered by the developers, I for one don't know the internals so well. I would assume that the paint event is sent only to the relevant widgets (based on geometry) for performance (e.g. you don't need to repaint widgets that hadn't been obscured by other windows and then exposed).

    I would have expected that the QTabWidget::paintEvent() renders the tab widget and it's children and after that I can perform my drawing operation which will (obviously?) occur above what has been drawn before.

    QTabWidget::paintEvent paints only the tab bar, not the children it contains. But in any case I don't know of a widget that explicitly repaints it children. I believe Qt sends the appropriate paint events to all affected widgets based on their geometry (i.e. depending on the "dirty" region).

    Kind regards.



  • @kshegunov Thank you for the information. Much appreciated!


  • Qt Champions 2016

    @Joel-Bodenmann
    Well, it's mostly speculation, but you're welcome. :)



  • @Chris-Kawa It turned out that QRubberBand is EXACTLY what I wanted. I am now using that successfully to display the drop zones. Thank you for introducing me to that :)


Log in to reply
 

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