Question

In my application i have an annoying white rectangle on tabstop controls. I tried to look in stylesheets but myitem:tabstop style don't do anything. Is there any way i can somehow change tabstop color/or make it another form.

Was it helpful?

Solution

Unfortunately the focus rectangle is not something that can be affected by the style sheets. Stylesheets are amazing, but sadly there are some restrictions.

There is a way to get rid of the focus rectangle - here is an example of how to do it for buttons. Although, you would have to handle this control by control. Basically what this is doing is in the rendering of the control, you are ignoring the focussed state, and drawing the control as if it isn't focussed.

To completely change how the focus rectangle looks I suppose you can override the primitive itself. A lot of widgets are made up of re-usable primitives. So when creating a QStyle object we can override how certain widgets or certain primitives are drawn.

So in your case you would create a QStyle class something like the following:

class CustomStyle : public QWindowsStyle
{
    Q_OBJECT

public:
    CustomStyle() {}

    void drawPrimitive(PrimitiveElement which,
                       const QStyleOption *option, QPainter *painter,
                       const QWidget *widget = 0) const;

}

Then in the implementation you would provide the means to draw the focus rectangle however you like. Below is the the default Windows implementation.

void CustomStyle::drawPrimitive(PrimitiveElement which,
                                const QStyleOption *option,
                                QPainter *painter,
                                const QWidget *widget) const
{
    switch (which) {
    case PE_FrameFocusRect:
        if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
        //### check for d->alt_down
        if (!(fropt->state & State_KeyboardFocusChange) && !proxy()->styleHint(SH_UnderlineShortcut, opt))
            return;
        QRect r = opt->rect;
        p->save();
        p->setBackgroundMode(Qt::TransparentMode);
        QColor bg_col = fropt->backgroundColor;
        if (!bg_col.isValid())
            bg_col = p->background().color();
        // Create an "XOR" color.
        QColor patternCol((bg_col.red() ^ 0xff) & 0xff,
                          (bg_col.green() ^ 0xff) & 0xff,
                          (bg_col.blue() ^ 0xff) & 0xff);
        p->setBrush(QBrush(patternCol, Qt::Dense4Pattern));
        p->setBrushOrigin(r.topLeft());
        p->setPen(Qt::NoPen);
        p->drawRect(r.left(), r.top(), r.width(), 1);    // Top
        p->drawRect(r.left(), r.bottom(), r.width(), 1); // Bottom
        p->drawRect(r.left(), r.top(), 1, r.height());   // Left
        p->drawRect(r.right(), r.top(), 1, r.height());  // Right
        p->restore();
    }
        break;
    default:
        QWindowsStyle::drawPrimitive(which, option, painter, widget);
    }
}

Then simply provide your style class to your application

QApplication::setStyle(new CustomStyle);

The down-side here, is that by subclassing QWindowsStyle, we are locking the application into a windows look and feel. There are other base styles you can use other than the windows one (such as QMacStyle, etc...), but the point is that you should know what you are getting into before going down this road.

This is a good article about QStyles and how to use the power of them to your benefit.

EDIT:

For users of Qt5 the QWindowsStyle has now been made private, see here for a quick explanation. But in theory everything that could be done with QWindowsStyle can be done with the new class QProxyStyle. See here for a quick example. I think the good news is that you are not locking into a specific base style (like QWindowsStyle). Which is good.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top