qstyle 一步一个jio印(2)——子元素编辑 样式效果初现

13 篇文章 0 订阅
9 篇文章 0 订阅
接着干!

以弄好一个pushbutton为目标,使劲的去看代码并抄一抄流程,适当进行改动能深入理解该地方的用处!

还是先整合好框架然后留空

通过查阅资料观察流程,得到基本原理。每个控件有若干个子元素构成,而插件通过修改编辑这些子元素打到修改控件外观的效果。

所以步骤是一样的,代码和网上说的也差不多。基本都是编写好父类的虚函数就行了

ok我们的主要编辑文件mystyle这个类,开始对它动手动脚。

虚函数polish()

有三个:

  1. virtual void polish(QWidget *widget);
  2. virtual void polish(QPalette &palette);
  3. virtual void unpolish(QWidget *widget);

第一个设置一下悬浮,重载一下事件过滤(虽然也没写新的),再调用一下父类:

void MyStyle::polish(QWidget *widget)
{
    if (!widget)
        return;

    if (qobject_cast<QPushButton *>(widget))
        widget->setAttribute(Qt::WA_Hover);

    if (!widget->parent() || !qobject_cast<QWidget *>(widget->parent()) || qobject_cast<QDialog *>(widget) || qobject_cast<QMainWindow *>(widget)) {
        addEventFilter(widget);
    }

    // base class polishing
    QCommonStyle::polish(widget);
}

第二个看名字就知道是设置调色版,先随意吧,太长了,大概就那些玩意儿,直接搬过来就是:

void MyStyle::polish(QPalette &palette)
{
    // Colors defined in GTK adwaita style in _colors.scss
    QColor base_color = QColor("#2c9dfc");
    QColor text_color = QColor("black");
    QColor bg_color = QColor("#f6f5f4");
    QColor fg_color = QColor("#2e3436");
    QColor selected_bg_color = QColor("#3584e4");
    QColor selected_fg_color = QColor("white");
    QColor osd_text_color = QColor("white");
    QColor osd_bg_color = QColor("black");
    QColor shadow = _helper->transparentize(bg_color, 0.9);

    QColor backdrop_fg_color = _helper->mix(fg_color, bg_color);
    QColor backdrop_base_color = _helper->darken(base_color, 0.01);
    QColor backdrop_selected_fg_color = backdrop_base_color;

    // This is the color we use as initial color for the gradient in normal state
    // Defined in _drawing.scss button(normal)
    QColor button_base_color = _helper->darken(QColor("#ffffff"), 0.04);

    QColor link_color = _helper->darken(selected_bg_color, 0.1);
    QColor link_visited_color = _helper->darken(selected_bg_color, 0.2);

    palette.setColor(QPalette::All,      QPalette::Window,          bg_color);
    palette.setColor(QPalette::All,      QPalette::WindowText,      fg_color);
    palette.setColor(QPalette::All,      QPalette::Base,            base_color);
    palette.setColor(QPalette::All,      QPalette::AlternateBase,   base_color);
    ...
    ...
    ...
}

第三个析构,也是直接回归父类就行:

void MyStyle::unpolish(QWidget *widget)
{
    QCommonStyle::unpolish(widget);
}

pixelMetric、subElementRect、styleHint、subControlRect、sizeFromContents、hitTestComplexControl

这几个虚函数都分别微调一些控件子元素的外观矩形大小,这些没有太大的改动,也先直接跳过返回父类即可:

int MyStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    return QCommonStyle::pixelMetric(metric, option, widget);
}

QRect MyStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
{
    return QCommonStyle::subElementRect(element, option, widget);
}

int MyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
{
    return QCommonStyle::styleHint(hint, option, widget, returnData);
}

QRect MyStyle::subControlRect(ComplexControl element, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const
{
    return QCommonStyle::subControlRect(element, option, subControl, widget);
}

QSize MyStyle::sizeFromContents(ContentsType element, const QStyleOption *option, const QSize &size, const QWidget *widget) const
{
    return QCommonStyle::sizeFromContents(element, option, size, widget);
}

QStyle::SubControl MyStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &point, const QWidget *widget) const
{
    return QCommonStyle::hitTestComplexControl(control, option, point, widget);
}

drawPrimitive

绘制PE子元素,其实暂时也不知道怎么查资料可以得到各个控件的子元素有什么,笨拙的通过打印看按钮有什么子元素可太秀了,好的通过打印看出按钮有两个PE子元素:PE_PanelButtonCommand、PE_FrameFocusRect。子元素可在官方文档中查看具体代表是什么,比如第一个官方的描述是“Button used to initiate an action”,第二个其实不用看文档也偶尔猜到是绘制聚焦时的矩形样式;

分别列出来:

void MyStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    StylePrimitive fcn(nullptr);
    switch (element) {
    case PE_PanelButtonCommand:
        fcn = &MyStyle::drawPanelButtonCommandPrimitive;
        break;
    case PE_FrameFocusRect:
        fcn = &MyStyle::drawFrameFocusRectPrimitive;
        break;
    default:
        break;
    }

    painter->save();
    // call function if implemented
    if (!(fcn && (this->*fcn)(option, painter, widget))) {
        QCommonStyle::drawPrimitive(element, option, painter, widget);
    }
    painter->restore();
}

其中第一句这个算是泛型指针?写着方便,也是高级写法,所指的函数参数都一样,定义是这样的:

using StylePrimitive = bool(MyStyle::*)(const QStyleOption *option, QPainter *painter, const QWidget *widget) const;

