Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing an overlay on top of an application's window

Tags:

qt

paint

I want to be able to paint on top of my application's window so that I can annotate all the widgets with some extra diagnostic information, similar to the CSS developer tools in Firefox (eg add widget classes, styles, highlight borders etc).

I can walk the widget tree and extract the relevant information, but the question is how can I overlay all the application windows with this information?

One way would be to override my QMainWindow's paint event, but this has to be done for all top level windows. Is there an alternative method where you can paint on the QDesktopWidget for instance? Or any hooks into each QWidget's paint method? Anything that involves subclassing QWidget itself won't work with the standard widgets.

This follows on from my previous question:

  • Are there any useful tools for diagnosing Qt layout and spacing problems?

cheers Mandrill

EDIT: Thanks to Dmitry I've now got a really simple method that is easily extensible:

class DiagnosticStyle : public QWindowsVistaStyle
{
Q_OBJECT

public: 
    typedef QWindowsVistaStyle BaseStyle;
    void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const;
};


void DiagnosticStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
    BaseStyle::drawControl(element, option, painter, widget);
    if (widget && painter) {
        // draw a border around the widget
        painter->setPen(QColor("red"));
        painter->drawRect(widget->rect());

        // show the classname of the widget
        QBrush translucentBrush(QColor(255,246,240, 100));
        painter->fillRect(widget->rect(), translucentBrush);
        painter->setPen(QColor("darkblue"));
        painter->drawText(widget->rect(), Qt::AlignLeft | Qt::AlignVCenter, widget->metaObject()->className()); 
    }
}

qApp->setStyle(new DiagnosticStyle());
like image 553
the_mandrill Avatar asked May 06 '11 10:05

the_mandrill


2 Answers

You can create own style class based on QMotifStyle or other ... and paint on any widget/control related to him information.

void MyStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,QPainter *painter, const QWidget *widget) const
{
     QStyle::State flags = option->state;
     QRect      rect     = option->rect;
     QPalette   pal      = option->palette;
     QBrush brush;

    switch (element)
    {
        case PE_FrameTabWidget:
        {
             painter->save();

                 // for example: draw anything on TabWidget
                painter->drawPixmap(rect,centerPm,centerPm.rect());
             painter->restore();
        }
        break;
        default:
         QMotifStyle::drawPrimitive(element, option, painter, widget);
         break;

    }
}
like image 177
Dmitry Avatar answered Nov 14 '22 19:11

Dmitry


Somewhere in Qt5 the styles (GTK, Windows, etc) were made internal. Now you need to use QCommonStyle.

If anyone's wondering how to do this with Qt5+. Here's a self-contained version of @the_mandrill's code above.

class DiagnosticStyle : public QCommonStyle
{
Q_OBJECT

public: 
    typedef QStyle BaseStyle;
    void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
    {
        QCommonStyle::drawControl(element, option, painter, widget);
        if (widget && painter) {
            // draw a border around the widget
            painter->setPen(QColor("red"));
            painter->drawRect(widget->rect());

            // show the classname of the widget
            QBrush translucentBrush(QColor(255,246,240, 100));
            painter->fillRect(widget->rect(), translucentBrush);
            painter->setPen(QColor("darkblue"));
            painter->drawText(widget->rect(), Qt::AlignLeft | Qt::AlignVCenter, widget->metaObject()->className()); 
        }
    };
};

Then, in your main window constructor call

qApp->setStyle(new DiagnosticStyle());
like image 41
Alchete Avatar answered Nov 14 '22 19:11

Alchete