在使用 Qt 开发图形界面的时候,我们难免要对各种控件进行重新绘制。记录一下我绘制 PE_FrameFocusRect 的经过。

PE_FrameFocusRect

绘制 QListWidgetItem 的选中框需要用到 QStyle::drawPrimitiveQStyle::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_FrameFocusRectQWindowsStyleQFusionStyle 的实现对比。

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 风格下也要参照源码的条件判断。


IcedBabyccino
1 声望0 粉丝

编程、潮流