在使用 Qt 开发图形界面的时候,我们难免要对各种控件进行重新绘制。记录一下我绘制 PE_FrameFocusRect
的经过。
PE_FrameFocusRect
绘制 QListWidgetItem
的选中框需要用到 QStyle::drawPrimitive
和 QStyle::PE_FrameFocusRect
。并且需要创建一个 QStyleOptionFocusRect
对象 ,它包含一个成员变量 QColor backgroundColor
。根据 Qt 文档我一开始以为修改这个背景颜色,就可以简单地修改 QStyle::PE_FrameFocusRect
的背景色,但事实上并非如此,这个 backgroundColor
成员的使用与否取决于不同的 QStyle
的具体实现。
QColor QStyleOptionFocusRect::backgroundColor
This variable holds the background color on which the focus rectangle is being drawn
The default value is an invalid color with the RGB value (0, 0, 0). An invalid color is a color that is not properly set up for the underlying window system.
我在绘制 QStyle::PE_FrameFocusRect
的时候就经历过失败,无论 QStyleOptionFocusRect::backgroundColor
设为什么颜色都没用。后来我发现了在不同的风格下 QStyle::drawPrimitive
的实现是很不一样的。我的项目是 Fusion 风格,所以根本没有用到 QStyleOptionFocusRect::backgroundColor
。下面是 QStyle::PE_FrameFocusRect
在 QWindowsStyle
与 QFusionStyle
的实现对比。
qfusionstyle.cpp
QColor highlight(const QPalette &pal) const {
if (isMacSystemPalette(pal))
return QColor(60, 140, 230);
return pal.color(QPalette::Highlight);
}
QColor highlightedOutline(const QPalette &pal) const {
QColor highlightedOutline = highlight(pal).darker(125);
if (highlightedOutline.value() > 160)
highlightedOutline.setHsl(highlightedOutline.hue(), highlightedOutline.saturation(), 160);
return highlightedOutline;
}
void QFusionStyle::drawPrimitive(
PrimitiveElement elem,
const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
QColor highlightedOutline = d->highlightedOutline(option->palette);
// .......
case PE_FrameFocusRect:
if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(option)) {
//### check for d->alt_down
if (!(fropt->state & State_KeyboardFocusChange))
return;
QRect rect = option->rect;
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
painter->translate(0.5, 0.5);
QColor fillcolor = highlightedOutline;
fillcolor.setAlpha(80);
painter->setPen(fillcolor.darker(120));
fillcolor.setAlpha(30);
QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
gradient.setColorAt(0, fillcolor.lighter(160));
gradient.setColorAt(1, fillcolor);
painter->setBrush(gradient);
painter->drawRoundedRect(option->rect.adjusted(0, 0, -1, -1), 1, 1);
painter->restore();
}
break;
//........
}
qwindowsstyle.cpp
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;
所以在 Fusion 风格下,绘制 QStyle::PE_FrameFocusRect
需要注意两点。一,需要设置 QStyleOption::QPalette
中的 QPalette::Highlight
的颜色;二,就是要设 QStyleOption::state
中的 State_KeyboardFocusChange
位。同理,Windows 风格下也要参照源码的条件判断。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。