具体绘画函数draw…先留空,这个是真的画画的时候了。

drawComplexControl、drawItemText

前面这个定制CC子元素,看了下button没有CC子元素,也没有特殊的itemtext需求,也是直接返回父类:

void MyStyle::drawComplexControl(ComplexControl element, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    QCommonStyle::drawComplexControl(element, option, painter, widget);
}

void MyStyle::drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &palette, bool enabled,const QString &text, QPalette::ColorRole textRole) const
{
    return QCommonStyle::drawItemText(painter, rect, flags, palette, enabled, text, textRole);
}

drawControl

定制CE子元素,button的CE有CE_PushButtonBevel、CE_PushButtonLabel。具体是什么就不再说了文档都有,也通过浅而易懂的命名知道意思了,格式一样:

void MyStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    StyleControl fcn(nullptr);
    switch (element) {
    case CE_PushButtonBevel:
        fcn = &MyStyle::drawPanelButtonCommandPrimitive;
        break;
    case CE_PushButtonLabel:
        fcn = &MyStyle::drawPushButtonLabelControl;
        break;
    default:
        break;
    }

    painter->save();

    // call function if implemented
    if (!(fcn && (this->*fcn)(option, painter, widget))) {
        QCommonStyle::drawControl(element, option, painter, widget);
    }

    painter->restore();
}

开始画画!

OK主要的虚函数都写好了,剩下画画的,仔细看每个虚函数给的参数,第一个是option包含着控件的属性,第二个画笔,第三个就是它自己,用这些参数足以开始画画了!

drawFrameFocusRectPrimitive

这个在adwaita源码中很明显的,它把聚焦矩形缩小一点,然后再用虚线画出这个矩形,效果是这样:

在这里插入图片描述

代码:

bool MyStyle::drawFrameFocusRectPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    const State &state(option->state);
    QRectF rect(QRectF(option->rect).adjusted(0, 0, -1, -1));
    const QPalette &palette(option->palette);

    if (rect.width() < 10)
        return true;

    QColor outlineColor(Helper::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.35));
    QPen pen(outlineColor, 1);
    pen.setStyle(Qt::CustomDashLine);
    pen.setDashPattern(QVector<qreal>() << 2 << 1);

    painter->setRenderHint(QPainter::Antialiasing, false);

    painter->setPen(pen);
    painter->drawRoundedRect(rect, 2, 2);

    return true;
}

也是显而易懂的,得到矩形后缩小,设置颜色,设置画笔,画矩形。
这个不太喜欢,直接去掉算了。

其中这个helper是用作渲染的类,主要作用是调色和封装一些画矩形的函数,其实这里可以随便上一种颜色即可,这个类就不详细说明了。

drawPanelButtonCommandPrimitive

这个是相当于初始化按钮绘制的函数了,代码:

bool MyStyle::drawPanelButtonCommandPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    // cast option and check
    const QStyleOptionButton *buttonOption(qstyleoption_cast< const QStyleOptionButton * >(option));
    if (!buttonOption)
        return true;

    // rect and palette
    const QRect &rect(option->rect);

    // button state
    const State &state(option->state);
    bool enabled(state & State_Enabled);
    bool windowActive(state & State_Active);
    bool mouseOver((state & State_Active) && enabled && (state & State_MouseOver));
    bool hasFocus((enabled && (state & State_HasFocus)) && !(widget && widget->focusProxy()));
    bool sunken(state & (State_On | State_Sunken));
    bool flat(buttonOption->features & QStyleOptionButton::Flat);

    if (flat) {
        // define colors and render
        const QPalette &palette(option->palette);
        QColor color(_helper->toolButtonColor(palette, mouseOver, hasFocus, sunken));
        _helper->renderToolButtonFrame(painter, rect, color, sunken);
    } else {
        // update button color from palette in case button is default
        QPalette palette(option->palette);
        if (enabled && buttonOption->features & QStyleOptionButton::DefaultButton) {
            QColor button(palette.color(QPalette::Button));
            QColor base(palette.color(QPalette::Base));
            palette.setColor(QPalette::Button, Helper::mix(button, base, 0.7));
        }

        QColor shadow(palette.color(QPalette::Shadow));
        QColor outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus));
        QColor background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, sunken));
        // render
        _helper->renderButtonFrame(painter, rect, background, outline, shadow, hasFocus, sunken, mouseOver, enabled && windowActive);
    }

    return true;
}

到这里发现绘制的流程基本也一致,显示获取rect要操作的矩形,获取各种状态参数,然后根据这些数据绘制即可,这是通过获取这个按钮的是否透明、点击、鼠标悬浮、使能失能等参数去画,这个_helper也只是封装了这个过程,也不过是判断状态state作出相应绘制而已。

drawPushButtonLabelControl

这里看了一下,基本也就判断下状态,其中有个判断是否有文字并且点击时字体矩形会稍微网右下角倾斜的效果,这个就实现了比较动态的感觉。

if (hasText && textRect.isValid()) {
        if (enabled && !sunken && !mouseOver && !flat) {
            drawItemText(painter, textRect.adjusted(0, 1, 0, 1), textFlags, palette, false, buttonOption->text, QPalette::Light);
        }
        drawItemText(painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole);
}

看看成果!

还记得demo吗,记得上面有一句QApplication::setStyle()吗?

现在把它弄成QApplication::setStyle(“mystyle”);运行看看:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值