Pens, brushes, colors, and … brushes.

QPalette is a wonderful class, but it's easy to get confused when trying to deal with it "properly", that is, always draw the correct shape with the right look based on the current palette.

Issues emerge quickly for style authors (or widget authors that pick colors from the palette). It starts with painter brushes and pens, which are easily confused with palette brushes and colors. It then moves onto QPalette roles as opposed to widget roles. If you want to use the QPalette::Base color role when filling a rect using a brush, you have the choice to either select the palette brush or color for the painter brush. And you can set a palette brush onto a painter pen, if you want to draw texture lines or gradient lines. But what happens if the widget is set up to use a different background role?

The widget background role is, among other things, used by the window system to draw the widget's system background. It is also used by Qt to decide what to fill the exposed/updated widget background with before paintEvent() is invoked. So if you set Qt::WA_NoSystemBackground, which implicitly sets Qt::WA_NoBackground (Qt::WA_OpaquePaintEvent in Qt 4.1), the widget background role is no longer used by Qt. For this reason, the widget background role should not be a great concern of the style writer - any attempt to use it (for blending, or dithering perhaps) doesn't adapt well to changes in the widget surroundings or ancestry. If you need it when writing a style, you can access it through the individual style functions' widget pointers (remember to check for w == 0!).

The painter pen is used for stroking (sic), *cough*, drawing outlines. The painter brush is used for filling shapes when calling "draw" operations on the painter. So if you draw a rect by calling QPainter::drawRect(), the painter pen will draw the rect outline, and the painter brush will be used to fill the inside of the rectangle. If you do not set the brush (or set the brush equal to Qt::NoBrush), the rect will not be filled, and similar with the pen, the rect will not get stroked.

The palette brush can be set on either a painter pen or a painter brush. You will typically see code like this for when drawing lines using a texture or a gradient:

// Use the QPalette::Button role's brush entry as a pen
painter->setPen(QPen(palette.button(), 0));
painter->drawLine(rect.topLeft(), rect.topRight());

And if the Button role of the palette has a texture brush, you'll get a "texture line", as opposed to the common plain-old-color line. You can think of the palette brush as really just an extension of QColor that is commonly used for filling, in conjunction with a painter brush. But you can also set a palette brush on a painter pen. Because QBrush can contain a color, the palette color is mostly for simplicity (as generating a color palette is faster and easier to work with).

Motif Plastique 2 /research
A Motif screenshot A Plastique 2 screenshot
Motif style works quite OK with different variations over the palette. Plastique style, work in progress, is already looking pretty good.

Understanding the relationship between colors, pens, brushes, brushes, and roles is essential when writing an adaptable modern style. And it's tough work; some would say it's questionable to try to make a style support all types of palette variations. But if you get it right, the results can be quite pleasing.

Blog Topics: