添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
DStyle

DStyle 继承于 QCommonStyle,在基类(QStyle)的基础上添加了一些枚举值以及绘制、加工类的函数。Qt 所有内置控件均在 paintEvent 中使用 QStyle 中提供的各种 drawXXX 接口进行绘制,另外,QStyle 中定义了大量的枚举类型,如 QStyle::PrimitiveElement、QStyle::ControlElement、QStyle::SubControl 等,这些枚举类型用于控件的绘制、布局、标志位等抽象接口的定义中。QStyle 满足了 Qt 原生控件自定义风格的需求,同理,DStyle 需要在此基础上满足 DTK 控件自定义风格的需求。

DStyleOption

用于扩展 QStyleOption。如 DStyleOptionButton 需要对 QStyleOptionButton 就行扩展,它需要同时继承 DStyleOption 和 QStyleOptionButton。

DPalette

控件的行为虽然不同,但是它们的配色有很多共同的地方,在 Qt 的 GUI 模块中,QPalette 类负责管理所有通用型颜色。每一个 QWidget 对象都有对应的 QPalette,当没有使用 QWidget::setPalette 指定控件使用的调色板时,其将跟随 QApplicatioin::palette。

QPalette 中定义了两个枚举类型:

  • ColorGroup 颜色的分组,包含:Disabled、Active(Normal)、Inactive 三个值
  • ColorRole 颜色的类型,包含:Background、Base、Foreground 等一系列值
  • 我们可以把 ColorRole 定义的颜色理解为 c++ 中的基本数据类型(int double等),则控件的设计类似于 c++ 类的设计,一个是封装基本数据类型定义一个类,另一个则是通过对基础颜色的组合创建一个控件。

    QPalette 包含十几种常用的颜色,能满足 Qt 所有内置控件的绘制需要。但是 DTK 控件的设计在配色上更加的丰富,QPalette::ColorRole 中定义的基本颜色无法满足需求,因此在 dtkwidget 库中定义了 DPalette 类,并且添加了 DPalette::ColorType 的枚举类型,用于为 DTK 控件添加基本色的定义。

    QStyle 和 QPalette 的关系

    QApplication 会在初始化阶段(当使用 QApplication::setStyle 后也会执行以下步骤)调用 QStyle::standardPalette 获取一个标准的 QPalette 对象,这个对象在各个控件的 paintEvent 中被初始化给 QStyleOption (用于存储绘制控件所需要的所有数据),之后在 QStyle 绘制控件时则从 QStyleOption::palette 中获取定义的各种颜色值。对于 QApplication、QStyleOptin、QWidget 而言,它们只识别 QPalette,因此,DPalette 的初始化目前是放置在 QStyle::polish(QApplication*) 中,由 DPalette 自己管理 QApplication 和 QWidget 对象所对应的 DPalette 数据,在 style 插件的实现中则通过 DPalette::get 静态函数获取调色板对象。

    DTK 控件设计

    在 DDEV20 的设计中,有以下几个特点。首先先看一张图

    每个控件分为五个状态:

  • Normal
  • Hover
  • Pressed
  • Disabled
  • Focus
  • 于此相关的是,主窗口层面还分为 Active 和 Inactive 状态,也就是窗口是否被激活的状态。窗口的状态可以和控件状态相互叠加,因此,叠加后的控件状态共有十种组合。不过,在控件中其实不用过于关心窗口的状态,窗口 Active 时控件都是默认样式,Inactive 时则把所有颜色的不透明度降低 40%。同理 Disabled 状态则把所有颜色的不透明度降低 60%。因此,除去这两个特殊状态后,控件中还剩余 Normal Hover Pressed Focus 四个状态需要关心。

    Normal

    控件默认状态,使用 DPalette 的 Normal 组中各个 ColorRole/ColorType 的定义即可。

    Hover

    控件的 hover 状态可以由 normal 状态经过颜色变换(调色:如提供颜色亮度等),可使用 DStyle::generatedBrush 获取加工后的颜色值。DStyle 定义了 StyleState 用于指定需要加工的目标颜色类型,默认 Normal 可以不进行任何加工。

    Pressed

    和 Hover 状态一样,也是由 normal 状态经过颜色变换得到。

    代码流程描述

    字号使用规范

    DFontManager

    字号分为十个等级,T1-T10,默认为 T6 级别,当系统中字号大小改变时,所有级别基于默认级别进行同值增减。例如,T6 当前对应的字号为 16px,在控制中心将字号调整为 20px 后,T1-T10 的字号都将增加 4px。所有的控件设计中均不可直接指定字号大小,如果需要对特定的 QWidget 对象设置字号等级,可以使用 DFontSizeManager::bind 接口绑定到对应的级别。

    如何实现一个全新的控件

    首先为此控件添加需要的枚举值,如 DSuggestButton ,QStyle 中已经包含了 QStyle::CE_PushButton 的定义,这部分不用再进行扩展,查看 QStyleOptionButton,它在 ButtonFeatures 中定义了按钮的一些特性,因此我们需要继承 QStyleOptionButton 进行扩展。

    class DStyleOptionButton : public QStyleOptionButton, public DStyleOption
    public:
        enum ButtonFeature {
            SuggestButton = (CommandLinkButton << 1),
            WarningButton = (SuggestButton << 1)
        void init(QWidget *widget) override;
    

    这是 DStyleOptionButton 的代码实现,添加了两个枚举值 SuggestButton、WarningButton。在 DSuggestButton 的 paintEvent 中将使用这些新加的值绘制自定义的按钮。

    void DSuggestButton::paintEvent(QPaintEvent *event)
        Q_UNUSED(event)
        QStylePainter p(this);
        DStyleOptionButton option;
        option.features |= DStyleOptionButton::ButtonFeatures(DStyleOptionButton::SuggestButton);
        initStyleOption(&option);
        option.init(this);
        p.drawControl(QStyle::CE_PushButton, option);
    

    最终,对 QStylePainter::drawControl 的调用将变为对 QStyle::drawControl 的调用。

    XXX::drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w = nullptr)
        switch(element) {
        case CE_PushButton:
            ...
            QStyleOptionButton *opt_button = static_case<QStyleOptionButton*>(opt);
            if (opt_button->features.testFlag(DStyleOptionButton::SuggestButton)) {
                // draw suggest button
            ...
            break;
    

    这样即完成了对 DSuggestButton 的绘制。

    如何自绘控件

    有些控件在 Qt 以及 DTK 库中均不存在,在应用程序的开发中需要自己绘制实现,如控制中心个性化模块中的颜色选择控件:

    paintEvent 代码:

    void paintEvent(QPaintEvent *event)
        QPainter pa(this);
        QStyleOption opt;
        opt.initFrom(this);
        int borderWidth = style()->pixelMetric(DStyle::PM_FocusBorderWidth, &opt, this);
        int borderSpacing = style()->pixelMetric(DStyle::PM_FocusBorderSpacing, &opt, this);
        const QMargins margins(borderWidth + borderSpacing, borderWidth + borderSpacing, borderWidth + borderSpacing, borderWidth + borderSpacing);    
        pa.fillRect(rect().marginRemoved(margins), color); // 填充颜色背景
        pa.setPen(QPen(borderWidth, opt.palette.highlight())); // 设置边框的宽度和颜色
        pa.drawEllipse(rect()); // 绘制选中的边框
    

    从例子中可以看出,所有和颜色相关的数据均从 QPalette 中读取,所有和大小相关的数据均从 style 对应的接口中读取。

    如何自定义控件的一些参数

    如更改文本颜色:

    QLabel label("test");
    QPalette pa = label.palette();
    pa.setColor(QPalette::Text, Qt::red);
    label.setPalette(pa);

    如何添加图标

    一个完整的应用程序主题需要关注的不仅仅是控件的样式,有时,程序中对图标的使用也需要区分深色还是浅色。在 Qt 库中,查找和使用图标都可以通过 QIcon 完成,为了方便图标自动跟随程序主题,DDE 桌面环境在 Qt platform theme 主题插件中添加了一个内置的图标主题,路径为:"qrc:/icons/deepin/builtin/[light/dark]",其中,lightdark子目录为可选,它们分别为应用程序提供亮色和暗色图标的存储,如果图标本身为通用型(在任何主题下都可使用),则图标文件直接放置到"qrc:/icons/deepin/builtin"目录即可。

    图标分为三种类型:

  • TextType 纯文本性图标,其颜色会跟随画笔的前景色变化(和文字颜色保持一致)。文件放置路径:"qrc:/icons/deepin/builtin/[light/dark]/texts"
  • ActionType 动作型图标,其颜色会在其 Mode 改变时跟随画笔前景色(Normal模式图标颜色不会发生变化)。文件放置路径:"qrc:/icons/deepin/builtin/[light/dark]/actions"
  • IconType 图标型图标,其颜色在任何模式下都不会变化。文件放置路径:"qrc:/icons/deepin/builtin/[light/dark]/icons"
  • 图标名称规范:

    名称前面需要添加能标示当前程序的前缀,例如控制中心的图标文件 dcc_xxx_32px.svg(设计大小为32)每一个都会有 “dcc_” 的前缀,其后跟图标s名称(图标名称单词间使用 “_” 符号链接,且全部使用小写字母),再接着,”_32px” 为图标大小标识,标识此图标默认大小,最后的 “.svg” 为图标文件后缀名。

    qrc 表示是一个 Qt 资源文件,此文件需要应用程序中自行创建。”/icons/deepin/builtin” 为路径的固定前缀,随后的目录则为三种类型主题对应的目录。”actions” 为图标的类型目录,目前支持 “texts”、”actions” 和 “icons” 三种类型,”texts” 和 “actions” 目录用于放置一些工具性图标(一般都比较小,且颜色单一),”icons” 则用于放置一些颜色丰富的图标。

    添加图标文件后,在程序中只需要使用 QIcon::fromTheme(“dcc_xxx”) 即可获取当前主题对应的图标对象,”dcc_xxx” 为图标文件名称,不包含图标大小标识和文件后缀名!

    此规范仅用于约定应用程序中图标的存储和使用,其它图片资源不可使用此规范!

    icon_demo.zip #示例程序


    下载地址:

    QtExamples

    欢迎 starfork 这个系列的 QT / DTK 学习,附学习由浅入深的目录。

    若文章有所感所获,亦可请我共饮一杯肥宅冰阔落;
    支付宝
    QQ 支付
    微信支付
    • 本文作者:偕臧
    • 本文链接:https://ifmet.cn/posts/525116e/
    • 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。