Qt样式系统详解(上)

目录

  1. Qt样式系统基础
  2. QSS(Qt样式表)详解
  3. QStyle样式引擎
  4. QPalette调色板系统
  5. QStyleOption样式配置
  6. 自定义样式的实现
  7. 样式系统的高级应用
  8. 主题系统与皮肤切换
  9. 样式性能优化
  10. 实际应用场景与最佳实践

1. Qt样式系统基础

1.1 什么是Qt样式系统

样式系统的基本概念

什么是样式系统?

样式系统是Qt框架中负责控制应用程序视觉外观的核心机制。它决定了控件如何被绘制、如何显示颜色、字体、边框、背景等视觉元素。简单来说,样式系统就是Qt应用程序的"化妆师",它让界面变得美观、统一、符合设计规范。

样式系统的核心作用

  1. 视觉呈现:控制控件的颜色、字体、边框、背景等视觉属性
  2. 平台适配:在不同操作系统上提供原生或统一的视觉体验
  3. 主题切换:支持亮色/暗色主题、自定义主题等
  4. 品牌定制:让应用程序具有独特的视觉风格

样式系统的工作流程

复制代码
用户界面需求 → 样式系统 → 绘制引擎 → 屏幕显示

当Qt需要绘制一个控件时(比如按钮),样式系统会:

  1. 收集控件的状态信息(是否按下、是否悬停、是否禁用等)
  2. 查找适用的样式规则(QSS样式表、QStyle样式引擎、QPalette调色板)
  3. 计算最终的视觉属性(颜色、尺寸、位置等)
  4. 调用绘制函数将控件绘制到屏幕上
Qt样式系统的组成部分

Qt样式系统由三个核心组件组成,它们协同工作,共同完成界面的绘制:

1. QSS(Qt Style Sheets)- 样式表

QSS是Qt的样式表系统,类似于Web开发中的CSS。它允许开发者通过文本方式定义控件的样式,具有声明式、易维护、易修改的特点。

特点

  • 基于CSS语法,学习成本低
  • 支持选择器、伪状态、子控件等高级特性
  • 可以动态修改,支持运行时切换主题
  • 样式与代码分离,便于维护

示例

cpp 复制代码
// 通过QSS设置按钮样式
QPushButton *button = new QPushButton("点击我");
button->setStyleSheet(
    "QPushButton {"
    "    background-color: #4CAF50;"
    "    color: white;"
    "    border: none;"
    "    padding: 10px;"
    "    border-radius: 5px;"
    "}"
    "QPushButton:hover {"
    "    background-color: #45a049;"
    "}"
);

2. QStyle - 样式引擎

QStyle是Qt的样式引擎,负责实际绘制控件。它是一个抽象基类,定义了绘制控件的接口。Qt为不同平台提供了不同的QStyle实现(如Windows样式、macOS样式、Fusion样式等)。

特点

  • 提供统一的绘制接口
  • 支持平台原生样式
  • 可以完全自定义绘制逻辑
  • 控制控件的尺寸、布局、绘制细节

QStyle的核心方法

cpp 复制代码
class QStyle {
public:
    // 绘制基本元素(如按钮、复选框等)
    virtual void drawPrimitive(PrimitiveElement pe, 
                               const QStyleOption *opt,
                               QPainter *p, 
                               const QWidget *w = nullptr) const = 0;
    
    // 绘制控件元素
    virtual void drawControl(ControlElement element,
                             const QStyleOption *opt,
                             QPainter *p,
                             const QWidget *w = nullptr) const = 0;
    
    // 绘制复杂控件(如组合框、滚动条等)
    virtual void drawComplexControl(ComplexControl cc,
                                    const QStyleOptionComplex *opt,
                                    QPainter *p,
                                    const QWidget *w = nullptr) const = 0;
    
    // 计算控件尺寸
    virtual QSize sizeFromContents(ContentsType ct,
                                    const QStyleOption *opt,
                                    const QSize &contentsSize,
                                    const QWidget *w = nullptr) const = 0;
};

3. QPalette - 调色板

QPalette是Qt的调色板系统,定义了应用程序使用的颜色方案。它通过颜色角色(Color Roles)和颜色组(Color Groups)来组织颜色,确保界面颜色的一致性和可访问性。

特点

  • 定义统一的颜色方案
  • 支持不同状态的颜色(活动、非活动、禁用)
  • 与QSS和QStyle协同工作
  • 支持主题切换

示例

cpp 复制代码
// 设置调色板
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);        // 窗口背景色
palette.setColor(QPalette::WindowText, Qt::black);   // 窗口文本色
palette.setColor(QPalette::Button, Qt::lightGray);   // 按钮背景色
palette.setColor(QPalette::ButtonText, Qt::black);   // 按钮文本色
palette.setColor(QPalette::Highlight, Qt::blue);     // 高亮色
palette.setColor(QPalette::HighlightedText, Qt::white); // 高亮文本色

qApp->setPalette(palette);

三者的关系

复制代码
QSS样式表(声明式,易用)
    ↓
QStyle样式引擎(执行绘制)
    ↓
QPalette调色板(提供颜色)
    ↓
最终视觉效果
样式系统与其他UI框架的对比

与Web CSS的对比

特性 Qt QSS Web CSS
语法 类似CSS,但有一些差异 标准CSS
选择器 支持类型、类、ID、伪状态等 支持更多选择器类型
盒模型 支持margin、border、padding 标准盒模型
动画 支持简单的过渡效果 支持完整的动画系统
布局 不直接控制布局(由布局管理器控制) 可以控制布局(Flexbox、Grid)

与WPF样式的对比

特性 Qt样式系统 WPF样式系统
样式定义 QSS文本或QStyle代码 XAML或代码
数据绑定 不支持 支持强大的数据绑定
模板 不支持控件模板 支持控件模板
动画 有限支持 完整的动画系统
主题 通过QSS和QPalette 通过ResourceDictionary

与Android样式的对比

特性 Qt样式系统 Android样式系统
样式定义 QSS文本 XML资源文件
主题 运行时切换 编译时或运行时切换
适配 手动适配不同屏幕 自动适配(dp、sp等)
Material Design 需要手动实现 原生支持

Qt样式系统的优势

  1. 跨平台统一:一套代码可以在多个平台运行,样式可以统一或适配平台
  2. 易于使用:QSS语法简单,类似CSS,学习成本低
  3. 灵活强大:支持声明式(QSS)和命令式(QStyle)两种方式
  4. 性能优秀:样式系统经过优化,性能表现良好
  5. 可扩展性强:可以完全自定义样式引擎
为什么需要样式系统

1. 视觉一致性

样式系统确保应用程序的所有控件具有一致的视觉风格。通过统一的样式定义,可以避免每个控件单独设置样式,减少代码重复,提高维护性。

示例

cpp 复制代码
// ❌ 没有样式系统:每个控件都要单独设置
QPushButton *btn1 = new QPushButton("按钮1");
btn1->setStyleSheet("background-color: blue; color: white;");

QPushButton *btn2 = new QPushButton("按钮2");
btn2->setStyleSheet("background-color: blue; color: white;");

QPushButton *btn3 = new QPushButton("按钮3");
btn3->setStyleSheet("background-color: blue; color: white;");

// ✅ 有样式系统:统一设置
qApp->setStyleSheet("QPushButton { background-color: blue; color: white; }");
QPushButton *btn1 = new QPushButton("按钮1");
QPushButton *btn2 = new QPushButton("按钮2");
QPushButton *btn3 = new QPushButton("按钮3");

2. 主题切换支持

现代应用程序通常需要支持亮色/暗色主题切换。样式系统通过QSS和QPalette可以轻松实现主题切换,无需修改代码逻辑。

示例

cpp 复制代码
void MainWindow::switchTheme(bool dark) {
    if (dark) {
        // 暗色主题
        qApp->setStyleSheet(
            "QWidget { background-color: #2b2b2b; color: #dddddd; }"
            "QPushButton { background-color: #3c3f41; }"
        );
    } else {
        // 亮色主题
        qApp->setStyleSheet(
            "QWidget { background-color: #ffffff; color: #000000; }"
            "QPushButton { background-color: #e0e0e0; }"
        );
    }
}

3. 平台原生体验

Qt样式系统支持平台原生样式,让应用程序在不同平台上看起来像原生应用,提供更好的用户体验。

示例

cpp 复制代码
// Windows平台使用Windows样式
qApp->setStyle("windows");

// macOS平台使用macOS样式
qApp->setStyle("macos");

// 跨平台统一样式
qApp->setStyle("fusion");

4. 品牌定制

企业应用程序通常需要符合品牌视觉规范。样式系统可以轻松实现品牌定制,包括颜色、字体、图标等。

5. 可维护性

样式系统将样式定义与代码逻辑分离,使得样式修改不需要重新编译代码,提高了开发效率和可维护性。


1.2 Qt样式系统的层次结构

样式层级关系

Qt样式系统采用分层架构,样式规则按照优先级从高到低依次应用。理解这个层级关系对于正确使用样式系统至关重要。

样式层级(从高到低)

复制代码
1. 控件自身样式(最高优先级)
   ↓
2. 父控件样式
   ↓
3. 应用级样式(QApplication::setStyleSheet)
   ↓
4. QStyle样式引擎
   ↓
5. QPalette调色板
   ↓
6. 系统默认样式(最低优先级)

实际示例

cpp 复制代码
// 1. 应用级样式(优先级3)
qApp->setStyleSheet("QPushButton { background-color: red; }");

// 2. 父控件样式(优先级2)
QWidget *parent = new QWidget();
parent->setStyleSheet("QPushButton { background-color: blue; }");

// 3. 控件自身样式(优先级1,最高)
QPushButton *button = new QPushButton("按钮", parent);
button->setStyleSheet("background-color: green;");

// 结果:按钮是绿色的(控件自身样式优先级最高)

源码分析

在Qt源码中,样式查找的顺序在QWidget::styleSheet()QApplication::styleSheet()中实现。当控件需要获取样式时,Qt会:

  1. 首先检查控件自身是否有styleSheet属性
  2. 如果没有,向上查找父控件的styleSheet
  3. 如果父控件也没有,查找QApplicationstyleSheet
  4. 如果都没有,使用QStyleQPalette
样式继承机制

Qt样式系统支持样式继承,子控件可以继承父控件的样式规则。这个机制类似于CSS的继承,但有一些Qt特有的规则。

继承规则

  1. 样式表继承:子控件会继承父控件的样式表规则,除非子控件有更具体的规则覆盖
  2. 字体继承:子控件自动继承父控件的字体设置
  3. 调色板继承:子控件自动继承父控件的调色板设置
  4. 样式引擎继承:子控件使用与父控件相同的QStyle实例

样式表继承示例

cpp 复制代码
// 父控件设置样式
QWidget *parent = new QWidget();
parent->setStyleSheet(
    "QWidget {"
    "    background-color: #f0f0f0;"
    "    color: #333333;"
    "    font-size: 12px;"
    "}"
    "QPushButton {"
    "    background-color: #4CAF50;"
    "    color: white;"
    "}"
);

// 子控件自动继承
QPushButton *button = new QPushButton("按钮", parent);
// button会继承:
// - background-color: #4CAF50(来自QPushButton规则)
// - color: white(来自QPushButton规则)
// - font-size: 12px(继承自QWidget规则)

QLabel *label = new QLabel("标签", parent);
// label会继承:
// - background-color: #f0f0f0(来自QWidget规则)
// - color: #333333(来自QWidget规则)
// - font-size: 12px(来自QWidget规则)

字体继承示例

cpp 复制代码
// 应用级字体
qApp->setFont(QFont("Microsoft YaHei", 10));

// 父控件字体
QWidget *parent = new QWidget();
parent->setFont(QFont("SimHei", 12));

// 子控件继承父控件字体
QLabel *label = new QLabel("文本", parent);
// label的字体是 SimHei 12(继承自parent)

// 子控件可以覆盖继承的字体
QLabel *label2 = new QLabel("文本2", parent);
label2->setFont(QFont("Courier New", 9));
// label2的字体是 Courier New 9(覆盖了继承的字体)

调色板继承示例

cpp 复制代码
// 父控件设置调色板
QWidget *parent = new QWidget();
QPalette pal = parent->palette();
pal.setColor(QPalette::WindowText, Qt::red);
parent->setPalette(pal);

// 子控件继承调色板
QLabel *label = new QLabel("红色文本", parent);
// label的文本颜色是红色(继承自parent的调色板)
样式优先级规则

Qt样式系统使用特定的优先级规则来决定哪个样式规则生效。理解这些规则对于正确使用样式系统非常重要。

优先级规则(从高到低)

  1. 内联样式 (控件自身的setStyleSheet
  2. ID选择器#objectName
  3. 类选择器 + 伪状态QPushButton:hover
  4. 类选择器QPushButton
  5. 类型选择器 + 伪状态QWidget:hover
  6. 类型选择器QWidget
  7. 通用选择器*

选择器特异性

Qt使用类似CSS的特异性(Specificity)规则:

  • ID选择器:特异性最高
  • 类选择器:中等特异性
  • 类型选择器:较低特异性
  • 通用选择器:最低特异性

示例

cpp 复制代码
qApp->setStyleSheet(
    // 规则1:通用选择器(优先级最低)
    "* { color: black; }"
    
    // 规则2:类型选择器(优先级中等)
    "QPushButton { color: blue; }"
    
    // 规则3:类选择器(优先级较高)
    ".myButton { color: green; }"
    
    // 规则4:ID选择器(优先级最高)
    "#okButton { color: red; }"
);

QPushButton *btn1 = new QPushButton("按钮1");
// btn1的颜色是blue(匹配规则2)

QPushButton *btn2 = new QPushButton("按钮2");
btn2->setProperty("class", "myButton");
// btn2的颜色是green(匹配规则3,优先级高于规则2)

QPushButton *btn3 = new QPushButton("按钮3");
btn3->setObjectName("okButton");
// btn3的颜色是red(匹配规则4,优先级最高)

伪状态的影响

伪状态会增加选择器的特异性:

cpp 复制代码
qApp->setStyleSheet(
    "QPushButton { background-color: gray; }"           // 普通状态
    "QPushButton:hover { background-color: lightgray; }" // 悬停状态(优先级更高)
    "QPushButton:pressed { background-color: darkgray; }" // 按下状态(优先级更高)
);

样式覆盖规则

当多个样式规则同时匹配时,后定义的规则会覆盖先定义的规则(如果优先级相同):

cpp 复制代码
qApp->setStyleSheet(
    "QPushButton { background-color: red; }"   // 先定义
    "QPushButton { background-color: blue; }"   // 后定义,覆盖前面的
);
// 最终QPushButton的背景色是blue
样式作用域

样式作用域定义了样式规则的有效范围。Qt支持全局作用域和局部作用域。

全局作用域

通过QApplication::setStyleSheet()设置的样式具有全局作用域,影响应用程序中的所有控件。

cpp 复制代码
// 全局样式
qApp->setStyleSheet(
    "QPushButton { background-color: blue; }"
    "QLabel { color: black; }"
);

// 所有QPushButton和QLabel都会应用这些样式
QPushButton *btn1 = new QPushButton("按钮1");
QPushButton *btn2 = new QPushButton("按钮2");
QLabel *label = new QLabel("标签");

局部作用域

通过QWidget::setStyleSheet()设置的样式具有局部作用域,只影响该控件及其子控件。

cpp 复制代码
// 全局样式
qApp->setStyleSheet("QPushButton { background-color: blue; }");

// 局部样式(只影响sidebar及其子控件)
QWidget *sidebar = new QWidget();
sidebar->setStyleSheet("QPushButton { background-color: green; }");

QPushButton *btn1 = new QPushButton("按钮1");  // 蓝色(全局样式)
QPushButton *btn2 = new QPushButton("按钮2", sidebar);  // 绿色(局部样式)

样式作用域的查找顺序

当控件需要获取样式时,Qt按以下顺序查找:

  1. 控件自身的styleSheet
  2. 父控件的styleSheet(向上查找)
  3. QApplicationstyleSheet

实际应用

cpp 复制代码
// 全局主题
qApp->setStyleSheet(
    "QWidget { background-color: #ffffff; }"
    "QPushButton { background-color: #4CAF50; color: white; }"
);

// 侧边栏局部主题
QWidget *sidebar = new QWidget();
sidebar->setStyleSheet(
    "QWidget { background-color: #2b2b2b; }"  // 覆盖全局的QWidget样式
    "QPushButton { background-color: #3c3f41; }" // 覆盖全局的QPushButton样式
);

// 主内容区使用全局主题
QWidget *mainContent = new QWidget();
// mainContent使用全局样式(白色背景)

// 侧边栏使用局部主题
QPushButton *sidebarBtn = new QPushButton("侧边栏按钮", sidebar);
// sidebarBtn使用局部样式(深色背景)

1.3 Qt样式系统的三大支柱

QSS(Qt Style Sheets)- 样式表

QSS是什么?

QSS(Qt Style Sheets)是Qt的样式表系统,它允许开发者使用类似CSS的语法来定义控件的视觉样式。QSS是Qt样式系统中最易用、最灵活的部分。

QSS的核心特点

  1. 声明式语法:类似CSS,易于学习和使用
  2. 选择器支持:支持类型、类、ID、属性、伪状态等选择器
  3. 动态修改:可以在运行时修改样式,支持主题切换
  4. 样式分离:样式与代码逻辑分离,便于维护

QSS的基本语法

cpp 复制代码
// 基本语法:选择器 { 属性: 值; }
QPushButton {
    background-color: #4CAF50;
    color: white;
    border: none;
    padding: 10px;
    border-radius: 5px;
}

QSS的应用方式

cpp 复制代码
// 方式1:通过代码设置
QPushButton *button = new QPushButton("按钮");
button->setStyleSheet("background-color: blue; color: white;");

// 方式2:从文件加载
QFile file("style.qss");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
qApp->setStyleSheet(styleSheet);

// 方式3:从资源文件加载
QFile file(":/styles/style.qss");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
qApp->setStyleSheet(styleSheet);

QSS的优势

  • 易用性:语法简单,类似CSS,学习成本低
  • 灵活性:支持复杂的选择器和伪状态
  • 可维护性:样式与代码分离,便于修改和维护
  • 动态性:支持运行时修改,实现主题切换

QSS的局限性

  • 性能:解析和应用QSS需要一定的性能开销
  • 功能限制:不支持CSS的所有特性(如动画、变换等)
  • 布局控制:不能直接控制布局(由布局管理器控制)
QStyle - 样式引擎

QStyle是什么?

QStyle是Qt的样式引擎,它是一个抽象基类,定义了绘制控件的接口。QStyle负责实际绘制控件的外观,包括颜色、形状、尺寸等。

QStyle的核心职责

  1. 绘制控件:绘制按钮、复选框、滚动条等控件
  2. 计算尺寸:计算控件的最佳尺寸
  3. 提供度量:提供样式相关的度量值(如边框宽度、间距等)
  4. 平台适配:在不同平台上提供原生或统一的视觉体验

QStyle的继承体系

cpp 复制代码
QStyle (抽象基类)
├── QCommonStyle (通用样式基类)
│   ├── QWindowsStyle (Windows样式)
│   ├── QMacStyle (macOS样式)
│   ├── QFusionStyle (Fusion样式,跨平台)
│   └── QProxyStyle (代理样式,用于扩展)
└── 自定义样式

QStyle的核心方法

cpp 复制代码
class QStyle {
public:
    // 绘制基本元素(如按钮、复选框等)
    virtual void drawPrimitive(PrimitiveElement pe,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w = nullptr) const = 0;
    
    // 绘制控件元素
    virtual void drawControl(ControlElement element,
                             const QStyleOption *opt,
                             QPainter *p,
                             const QWidget *w = nullptr) const = 0;
    
    // 绘制复杂控件(如组合框、滚动条等)
    virtual void drawComplexControl(ComplexControl cc,
                                    const QStyleOptionComplex *opt,
                                    QPainter *p,
                                    const QWidget *w = nullptr) const = 0;
    
    // 计算控件尺寸
    virtual QSize sizeFromContents(ContentsType ct,
                                    const QStyleOption *opt,
                                    const QSize &contentsSize,
                                    const QWidget *w = nullptr) const = 0;
    
    // 获取像素度量(如边框宽度、间距等)
    virtual int pixelMetric(PixelMetric metric,
                             const QStyleOption *option = nullptr,
                             const QWidget *widget = nullptr) const = 0;
    
    // 获取样式提示
    virtual int styleHint(StyleHint hint,
                          const QStyleOption *option = nullptr,
                          const QWidget *widget = nullptr,
                          QStyleHintReturn *returnData = nullptr) const = 0;
};

QStyle的使用

cpp 复制代码
// 设置应用程序的样式
qApp->setStyle("fusion");  // 使用Fusion样式

// 或者创建样式实例
QStyle *style = new QFusionStyle();
qApp->setStyle(style);

// 获取控件的样式
QStyle *widgetStyle = widget->style();

QStyle的优势

  • 完全控制:可以完全控制控件的绘制逻辑
  • 平台原生:支持平台原生样式,提供原生体验
  • 性能优秀:直接绘制,性能优于QSS
  • 可扩展性:可以继承QStyle创建自定义样式

QStyle的局限性

  • 复杂度高:需要理解Qt的绘制系统
  • 代码量大:实现完整样式需要大量代码
  • 维护困难:样式逻辑与代码耦合,不易维护
QPalette - 调色板

QPalette是什么?

QPalette是Qt的调色板系统,它定义了应用程序使用的颜色方案。QPalette通过颜色角色(Color Roles)和颜色组(Color Groups)来组织颜色,确保界面颜色的一致性和可访问性。

QPalette的核心概念

  1. 颜色角色(Color Roles):定义颜色的用途(如窗口背景、文本颜色、按钮颜色等)
  2. 颜色组(Color Groups):定义颜色的状态(如活动、非活动、禁用等)

颜色角色(Color Roles)

cpp 复制代码
enum ColorRole {
    WindowText,        // 窗口文本色
    Button,            // 按钮背景色
    Light,             // 浅色(用于3D效果)
    Dark,              // 深色(用于3D效果)
    Mid,               // 中间色(用于3D效果)
    Text,              // 文本色
    BrightText,        // 亮文本色
    ButtonText,        // 按钮文本色
    Base,              // 基础背景色(如输入框背景)
    Window,            // 窗口背景色
    Shadow,            // 阴影色
    Highlight,         // 高亮色
    HighlightedText,   // 高亮文本色
    Link,              // 链接色
    LinkVisited,       // 已访问链接色
    AlternateBase,     // 交替背景色(如表格行)
    ToolTipBase,       // 工具提示背景色
    ToolTipText,       // 工具提示文本色
    // ... 更多角色
};

颜色组(Color Groups)

cpp 复制代码
enum ColorGroup {
    Active,    // 活动状态(窗口有焦点)
    Inactive,  // 非活动状态(窗口无焦点)
    Disabled   // 禁用状态(控件被禁用)
};

QPalette的使用

cpp 复制代码
// 创建调色板
QPalette palette;

// 设置活动状态的颜色
palette.setColor(QPalette::Active, QPalette::Window, Qt::white);
palette.setColor(QPalette::Active, QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Active, QPalette::Button, Qt::lightGray);
palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::black);
palette.setColor(QPalette::Active, QPalette::Highlight, Qt::blue);
palette.setColor(QPalette::Active, QPalette::HighlightedText, Qt::white);

// 设置禁用状态的颜色
palette.setColor(QPalette::Disabled, QPalette::WindowText, Qt::gray);
palette.setColor(QPalette::Disabled, QPalette::ButtonText, Qt::gray);

// 应用调色板
qApp->setPalette(palette);

QPalette的优势

  • 一致性:确保应用程序使用统一的颜色方案
  • 可访问性:支持不同状态的颜色,提高可访问性
  • 主题支持:可以轻松切换亮色/暗色主题
  • 平台适配:可以适配不同平台的颜色方案

QPalette的局限性

  • 功能有限:只能定义颜色,不能定义其他样式属性
  • 需要配合:通常需要与QSS或QStyle配合使用
三者的关系与协同工作

三者的关系

QSS、QStyle和QPalette是Qt样式系统的三大支柱,它们协同工作,共同完成界面的绘制:

复制代码
QSS样式表(声明式,易用)
    ↓ 提供样式规则
QStyle样式引擎(执行绘制)
    ↓ 使用颜色
QPalette调色板(提供颜色)
    ↓
最终视觉效果

协同工作流程

  1. QSS提供样式规则:开发者通过QSS定义控件的样式规则(颜色、边框、背景等)
  2. QStyle执行绘制:QStyle根据样式规则和控件状态,调用绘制函数绘制控件
  3. QPalette提供颜色:QPalette提供统一的颜色方案,QSS和QStyle都可以使用

实际工作示例

cpp 复制代码
// 1. 设置QPalette(提供颜色方案)
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);
palette.setColor(QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Highlight, Qt::blue);
qApp->setPalette(palette);

// 2. 设置QStyle(选择样式引擎)
qApp->setStyle("fusion");

// 3. 设置QSS(定义样式规则)
qApp->setStyleSheet(
    "QPushButton {"
    "    background-color: palette(button);"  // 使用QPalette的颜色
    "    color: palette(button-text);"
    "    border: 1px solid palette(dark);"
    "    padding: 5px;"
    "}"
    "QPushButton:hover {"
    "    background-color: palette(highlight);"  // 使用QPalette的高亮色
    "}"
);

// 当绘制QPushButton时:
// 1. QSS提供样式规则(背景色、边框、内边距等)
// 2. QStyle根据规则和控件状态绘制控件
// 3. QPalette提供具体的颜色值

优先级关系

当三者同时设置时,优先级从高到低:

  1. QSS样式表(最高优先级)
  2. QStyle样式引擎
  3. QPalette调色板(最低优先级)

示例

cpp 复制代码
// 设置QPalette
QPalette palette;
palette.setColor(QPalette::Button, Qt::red);
qApp->setPalette(palette);

// 设置QSS(会覆盖QPalette的颜色)
qApp->setStyleSheet("QPushButton { background-color: blue; }");

// 结果:QPushButton的背景色是blue(QSS优先级更高)

最佳实践

  1. 使用QPalette定义颜色方案:确保颜色的一致性和可访问性
  2. 使用QSS定义样式细节:利用QSS的灵活性定义边框、圆角、阴影等
  3. 使用QStyle控制绘制逻辑:对于复杂控件,可以自定义QStyle
  4. 三者配合使用:充分利用三者的优势,实现最佳的视觉效果

总结

Qt样式系统的三大支柱各司其职,协同工作:

  • QSS:提供声明式的样式定义,易于使用和维护
  • QStyle:提供强大的绘制能力,支持平台原生和自定义样式
  • QPalette:提供统一的颜色方案,确保颜色的一致性和可访问性

理解三者的关系和协同工作机制,对于掌握Qt样式系统至关重要。


2. QSS(Qt样式表)详解

2.1 QSS基础语法

CSS与QSS的关系

QSS的起源

QSS(Qt Style Sheets)是Qt框架借鉴Web开发中的CSS(Cascading Style Sheets)语法而设计的样式表系统。Qt开发团队在设计QSS时,充分考虑了CSS的成熟语法和广泛使用,使得熟悉Web开发的开发者能够快速上手。

相似之处

  1. 语法结构:QSS和CSS都使用相同的语法结构

    css 复制代码
    /* CSS */
    selector {
        property: value;
    }
    
    /* QSS */
    QPushButton {
        background-color: blue;
    }
  2. 选择器:都支持类型选择器、类选择器、ID选择器等

  3. 属性命名 :大部分属性名称相同(如background-colorcolorborder等)

  4. 盒模型:都使用margin、border、padding的概念

  5. 继承机制:都支持样式继承

主要差异

特性 CSS QSS
目标对象 HTML元素 Qt控件(QWidget及其子类)
选择器 支持更多选择器类型 支持Qt特有的选择器(如伪状态)
布局控制 可以控制布局(Flexbox、Grid) 不能直接控制布局(由布局管理器控制)
动画 完整的动画系统 支持简单的过渡效果
变换 支持transform(旋转、缩放等) 不支持transform
伪元素 支持::before、::after 不支持,但支持子控件(Sub-Controls)
变量 支持CSS变量 不支持变量(但可以使用QPalette)

实际对比示例

css 复制代码
/* CSS - Web开发 */
.button {
    background-color: #4CAF50;
    color: white;
    padding: 10px;
    border-radius: 5px;
}

.button:hover {
    background-color: #45a049;
}
cpp 复制代码
// QSS - Qt开发
QPushButton {
    background-color: #4CAF50;
    color: white;
    padding: 10px;
    border-radius: 5px;
}

QPushButton:hover {
    background-color: #45a049;
}

为什么Qt选择类似CSS的语法?

  1. 降低学习成本:熟悉CSS的开发者可以快速上手
  2. 成熟的设计:CSS经过多年发展,语法设计成熟
  3. 易于维护:声明式语法,样式与代码分离
  4. 灵活性:支持复杂的选择器和样式规则
QSS基本语法规则

基本语法结构

QSS的基本语法遵循以下结构:

复制代码
选择器 {
    属性1: 值1;
    属性2: 值2;
    ...
}

语法规则

  1. 选择器:指定要应用样式的控件类型或标识
  2. 大括号:包含样式规则,必须成对出现
  3. 属性 :要设置的样式属性(如background-colorcolor等)
  4. 冒号:属性名和值之间用冒号分隔
  5. :属性的具体值
  6. 分号:每个属性声明以分号结尾

示例

cpp 复制代码
// 基本语法示例
QPushButton {
    background-color: blue;
    color: white;
    border: 2px solid black;
    padding: 10px;
    border-radius: 5px;
}

注释

QSS支持C++风格的注释:

cpp 复制代码
/* 这是单行注释 */
QPushButton {
    background-color: blue; /* 行内注释 */
    color: white;
}

/*
 * 这是多行注释
 * 可以写多行
 */

多个选择器

可以为多个选择器设置相同的样式:

cpp 复制代码
QPushButton, QLabel, QLineEdit {
    color: blue;
    font-size: 14px;
}

嵌套选择器

QSS支持嵌套选择器(后代选择器):

cpp 复制代码
QWidget {
    background-color: white;
}

QWidget QPushButton {
    background-color: blue;
}

语法注意事项

  1. 大小写敏感:QSS是大小写敏感的

    cpp 复制代码
    // ✅ 正确
    QPushButton { background-color: blue; }
    
    // ❌ 错误
    qpushbutton { background-color: blue; }
  2. 引号使用:字符串值通常不需要引号,但包含空格的值需要引号

    cpp 复制代码
    // ✅ 正确
    font-family: "Microsoft YaHei";
    font-family: Arial;
    
    // ❌ 错误(如果字体名包含空格)
    font-family: Microsoft YaHei;  // 会被解析为两个值
  3. 单位:数值通常需要单位(px、pt、em等)

    cpp 复制代码
    // ✅ 正确
    padding: 10px;
    font-size: 12pt;
    
    // ❌ 错误(缺少单位)
    padding: 10;  // 可能不会生效
选择器(Selectors)

什么是选择器?

选择器用于指定哪些控件应该应用样式规则。QSS支持多种选择器类型,每种选择器有不同的优先级和用途。

选择器类型概览

  1. 通用选择器*):匹配所有控件
  2. 类型选择器QPushButton):匹配特定类型的控件
  3. 类选择器.className):匹配具有特定类的控件
  4. ID选择器#objectName):匹配具有特定对象名的控件
  5. 属性选择器[property="value"]):匹配具有特定属性的控件
  6. 子选择器parent > child):匹配直接子控件
  7. 后代选择器ancestor descendant):匹配所有后代控件
  8. 伪状态选择器:hover:pressed等):匹配特定状态的控件

选择器优先级

选择器的优先级从高到低:

  1. ID选择器(#objectName
  2. 类选择器(.className
  3. 类型选择器(QPushButton
  4. 通用选择器(*

示例

cpp 复制代码
qApp->setStyleSheet(
    // 通用选择器(优先级最低)
    "* { color: black; }"
    
    // 类型选择器(优先级中等)
    "QPushButton { color: blue; }"
    
    // 类选择器(优先级较高)
    ".myButton { color: green; }"
    
    // ID选择器(优先级最高)
    "#okButton { color: red; }"
);
属性(Properties)

什么是属性?

属性定义了控件的视觉样式,如颜色、字体、边框、间距等。QSS支持大量属性,可以控制控件的各个方面。

属性分类

  1. 颜色属性colorbackground-colorborder-color
  2. 字体属性font-familyfont-sizefont-weight
  3. 边框属性borderborder-widthborder-styleborder-radius
  4. 间距属性marginpadding
  5. 尺寸属性widthheightmin-widthmax-width
  6. 背景属性backgroundbackground-imagebackground-repeat
  7. 文本属性text-aligntext-decoration

常用属性示例

cpp 复制代码
QPushButton {
    /* 颜色属性 */
    color: white;
    background-color: #4CAF50;
    border-color: #45a049;
    
    /* 字体属性 */
    font-family: "Microsoft YaHei";
    font-size: 14px;
    font-weight: bold;
    
    /* 边框属性 */
    border: 2px solid #45a049;
    border-radius: 5px;
    
    /* 间距属性 */
    padding: 10px 15px;
    margin: 5px;
    
    /* 尺寸属性 */
    min-width: 100px;
    min-height: 30px;
}

属性继承

某些属性会被子控件继承:

  • color:文本颜色
  • font-*:字体相关属性
  • text-align:文本对齐

属性不继承

某些属性不会被继承:

  • background-color:背景颜色
  • border:边框
  • padding:内边距
  • margin:外边距
值(Values)

值的类型

QSS支持多种类型的值:

  1. 颜色值

    • 命名颜色:redbluewhite
    • 十六进制:#FF0000#4CAF50
    • RGB:rgb(255, 0, 0)
    • RGBA:rgba(255, 0, 0, 0.5)
    • QPalette引用:palette(button)palette(button-text)
  2. 长度值

    • 像素:10px20px
    • 点:12pt14pt
    • 相对单位:1em2em
    • 百分比:50%100%
  3. 字符串值

    • 字体名:"Microsoft YaHei"Arial
    • URL:url(:/images/button.png)
  4. 关键字值

    • noneautoinherit
    • soliddasheddotted(边框样式)
    • leftcenterright(对齐方式)

颜色值示例

cpp 复制代码
QPushButton {
    /* 命名颜色 */
    background-color: red;
    
    /* 十六进制 */
    background-color: #FF0000;
    background-color: #F00;  /* 简写形式 */
    
    /* RGB */
    background-color: rgb(255, 0, 0);
    
    /* RGBA(带透明度) */
    background-color: rgba(255, 0, 0, 0.5);
    
    /* QPalette引用 */
    background-color: palette(button);
    color: palette(button-text);
}

长度值示例

cpp 复制代码
QPushButton {
    /* 像素 */
    padding: 10px;
    font-size: 14px;
    
    /* 点 */
    font-size: 12pt;
    
    /* 相对单位 */
    font-size: 1.2em;
    
    /* 百分比 */
    width: 50%;
    height: 100%;
}

字符串值示例

cpp 复制代码
QPushButton {
    /* 字体名(包含空格需要引号) */
    font-family: "Microsoft YaHei";
    font-family: Arial;  /* 不包含空格可以不用引号 */
    
    /* 图片URL */
    background-image: url(:/images/button.png);
    border-image: url(:/images/border.png);
}

关键字值示例

cpp 复制代码
QPushButton {
    /* 边框样式 */
    border: 1px solid black;
    border: 1px dashed black;
    border: 1px dotted black;
    border: none;  /* 无边框 */
    
    /* 文本对齐 */
    text-align: left;
    text-align: center;
    text-align: right;
    
    /* 自动尺寸 */
    width: auto;
    height: auto;
}

值的组合

某些属性可以接受多个值:

cpp 复制代码
QPushButton {
    /* 边框:宽度 样式 颜色 */
    border: 2px solid #4CAF50;
    
    /* 内边距:上 右 下 左 */
    padding: 10px 15px 10px 15px;
    
    /* 内边距:上下 左右 */
    padding: 10px 15px;
    
    /* 内边距:所有方向相同 */
    padding: 10px;
    
    /* 外边距:上 右 下 左 */
    margin: 5px 10px 5px 10px;
}

特殊值

  1. palette()函数:引用QPalette中的颜色

    cpp 复制代码
    color: palette(button-text);
    background-color: palette(button);
  2. url()函数:引用资源文件

    cpp 复制代码
    background-image: url(:/images/background.png);
  3. qlineargradient()函数:线性渐变

    cpp 复制代码
    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                stop:0 white, stop:1 gray);

2.2 QSS选择器详解

选择器是QSS的核心,它决定了哪些控件会应用样式规则。理解各种选择器的用法和优先级对于掌握QSS至关重要。

通用选择器(Universal Selector)

语法*

作用:匹配所有控件,优先级最低。

使用场景

  • 设置全局默认样式
  • 重置所有控件的某些属性

示例

cpp 复制代码
// 设置所有控件的默认字体
qApp->setStyleSheet("* { font-family: 'Microsoft YaHei'; font-size: 12px; }");

// 重置所有控件的内边距和外边距
qApp->setStyleSheet("* { margin: 0; padding: 0; }");

注意事项

  • 通用选择器优先级最低,容易被其他选择器覆盖
  • 使用通用选择器可能影响性能(需要检查所有控件)
  • 谨慎使用,避免过度影响
类型选择器(Type Selector)

语法控件类型名(如QPushButtonQLabel等)

作用:匹配指定类型的所有控件。

使用场景

  • 为特定类型的控件设置统一样式
  • 最常用的选择器类型

示例

cpp 复制代码
// 设置所有按钮的样式
qApp->setStyleSheet(
    "QPushButton {"
    "    background-color: #4CAF50;"
    "    color: white;"
    "    border: none;"
    "    padding: 10px;"
    "    border-radius: 5px;"
    "}"
);

// 设置所有标签的样式
qApp->setStyleSheet(
    "QLabel {"
    "    color: #333333;"
    "    font-size: 14px;"
    "}"
);

// 设置所有输入框的样式
qApp->setStyleSheet(
    "QLineEdit {"
    "    border: 1px solid #cccccc;"
    "    padding: 5px;"
    "    border-radius: 3px;"
    "}"
);

控件类型名称

QSS使用Qt控件的类名作为类型选择器:

  • QWidget:所有控件的基类
  • QPushButton:按钮
  • QLabel:标签
  • QLineEdit:单行输入框
  • QTextEdit:多行文本编辑器
  • QComboBox:组合框
  • QCheckBox:复选框
  • QRadioButton:单选按钮
  • QSlider:滑块
  • QProgressBar:进度条
  • QScrollBar:滚动条
  • QTabWidget:标签页控件
  • QMenu:菜单
  • QMenuBar:菜单栏
  • 等等...

注意事项

  • 类型选择器匹配所有该类型的控件,包括子类
  • 如果控件是QPushButton的子类,也会匹配QPushButton选择器
类选择器(Class Selector)

语法.类名

作用 :匹配具有特定类的控件。控件通过setProperty("class", "类名")设置类。

使用场景

  • 为特定功能的控件设置样式
  • 创建可重用的样式类

示例

cpp 复制代码
// 定义样式类
qApp->setStyleSheet(
    ".primary-button {"
    "    background-color: #4CAF50;"
    "    color: white;"
    "}"
    
    ".secondary-button {"
    "    background-color: #2196F3;"
    "    color: white;"
    "}"
    
    ".danger-button {"
    "    background-color: #f44336;"
    "    color: white;"
    "}"
);

// 应用样式类
QPushButton *okBtn = new QPushButton("确定");
okBtn->setProperty("class", "primary-button");  // 应用primary-button样式

QPushButton *cancelBtn = new QPushButton("取消");
cancelBtn->setProperty("class", "secondary-button");  // 应用secondary-button样式

QPushButton *deleteBtn = new QPushButton("删除");
deleteBtn->setProperty("class", "danger-button");  // 应用danger-button样式

多个类

一个控件可以有多个类:

cpp 复制代码
QPushButton *btn = new QPushButton("按钮");
btn->setProperty("class", "primary-button large-button");
// 按钮同时具有primary-button和large-button两个类

// 样式定义
qApp->setStyleSheet(
    ".primary-button { background-color: #4CAF50; }"
    ".large-button { padding: 15px; font-size: 16px; }"
);

注意事项

  • 类名不能包含空格(多个类用空格分隔)
  • 类选择器优先级高于类型选择器
  • 类名区分大小写
ID选择器(ID Selector)

语法#对象名

作用:匹配具有特定对象名(objectName)的控件。优先级最高。

使用场景

  • 为特定控件设置唯一样式
  • 覆盖其他选择器的样式

示例

cpp 复制代码
// 定义ID样式
qApp->setStyleSheet(
    "#okButton {"
    "    background-color: #4CAF50;"
    "    color: white;"
    "}"
    
    "#cancelButton {"
    "    background-color: #f44336;"
    "    color: white;"
    "}"
);

// 设置对象名
QPushButton *okBtn = new QPushButton("确定");
okBtn->setObjectName("okButton");  // 应用#okButton样式

QPushButton *cancelBtn = new QPushButton("取消");
cancelBtn->setObjectName("cancelButton");  // 应用#cancelButton样式

ID选择器的优先级

ID选择器优先级最高,可以覆盖其他选择器:

cpp 复制代码
qApp->setStyleSheet(
    "QPushButton { background-color: blue; }"  // 类型选择器
    "#okButton { background-color: green; }"    // ID选择器(优先级更高)
);

QPushButton *btn = new QPushButton("按钮");
btn->setObjectName("okButton");
// btn的背景色是green(ID选择器优先级更高)

注意事项

  • 对象名必须唯一(在同一父控件下)
  • ID选择器优先级最高,谨慎使用
  • 对象名区分大小写
属性选择器(Attribute Selector)

语法

  • [属性名]:匹配具有该属性的控件
  • [属性名="值"]:匹配属性值等于指定值的控件
  • [属性名~="值"]:匹配属性值包含指定值的控件(用空格分隔)

作用:根据控件的属性(property)来匹配控件。

使用场景

  • 根据自定义属性设置样式
  • 根据控件状态设置样式

示例

cpp 复制代码
// 匹配具有enabled属性的控件
qApp->setStyleSheet(
    "QPushButton[enabled=\"true\"] {"
    "    background-color: #4CAF50;"
    "}"
    
    "QPushButton[enabled=\"false\"] {"
    "    background-color: #cccccc;"
    "    color: #999999;"
    "}"
);

// 使用自定义属性
QPushButton *btn = new QPushButton("按钮");
btn->setProperty("buttonType", "primary");

qApp->setStyleSheet(
    "QPushButton[buttonType=\"primary\"] {"
    "    background-color: #4CAF50;"
    "}"
    
    "QPushButton[buttonType=\"secondary\"] {"
    "    background-color: #2196F3;"
    "}"
);

属性值匹配

cpp 复制代码
// 精确匹配
QPushButton[objectName="okButton"] { ... }

// 包含匹配(值用空格分隔)
QPushButton[class~="primary"] { ... }  // 匹配class包含"primary"的按钮

注意事项

  • 属性名区分大小写
  • 属性值需要用引号括起来
  • 属性选择器优先级高于类型选择器
子选择器(Child Selector)

语法父选择器 > 子选择器

作用:匹配直接子控件(只匹配直接子级,不匹配孙子级)。

使用场景

  • 为特定父控件的直接子控件设置样式
  • 精确控制样式作用范围

示例

cpp 复制代码
// 只匹配QWidget的直接子QPushButton
qApp->setStyleSheet(
    "QWidget > QPushButton {"
    "    background-color: blue;"
    "}"
);

// 结构示例
QWidget *parent = new QWidget();
QPushButton *btn1 = new QPushButton("按钮1", parent);  // ✅ 匹配(直接子)
QWidget *child = new QWidget(parent);
QPushButton *btn2 = new QPushButton("按钮2", child);   // ❌ 不匹配(不是直接子)

与后代选择器的区别

cpp 复制代码
// 子选择器:只匹配直接子控件
QWidget > QPushButton { ... }

// 后代选择器:匹配所有后代控件
QWidget QPushButton { ... }
后代选择器(Descendant Selector)

语法祖先选择器 后代选择器(用空格分隔)

作用:匹配所有后代控件(包括子级、孙子级等所有层级)。

使用场景

  • 为特定容器内的所有控件设置样式
  • 创建局部主题

示例

cpp 复制代码
// 匹配QWidget内的所有QPushButton(任何层级)
qApp->setStyleSheet(
    "QWidget QPushButton {"
    "    background-color: blue;"
    "}"
);

// 结构示例
QWidget *parent = new QWidget();
QPushButton *btn1 = new QPushButton("按钮1", parent);  // ✅ 匹配
QWidget *child = new QWidget(parent);
QPushButton *btn2 = new QPushButton("按钮2", child);   // ✅ 匹配(后代)

实际应用

cpp 复制代码
// 为侧边栏内的所有按钮设置样式
QWidget *sidebar = new QWidget();
sidebar->setObjectName("sidebar");

qApp->setStyleSheet(
    "#sidebar QPushButton {"
    "    background-color: #3c3f41;"
    "    color: white;"
    "    text-align: left;"
    "    padding: 10px;"
    "}"
);

多级后代选择器

cpp 复制代码
// 匹配QMainWindow内的QWidget内的QPushButton
QMainWindow QWidget QPushButton { ... }
伪类选择器(Pseudo-Class Selector)

语法选择器:伪类

注意:在QSS中,伪类选择器的概念与CSS不同。QSS主要使用伪状态选择器(Pseudo-State Selector),而不是伪类选择器。

QSS中的伪类

QSS实际上没有传统CSS意义上的伪类选择器(如:first-child:last-child等),而是使用伪状态选择器。

与CSS的区别

  • CSS伪类:hover:active:focus:first-child
  • QSS伪状态:hover:pressed:checked:disabled

在QSS中,我们通常说的"伪类"实际上是指"伪状态"。

伪状态选择器(Pseudo-State Selector)

语法选择器:伪状态

作用:根据控件的状态(如悬停、按下、选中等)来匹配控件。

常用伪状态

  1. :hover:鼠标悬停
  2. :pressed:按下状态
  3. :checked:选中状态(用于复选框、单选按钮等)
  4. :unchecked:未选中状态
  5. :enabled:启用状态
  6. :disabled:禁用状态
  7. :focus:获得焦点
  8. :flat:扁平样式
  9. :default:默认按钮
  10. :exclusive:独占按钮组

示例

cpp 复制代码
qApp->setStyleSheet(
    // 普通状态
    "QPushButton {"
    "    background-color: #4CAF50;"
    "    color: white;"
    "}"
    
    // 悬停状态
    "QPushButton:hover {"
    "    background-color: #45a049;"
    "}"
    
    // 按下状态
    "QPushButton:pressed {"
    "    background-color: #3d8b40;"
    "}"
    
    // 禁用状态
    "QPushButton:disabled {"
    "    background-color: #cccccc;"
    "    color: #999999;"
    "}"
    
    // 获得焦点
    "QPushButton:focus {"
    "    border: 2px solid #2196F3;"
    "}"
);

复选框和单选按钮的伪状态

cpp 复制代码
qApp->setStyleSheet(
    // 未选中
    "QCheckBox {"
    "    color: black;"
    "}"
    
    // 选中
    "QCheckBox:checked {"
    "    color: blue;"
    "}"
    
    // 禁用
    "QCheckBox:disabled {"
    "    color: gray;"
    "}"
);

伪状态的组合

可以组合多个伪状态:

cpp 复制代码
qApp->setStyleSheet(
    // 悬停且未禁用
    "QPushButton:hover:!disabled {"
    "    background-color: #45a049;"
    "}"
    
    // 选中且悬停
    "QCheckBox:checked:hover {"
    "    color: darkblue;"
    "}"
);

否定伪状态

使用!来否定伪状态:

cpp 复制代码
qApp->setStyleSheet(
    // 未禁用
    "QPushButton:!disabled {"
    "    background-color: #4CAF50;"
    "}"
    
    // 未选中
    "QCheckBox:!checked {"
    "    color: gray;"
    "}"
);

伪状态的优先级

伪状态会增加选择器的特异性,优先级高于普通选择器:

cpp 复制代码
qApp->setStyleSheet(
    "QPushButton { background-color: gray; }"           // 普通状态
    "QPushButton:hover { background-color: lightgray; }" // 悬停状态(优先级更高)
    "QPushButton:pressed { background-color: darkgray; }" // 按下状态(优先级更高)
);

注意事项

  • 伪状态区分大小写
  • 可以组合多个伪状态
  • 伪状态会增加选择器的优先级
  • 某些控件可能不支持某些伪状态

2.3 QSS常用属性

QSS提供了丰富的属性来控制控件的视觉样式。本节介绍最常用的属性及其用法。

颜色和背景属性

颜色属性

  1. color:文本颜色

    cpp 复制代码
    QPushButton { color: white; }
    QLabel { color: #333333; }
  2. background-color:背景颜色

    cpp 复制代码
    QPushButton { background-color: #4CAF50; }
    QWidget { background-color: white; }
  3. border-color:边框颜色

    cpp 复制代码
    QPushButton { border-color: #45a049; }

背景属性

  1. background:综合背景属性(可以设置颜色、图片等)

    cpp 复制代码
    QPushButton {
        background: #4CAF50;  // 背景颜色
    }
  2. background-image:背景图片

    cpp 复制代码
    QPushButton {
        background-image: url(:/images/button.png);
    }
  3. background-repeat:背景图片重复方式

    cpp 复制代码
    QPushButton {
        background-image: url(:/images/pattern.png);
        background-repeat: repeat;  // repeat, repeat-x, repeat-y, no-repeat
    }
  4. background-position:背景图片位置

    cpp 复制代码
    QPushButton {
        background-image: url(:/images/icon.png);
        background-position: left center;
    }

颜色值格式

cpp 复制代码
QPushButton {
    /* 命名颜色 */
    background-color: red;
    
    /* 十六进制 */
    background-color: #FF0000;
    background-color: #F00;  /* 简写 */
    
    /* RGB */
    background-color: rgb(255, 0, 0);
    
    /* RGBA(带透明度) */
    background-color: rgba(255, 0, 0, 0.5);
    
    /* QPalette引用 */
    background-color: palette(button);
    color: palette(button-text);
}
边框和圆角属性

边框属性

  1. border:综合边框属性

    cpp 复制代码
    QPushButton {
        border: 2px solid #4CAF50;  /* 宽度 样式 颜色 */
    }
  2. border-width:边框宽度

    cpp 复制代码
    QPushButton {
        border-width: 2px;
        /* 或分别设置 */
        border-top-width: 2px;
        border-right-width: 1px;
        border-bottom-width: 2px;
        border-left-width: 1px;
    }
  3. border-style:边框样式

    cpp 复制代码
    QPushButton {
        border-style: solid;    /* 实线 */
        border-style: dashed;   /* 虚线 */
        border-style: dotted;   /* 点线 */
        border-style: none;     /* 无边框 */
    }
  4. border-color:边框颜色

    cpp 复制代码
    QPushButton {
        border-color: #4CAF50;
        /* 或分别设置 */
        border-top-color: red;
        border-right-color: blue;
        border-bottom-color: green;
        border-left-color: yellow;
    }

圆角属性

  1. border-radius :圆角半径

    cpp 复制代码
    QPushButton {
        border-radius: 5px;  /* 所有角 */
        /* 或分别设置 */
        border-top-left-radius: 10px;
        border-top-right-radius: 10px;
        border-bottom-left-radius: 5px;
        border-bottom-right-radius: 5px;
    }

边框示例

cpp 复制代码
// 圆角按钮
QPushButton {
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
    padding: 10px;
}

// 带边框的输入框
QLineEdit {
    border: 1px solid #cccccc;
    border-radius: 3px;
    padding: 5px;
}

// 虚线边框
QWidget {
    border: 2px dashed #999999;
}
字体和文本属性

字体属性

  1. font-family:字体族

    cpp 复制代码
    QPushButton {
        font-family: "Microsoft YaHei";
        font-family: Arial, "Microsoft YaHei", sans-serif;  /* 多个字体,逗号分隔 */
    }
  2. font-size:字体大小

    cpp 复制代码
    QPushButton {
        font-size: 14px;
        font-size: 12pt;
        font-size: 1.2em;
    }
  3. font-weight:字体粗细

    cpp 复制代码
    QPushButton {
        font-weight: normal;  /* 正常 */
        font-weight: bold;     /* 粗体 */
        font-weight: 100;      /* 数值:100-900 */
    }
  4. font-style:字体样式

    cpp 复制代码
    QPushButton {
        font-style: normal;   /* 正常 */
        font-style: italic;    /* 斜体 */
        font-style: oblique;  /* 倾斜 */
    }
  5. font:综合字体属性

    cpp 复制代码
    QPushButton {
        font: bold 14px "Microsoft YaHei";  /* 粗细 大小 字体族 */
    }

文本属性

  1. text-align:文本对齐

    cpp 复制代码
    QPushButton {
        text-align: left;    /* 左对齐 */
        text-align: center;  /* 居中 */
        text-align: right;  /* 右对齐 */
    }
  2. text-decoration:文本装饰

    cpp 复制代码
    QLabel {
        text-decoration: none;        /* 无装饰 */
        text-decoration: underline;   /* 下划线 */
        text-decoration: line-through; /* 删除线 */
    }
  3. text-transform:文本转换

    cpp 复制代码
    QLabel {
        text-transform: none;      /* 不转换 */
        text-transform: uppercase; /* 大写 */
        text-transform: lowercase; /* 小写 */
        text-transform: capitalize; /* 首字母大写 */
    }

字体示例

cpp 复制代码
// 标题样式
QLabel {
    font-family: "Microsoft YaHei";
    font-size: 18px;
    font-weight: bold;
    color: #333333;
}

// 正文样式
QLabel {
    font-family: "Microsoft YaHei";
    font-size: 14px;
    font-weight: normal;
    color: #666666;
}
间距和边距属性

内边距(Padding)

内边距是控件内容与边框之间的距离。

cpp 复制代码
QPushButton {
    padding: 10px;              /* 所有方向相同 */
    padding: 10px 15px;           /* 上下 左右 */
    padding: 5px 10px 15px 20px; /* 上 右 下 左 */
    
    /* 或分别设置 */
    padding-top: 10px;
    padding-right: 15px;
    padding-bottom: 10px;
    padding-left: 15px;
}

外边距(Margin)

外边距是控件与外部元素之间的距离。

cpp 复制代码
QPushButton {
    margin: 5px;                  /* 所有方向相同 */
    margin: 5px 10px;             /* 上下 左右 */
    margin: 2px 5px 8px 10px;    /* 上 右 下 左 */
    
    /* 或分别设置 */
    margin-top: 5px;
    margin-right: 10px;
    margin-bottom: 5px;
    margin-left: 10px;
}

间距示例

cpp 复制代码
// 按钮间距
QPushButton {
    padding: 10px 20px;  /* 内边距:上下10px,左右20px */
    margin: 5px;         /* 外边距:所有方向5px */
}

// 输入框间距
QLineEdit {
    padding: 5px;        /* 内边距:所有方向5px */
    margin: 0;           /* 外边距:无 */
}
尺寸属性

宽度和高度

cpp 复制代码
QPushButton {
    width: 100px;   /* 固定宽度 */
    height: 30px;   /* 固定高度 */
}

最小和最大尺寸

cpp 复制代码
QPushButton {
    min-width: 100px;   /* 最小宽度 */
    min-height: 30px;   /* 最小高度 */
    max-width: 300px;  /* 最大宽度 */
    max-height: 100px;  /* 最大高度 */
}

尺寸单位

cpp 复制代码
QPushButton {
    width: 100px;      /* 像素 */
    width: 50%;        /* 百分比(相对于父控件) */
    width: auto;       /* 自动(根据内容) */
}

尺寸示例

cpp 复制代码
// 固定尺寸按钮
QPushButton {
    width: 120px;
    height: 40px;
}

// 最小尺寸按钮
QPushButton {
    min-width: 100px;
    min-height: 30px;
}

// 全宽按钮
QPushButton {
    width: 100%;
}
定位属性

注意 :QSS不能像CSS那样直接控制控件的定位(如positiontopleft等)。控件的定位由Qt的布局管理器(如QHBoxLayoutQVBoxLayout等)控制。

QSS可以影响的"定位"相关属性

  1. alignment:对齐方式(在某些控件中有效)

    cpp 复制代码
    QLabel {
        /* 注意:text-align用于文本对齐,不是控件对齐 */
    }
  2. subcontrol-position:子控件位置(用于子控件)

    cpp 复制代码
    QComboBox::drop-down {
        subcontrol-position: top right;
    }

实际定位控制

在Qt中,控件的定位应该通过布局管理器来实现:

cpp 复制代码
// ❌ QSS不能这样控制定位
QPushButton {
    position: absolute;
    top: 10px;
    left: 20px;
}

// ✅ 应该使用布局管理器
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(button);

总结

QSS主要用于控制控件的视觉样式(颜色、字体、边框等),而不是布局和定位。布局应该使用Qt的布局管理器来实现。


2.4 QSS盒模型

盒模型是QSS中最重要的概念之一,它定义了控件内容、内边距、边框和外边距之间的关系。

盒模型的组成

盒模型的四个部分(从内到外):

复制代码
┌─────────────────────────────────┐
│         Margin (外边距)          │
│  ┌───────────────────────────┐  │
│  │      Border (边框)         │  │
│  │  ┌─────────────────────┐  │  │
│  │  │  Padding (内边距)   │  │  │
│  │  │  ┌───────────────┐  │  │  │
│  │  │  │   Content    │  │  │  │
│  │  │  │   (内容)     │  │  │  │
│  │  │  └───────────────┘  │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘
  1. Content(内容):控件的实际内容(文本、图标等)
  2. Padding(内边距):内容与边框之间的距离
  3. Border(边框):围绕内边距和内容的边框
  4. Margin(外边距):控件与外部元素之间的距离

盒模型示例

cpp 复制代码
QPushButton {
    /* 内容区域 */
    width: 100px;
    height: 30px;
    
    /* 内边距 */
    padding: 10px;
    
    /* 边框 */
    border: 2px solid #4CAF50;
    
    /* 外边距 */
    margin: 5px;
}
margin、border、padding的使用

Margin(外边距)

外边距控制控件与外部元素的距离,不会影响控件本身的尺寸。

cpp 复制代码
QPushButton {
    margin: 10px;              /* 所有方向相同 */
    margin: 5px 10px;          /* 上下 左右 */
    margin: 2px 5px 8px 10px;  /* 上 右 下 左 */
    
    /* 或分别设置 */
    margin-top: 10px;
    margin-right: 10px;
    margin-bottom: 10px;
    margin-left: 10px;
}

Border(边框)

边框围绕内边距和内容,会影响控件的总尺寸。

cpp 复制代码
QPushButton {
    border: 2px solid #4CAF50;  /* 宽度 样式 颜色 */
    
    /* 或分别设置 */
    border-width: 2px;
    border-style: solid;
    border-color: #4CAF50;
    
    /* 或分别设置各边 */
    border-top: 2px solid red;
    border-right: 1px solid blue;
    border-bottom: 2px solid green;
    border-left: 1px solid yellow;
}

Padding(内边距)

内边距控制内容与边框的距离,会影响控件的可用内容区域。

cpp 复制代码
QPushButton {
    padding: 10px;             /* 所有方向相同 */
    padding: 5px 10px;          /* 上下 左右 */
    padding: 2px 5px 8px 10px;  /* 上 右 下 左 */
    
    /* 或分别设置 */
    padding-top: 10px;
    padding-right: 15px;
    padding-bottom: 10px;
    padding-left: 15px;
}

实际示例

cpp 复制代码
// 按钮盒模型
QPushButton {
    /* 内容区域 */
    min-width: 80px;
    min-height: 30px;
    
    /* 内边距:内容与边框的距离 */
    padding: 10px 20px;
    
    /* 边框 */
    border: 2px solid #4CAF50;
    border-radius: 5px;
    
    /* 外边距:按钮与其他元素的距离 */
    margin: 5px;
}
盒模型计算规则

总尺寸计算

控件的总尺寸 = 内容尺寸 + 内边距 + 边框 + 外边距

复制代码
总宽度 = width + padding-left + padding-right + border-left-width + border-right-width + margin-left + margin-right
总高度 = height + padding-top + padding-bottom + border-top-width + border-bottom-width + margin-top + margin-bottom

示例计算

cpp 复制代码
QPushButton {
    width: 100px;        /* 内容宽度 */
    height: 30px;        /* 内容高度 */
    padding: 10px;        /* 内边距:上下左右各10px */
    border: 2px solid;    /* 边框:上下左右各2px */
    margin: 5px;          /* 外边距:上下左右各5px */
}

/* 总宽度 = 100 + 10*2 + 2*2 + 5*2 = 134px */
/* 总高度 = 30 + 10*2 + 2*2 + 5*2 = 64px */

注意事项

  1. 外边距不计算在控件尺寸内:外边距是控件外部的空间
  2. 边框和内边距会增加控件尺寸 :如果设置了width: 100pxpadding: 10px,实际内容区域会小于100px
  3. 盒模型会影响布局:布局管理器计算控件尺寸时会考虑内边距和边框
盒模型的实际应用

场景1:按钮样式设计

cpp 复制代码
QPushButton {
    /* 内容区域 */
    min-width: 100px;
    min-height: 35px;
    
    /* 内边距:让文本不贴边 */
    padding: 8px 16px;
    
    /* 边框:定义按钮边界 */
    border: 1px solid #4CAF50;
    border-radius: 4px;
    
    /* 外边距:按钮之间的间距 */
    margin: 4px;
}

场景2:输入框样式设计

cpp 复制代码
QLineEdit {
    /* 内容区域 */
    min-height: 30px;
    
    /* 内边距:让输入文本不贴边 */
    padding: 5px 10px;
    
    /* 边框:定义输入框边界 */
    border: 1px solid #cccccc;
    border-radius: 3px;
    
    /* 外边距:输入框之间的间距 */
    margin: 2px;
}

场景3:卡片样式设计

cpp 复制代码
QWidget {
    /* 内容区域 */
    min-width: 200px;
    min-height: 150px;
    
    /* 内边距:内容与卡片边缘的距离 */
    padding: 20px;
    
    /* 边框:卡片边界 */
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    
    /* 外边距:卡片之间的间距 */
    margin: 10px;
    
    /* 背景 */
    background-color: white;
}

盒模型调试技巧

可以通过设置不同的边框颜色来可视化盒模型:

cpp 复制代码
QPushButton {
    border: 2px solid red;      /* 边框:红色 */
    padding: 10px;               /* 内边距:10px */
    background-color: blue;     /* 背景:蓝色(包括内边距区域) */
}

2.5 QSS子控件(Sub-Controls)

什么是子控件

子控件概念

子控件(Sub-Controls)是复杂控件内部的组成部分。例如,QComboBox(组合框)包含下拉箭头、文本区域等子控件;QScrollBar(滚动条)包含滑块、上下箭头等子控件。

子控件语法

cpp 复制代码
主控件::子控件 {
    属性: 值;
}

示例

cpp 复制代码
// 设置QComboBox的下拉箭头样式
QComboBox::drop-down {
    border: 1px solid #cccccc;
    background-color: #f0f0f0;
}
常用控件的子控件列表

QComboBox(组合框)

  • ::drop-down:下拉箭头按钮
  • ::down-arrow:下拉箭头图标
cpp 复制代码
QComboBox {
    border: 1px solid #cccccc;
    padding: 5px;
}

QComboBox::drop-down {
    border: none;
    background-color: #4CAF50;
    width: 30px;
}

QComboBox::down-arrow {
    image: url(:/images/arrow_down.png);
    width: 12px;
    height: 12px;
}

QScrollBar(滚动条)

  • ::handle:滑块
  • ::add-line:增加按钮(向下/向右)
  • ::sub-line:减少按钮(向上/向左)
  • ::add-page:增加页面区域
  • ::sub-page:减少页面区域
cpp 复制代码
QScrollBar:vertical {
    width: 12px;
    background-color: #f0f0f0;
}

QScrollBar::handle:vertical {
    background-color: #cccccc;
    min-height: 20px;
    border-radius: 6px;
}

QScrollBar::handle:vertical:hover {
    background-color: #999999;
}

QScrollBar::add-line:vertical,
QScrollBar::sub-line:vertical {
    height: 0px;  /* 隐藏箭头按钮 */
}

QSpinBox/QDoubleSpinBox(数字输入框)

  • ::up-button:增加按钮
  • ::down-button:减少按钮
  • ::up-arrow:向上箭头
  • ::down-arrow:向下箭头
cpp 复制代码
QSpinBox {
    border: 1px solid #cccccc;
    padding: 5px;
}

QSpinBox::up-button {
    background-color: #4CAF50;
    border: none;
    width: 20px;
}

QSpinBox::down-button {
    background-color: #f44336;
    border: none;
    width: 20px;
}

QSlider(滑块)

  • ::handle:滑块手柄
  • ::groove:滑槽
  • ::sub-page:滑块左侧区域
  • ::add-page:滑块右侧区域
cpp 复制代码
QSlider::groove:horizontal {
    height: 4px;
    background-color: #e0e0e0;
}

QSlider::handle:horizontal {
    width: 16px;
    height: 16px;
    background-color: #4CAF50;
    border-radius: 8px;
    margin: -6px 0;
}

QSlider::handle:horizontal:hover {
    background-color: #45a049;
}

QProgressBar(进度条)

  • ::chunk:进度块
cpp 复制代码
QProgressBar {
    border: 1px solid #cccccc;
    border-radius: 3px;
    text-align: center;
}

QProgressBar::chunk {
    background-color: #4CAF50;
    border-radius: 2px;
}

QTabWidget(标签页)

  • ::tab-bar:标签栏
  • ::tab:标签页
cpp 复制代码
QTabWidget::pane {
    border: 1px solid #cccccc;
}

QTabBar::tab {
    background-color: #f0f0f0;
    padding: 8px 16px;
    border: 1px solid #cccccc;
}

QTabBar::tab:selected {
    background-color: #4CAF50;
    color: white;
}
子控件的样式设置

基本用法

cpp 复制代码
// 设置主控件样式
QComboBox {
    border: 1px solid #cccccc;
    padding: 5px;
    border-radius: 3px;
}

// 设置子控件样式
QComboBox::drop-down {
    border: none;
    background-color: #4CAF50;
    width: 30px;
    border-top-right-radius: 3px;
    border-bottom-right-radius: 3px;
}

子控件与伪状态组合

cpp 复制代码
QScrollBar::handle:vertical:hover {
    background-color: #999999;
}

QScrollBar::handle:vertical:pressed {
    background-color: #666666;
}

子控件的尺寸控制

cpp 复制代码
QComboBox::drop-down {
    width: 30px;  /* 固定宽度 */
}

QScrollBar::handle:vertical {
    min-height: 20px;  /* 最小高度 */
}
子控件的布局控制

子控件位置

使用subcontrol-positionsubcontrol-origin控制子控件的位置:

cpp 复制代码
QComboBox::drop-down {
    subcontrol-origin: padding;
    subcontrol-position: top right;
    width: 30px;
}

子控件对齐

cpp 复制代码
QComboBox::down-arrow {
    image: url(:/images/arrow.png);
    width: 12px;
    height: 12px;
    subcontrol-origin: padding;
    subcontrol-position: center;
}

实际应用示例

cpp 复制代码
// 自定义组合框样式
QComboBox {
    border: 1px solid #cccccc;
    border-radius: 3px;
    padding: 5px 10px;
    min-width: 120px;
}

QComboBox::drop-down {
    subcontrol-origin: padding;
    subcontrol-position: top right;
    width: 30px;
    border-left: 1px solid #cccccc;
    border-top-right-radius: 3px;
    border-bottom-right-radius: 3px;
    background-color: #f0f0f0;
}

QComboBox::down-arrow {
    image: url(:/images/arrow_down.png);
    width: 12px;
    height: 12px;
}

QComboBox::drop-down:hover {
    background-color: #e0e0e0;
}

2.6 QSS伪状态(Pseudo-States)

伪状态是QSS中非常重要的特性,它允许根据控件的状态(如悬停、按下、选中等)来应用不同的样式。

常用伪状态列表

交互状态

  1. :hover:鼠标悬停

    cpp 复制代码
    QPushButton:hover {
        background-color: #45a049;
    }
  2. :pressed:按下状态

    cpp 复制代码
    QPushButton:pressed {
        background-color: #3d8b40;
    }
  3. :focus:获得焦点

    cpp 复制代码
    QLineEdit:focus {
        border: 2px solid #2196F3;
    }

选中状态

  1. :checked:选中(用于复选框、单选按钮等)

    cpp 复制代码
    QCheckBox:checked {
        color: blue;
    }
  2. :unchecked:未选中

    cpp 复制代码
    QCheckBox:unchecked {
        color: gray;
    }

启用/禁用状态

  1. :enabled:启用状态

    cpp 复制代码
    QPushButton:enabled {
        background-color: #4CAF50;
    }
  2. :disabled:禁用状态

    cpp 复制代码
    QPushButton:disabled {
        background-color: #cccccc;
        color: #999999;
    }

其他状态

  1. :flat:扁平样式

    cpp 复制代码
    QPushButton:flat {
        border: none;
    }
  2. :default:默认按钮

    cpp 复制代码
    QPushButton:default {
        border: 2px solid #2196F3;
    }
  3. :exclusive:独占按钮组

    cpp 复制代码
    QPushButton:exclusive {
        background-color: #4CAF50;
    }
伪状态的组合使用

多个伪状态组合

cpp 复制代码
// 悬停且未禁用
QPushButton:hover:!disabled {
    background-color: #45a049;
}

// 选中且悬停
QCheckBox:checked:hover {
    color: darkblue;
}

// 按下且获得焦点
QPushButton:pressed:focus {
    background-color: #3d8b40;
    border: 2px solid #2196F3;
}

否定伪状态

使用!来否定伪状态:

cpp 复制代码
// 未禁用
QPushButton:!disabled {
    background-color: #4CAF50;
}

// 未选中
QCheckBox:!checked {
    color: gray;
}

完整的状态链示例

cpp 复制代码
QPushButton {
    /* 默认状态 */
    background-color: #4CAF50;
    color: white;
    border: none;
    padding: 10px;
    border-radius: 5px;
}

QPushButton:hover {
    /* 悬停状态 */
    background-color: #45a049;
}

QPushButton:pressed {
    /* 按下状态 */
    background-color: #3d8b40;
}

QPushButton:focus {
    /* 获得焦点 */
    border: 2px solid #2196F3;
}

QPushButton:disabled {
    /* 禁用状态 */
    background-color: #cccccc;
    color: #999999;
}
自定义伪状态

注意:QSS本身不支持自定义伪状态,但可以通过控件的属性(property)来模拟:

cpp 复制代码
// 设置自定义属性
QPushButton *btn = new QPushButton("按钮");
btn->setProperty("state", "loading");

// 使用属性选择器
qApp->setStyleSheet(
    "QPushButton[state=\"loading\"] {"
    "    background-color: #ff9800;"
    "}"
    
    "QPushButton[state=\"success\"] {"
    "    background-color: #4CAF50;"
    "}"
);

动态切换属性

cpp 复制代码
// 切换状态
void setButtonState(QPushButton *btn, const QString &state) {
    btn->setProperty("state", state);
    btn->style()->unpolish(btn);  // 刷新样式
    btn->style()->polish(btn);
    btn->update();
}
动态伪状态切换

代码控制伪状态

虽然伪状态(如:hover:pressed)是自动的,但可以通过代码来触发某些状态:

cpp 复制代码
// 程序化触发焦点
QPushButton *btn = new QPushButton("按钮");
btn->setFocus();  // 触发:focus状态

// 程序化触发选中
QCheckBox *checkbox = new QCheckBox("选项");
checkbox->setChecked(true);  // 触发:checked状态

// 程序化触发禁用
QPushButton *btn = new QPushButton("按钮");
btn->setEnabled(false);  // 触发:disabled状态

状态切换示例

cpp 复制代码
class CustomButton : public QPushButton {
    Q_OBJECT
public:
    CustomButton(const QString &text, QWidget *parent = nullptr)
        : QPushButton(text, parent)
    {
        setProperty("customState", "normal");
    }
    
    void setCustomState(const QString &state) {
        setProperty("customState", state);
        style()->unpolish(this);
        style()->polish(this);
        update();
    }
};

// 样式定义
qApp->setStyleSheet(
    "CustomButton[customState=\"normal\"] {"
    "    background-color: #4CAF50;"
    "}"
    
    "CustomButton[customState=\"loading\"] {"
    "    background-color: #ff9800;"
    "}"
    
    "CustomButton[customState=\"success\"] {"
    "    background-color: #4CAF50;"
    "}"
);

2.7 QSS高级特性

渐变(Gradients)

线性渐变

使用qlineargradient()函数创建线性渐变:

cpp 复制代码
QPushButton {
    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                stop:0 white, stop:1 gray);
}

参数说明

  • x1, y1:起始点坐标(0-1)
  • x2, y2:结束点坐标(0-1)
  • stop:位置 颜色:渐变停止点

渐变示例

cpp 复制代码
// 垂直渐变(从上到下)
QPushButton {
    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                stop:0 #4CAF50, stop:1 #45a049);
}

// 水平渐变(从左到右)
QPushButton {
    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                                stop:0 #4CAF50, stop:1 #45a049);
}

// 多色渐变
QPushButton {
    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                stop:0 white,
                                stop:0.5 #4CAF50,
                                stop:1 #45a049);
}

径向渐变

使用qradialgradient()函数创建径向渐变:

cpp 复制代码
QPushButton {
    background: qradialgradient(cx:0.5, cy:0.5, radius:0.5,
                                 fx:0.5, fy:0.5,
                                 stop:0 white, stop:1 gray);
}
图片和图标

背景图片

cpp 复制代码
QPushButton {
    background-image: url(:/images/button_bg.png);
    background-repeat: no-repeat;
    background-position: center;
}

边框图片

cpp 复制代码
QPushButton {
    border-image: url(:/images/button_border.png) 10 10 10 10 stretch stretch;
}

图标

cpp 复制代码
// 在按钮上设置图标(通过代码)
QPushButton *btn = new QPushButton("按钮");
btn->setIcon(QIcon(":/images/icon.png"));

// 通过QSS设置子控件的图标
QComboBox::down-arrow {
    image: url(:/images/arrow_down.png);
    width: 12px;
    height: 12px;
}
透明度和阴影

透明度

cpp 复制代码
QPushButton {
    background-color: rgba(76, 175, 80, 0.8);  /* RGBA格式 */
}

QWidget {
    background-color: transparent;  /* 透明背景 */
}

阴影效果(通过边框模拟):

cpp 复制代码
QPushButton {
    background-color: #4CAF50;
    border: none;
    border-radius: 5px;
    /* 注意:QSS不直接支持box-shadow,可以通过多层边框模拟 */
}

注意 :QSS不直接支持box-shadow属性,如果需要阴影效果,可以考虑:

  1. 使用图片
  2. 通过代码绘制
  3. 使用多层控件模拟
动画和过渡效果

QSS的动画支持

QSS本身不支持CSS那样的动画(@keyframesanimation等),但可以通过以下方式实现类似效果:

1. 使用伪状态切换

cpp 复制代码
QPushButton {
    background-color: #4CAF50;
    transition: background-color 0.3s;  /* 注意:QSS不支持transition */
}

QPushButton:hover {
    background-color: #45a049;
}

注意 :QSS不支持transition属性,状态切换是瞬时的。

2. 通过代码实现动画

cpp 复制代码
// 使用QPropertyAnimation实现颜色过渡
QPropertyAnimation *animation = new QPropertyAnimation(button, "styleSheet");
animation->setDuration(300);
animation->setStartValue("background-color: #4CAF50;");
animation->setEndValue("background-color: #45a049;");
animation->start();

3. 使用Qt动画框架

cpp 复制代码
// 使用QGraphicsOpacityEffect实现淡入淡出
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(button);
button->setGraphicsEffect(effect);

QPropertyAnimation *animation = new QPropertyAnimation(effect, "opacity");
animation->setDuration(300);
animation->setStartValue(0.0);
animation->setEndValue(1.0);
animation->start();

总结

QSS虽然不支持完整的动画系统,但可以通过:

  • 伪状态切换实现简单的交互效果
  • Qt动画框架实现复杂的动画
  • 代码控制实现动态样式切换


3. QStyle样式引擎

3.1 QStyle基础

QStyle是Qt样式系统的核心引擎,它负责实际绘制控件的外观。理解QStyle的工作原理对于深入掌握Qt样式系统至关重要。

QStyle的作用和职责

QStyle是什么?

QStyle是一个抽象基类,定义了绘制Qt控件的接口。它是Qt样式系统的执行引擎,负责将样式规则转换为实际的视觉效果。

QStyle的核心职责

  1. 绘制控件:绘制按钮、复选框、滚动条等控件的视觉外观
  2. 计算尺寸:计算控件的最佳尺寸,考虑内容、内边距、边框等
  3. 提供度量:提供样式相关的度量值(如边框宽度、间距、图标大小等)
  4. 平台适配:在不同平台上提供原生或统一的视觉体验
  5. 样式提示:提供样式相关的提示信息(如控件行为、布局规则等)

QStyle的工作流程

复制代码
控件需要绘制
    ↓
QStyle::drawControl() / drawComplexControl()
    ↓
根据QStyleOption获取控件状态和参数
    ↓
使用QPainter绘制控件外观
    ↓
完成绘制

QStyle与QSS的关系

  • QSS:提供声明式的样式定义(易用、灵活)
  • QStyle:执行实际的绘制工作(强大、可定制)

QSS样式表最终会被QStyle解析和应用。当控件需要绘制时,QStyle会:

  1. 检查是否有QSS样式表
  2. 如果有,解析QSS规则
  3. 结合QStyle的绘制逻辑
  4. 使用QPainter绘制控件

QStyle的优势

  1. 完全控制:可以完全控制控件的绘制逻辑
  2. 平台原生:支持平台原生样式,提供原生体验
  3. 性能优秀:直接绘制,性能优于QSS解析
  4. 可扩展性:可以继承QStyle创建自定义样式

QStyle的局限性

  1. 复杂度高:需要理解Qt的绘制系统
  2. 代码量大:实现完整样式需要大量代码
  3. 维护困难:样式逻辑与代码耦合,不易维护
Qt内置样式列表

Qt提供了多个内置样式,可以在不同平台上使用:

1. Windows样式QWindowsStyle / "windows"

  • 平台:Windows
  • 特点:使用Windows原生样式,提供原生Windows外观
  • 使用qApp->setStyle("windows");

2. macOS样式QMacStyle / "macos"

  • 平台:macOS
  • 特点:使用macOS原生样式,提供原生macOS外观
  • 使用qApp->setStyle("macos");

3. Fusion样式QFusionStyle / "fusion"

  • 平台:所有平台
  • 特点:跨平台统一样式,现代扁平化设计
  • 使用qApp->setStyle("fusion");

4. GTK+样式QGtkStyle / "gtk+"

  • 平台:Linux(需要GTK+)
  • 特点:使用GTK+主题系统
  • 使用qApp->setStyle("gtk+");

5. Android样式QAndroidStyle / "android"

  • 平台:Android
  • 特点:Android Material Design风格
  • 使用qApp->setStyle("android");

6. iOS样式QIOSStyle / "ios"

  • 平台:iOS
  • 特点:iOS原生风格
  • 使用qApp->setStyle("ios");

获取可用样式列表

cpp 复制代码
QStringList availableStyles = QStyleFactory::keys();
qDebug() << "可用样式:" << availableStyles;
// 输出:可用样式:("windows", "fusion", ...)

设置样式

cpp 复制代码
// 方式1:使用样式名称
qApp->setStyle("fusion");

// 方式2:创建样式实例
QStyle *style = QStyleFactory::create("fusion");
qApp->setStyle(style);

// 方式3:使用平台特定样式
#ifdef Q_OS_WIN
    qApp->setStyle("windows");
#elif defined(Q_OS_MAC)
    qApp->setStyle("macos");
#else
    qApp->setStyle("fusion");
#endif
QStyle的继承体系

继承层次结构

复制代码
QStyle (抽象基类)
    ↓
QCommonStyle (通用样式基类)
    ├── QWindowsStyle (Windows样式)
    ├── QMacStyle (macOS样式)
    ├── QFusionStyle (Fusion样式)
    ├── QGtkStyle (GTK+样式)
    ├── QAndroidStyle (Android样式)
    └── QIOSStyle (iOS样式)
    ↓
QProxyStyle (代理样式,用于扩展)

QStyle(抽象基类)

QStyle定义了所有样式必须实现的接口:

cpp 复制代码
class QStyle {
public:
    // 绘制基本元素
    virtual void drawPrimitive(PrimitiveElement pe,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w = nullptr) const = 0;
    
    // 绘制控件元素
    virtual void drawControl(ControlElement element,
                             const QStyleOption *opt,
                             QPainter *p,
                             const QWidget *w = nullptr) const = 0;
    
    // 绘制复杂控件
    virtual void drawComplexControl(ComplexControl cc,
                                    const QStyleOptionComplex *opt,
                                    QPainter *p,
                                    const QWidget *w = nullptr) const = 0;
    
    // 计算控件尺寸
    virtual QSize sizeFromContents(ContentsType ct,
                                    const QStyleOption *opt,
                                    const QSize &contentsSize,
                                    const QWidget *w = nullptr) const = 0;
    
    // 获取像素度量
    virtual int pixelMetric(PixelMetric metric,
                             const QStyleOption *option = nullptr,
                             const QWidget *widget = nullptr) const = 0;
    
    // 获取样式提示
    virtual int styleHint(StyleHint hint,
                          const QStyleOption *option = nullptr,
                          const QWidget *widget = nullptr,
                          QStyleHintReturn *returnData = nullptr) const = 0;
    
    // ... 更多方法
};

QCommonStyle(通用样式基类)

QCommonStyle提供了QStyle接口的默认实现,大多数内置样式都继承自它:

cpp 复制代码
class QCommonStyle : public QStyle {
    // 提供默认实现
    // 子类可以重写特定方法
};

QProxyStyle(代理样式)

QProxyStyle允许在不修改原始样式的情况下扩展样式功能:

cpp 复制代码
class CustomStyle : public QProxyStyle {
public:
    CustomStyle(QStyle *baseStyle = nullptr) : QProxyStyle(baseStyle) {}
    
    void drawPrimitive(PrimitiveElement pe,
                       const QStyleOption *opt,
                       QPainter *p,
                       const QWidget *w = nullptr) const override {
        // 自定义绘制逻辑
        if (pe == PE_PanelButtonCommand) {
            // 自定义按钮绘制
            // ...
        } else {
            // 使用基础样式
            QProxyStyle::drawPrimitive(pe, opt, p, w);
        }
    }
};

// 使用
QStyle *baseStyle = QStyleFactory::create("fusion");
QStyle *customStyle = new CustomStyle(baseStyle);
qApp->setStyle(customStyle);
样式引擎的工作原理

样式引擎的工作流程

  1. 控件请求绘制 :当控件需要绘制时(如paintEvent()),调用QStyle::drawControl()drawComplexControl()

  2. 创建样式选项 :控件创建QStyleOption对象,包含绘制所需的所有信息(位置、大小、状态等)

  3. 样式处理:QStyle根据样式选项和控件状态,决定如何绘制

  4. 应用QSS:如果有QSS样式表,QStyle会解析并应用QSS规则

  5. 执行绘制 :使用QPainter实际绘制控件

源码示例(简化版):

cpp 复制代码
// 控件绘制流程(简化)
void QPushButton::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QStyleOptionButton option;
    initStyleOption(&option);  // 初始化样式选项
    
    // 调用样式引擎绘制
    style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
}

// QStyle的绘制实现(简化)
void QCommonStyle::drawControl(ControlElement element,
                                const QStyleOption *opt,
                                QPainter *p,
                                const QWidget *widget) const {
    switch (element) {
        case CE_PushButton:
            // 绘制按钮
            drawPushButton(opt, p, widget);
            break;
        case CE_PushButtonLabel:
            // 绘制按钮标签
            drawPushButtonLabel(opt, p, widget);
            break;
        // ... 其他控件元素
    }
}

样式选项(QStyleOption)

QStyleOption包含绘制所需的所有信息:

cpp 复制代码
class QStyleOption {
public:
    QRect rect;              // 绘制区域
    QPalette palette;         // 调色板
    QFont font;              // 字体
    QStyle::State state;     // 状态(启用、禁用、悬停等)
    // ... 更多属性
};

// 控件特定的样式选项
class QStyleOptionButton : public QStyleOption {
public:
    QString text;            // 按钮文本
    QIcon icon;              // 按钮图标
    QSize iconSize;          // 图标大小
    bool flat;               // 是否扁平
    // ... 更多属性
};

样式状态(State)

QStyle::State枚举定义了控件的状态:

cpp 复制代码
enum State {
    State_None = 0x00000000,
    State_Enabled = 0x00000001,      // 启用
    State_Raised = 0x00000002,       // 凸起
    State_Sunken = 0x00000004,       // 凹陷
    State_Off = 0x00000008,          // 关闭
    State_NoChange = 0x00000010,     // 无变化
    State_On = 0x00000020,            // 开启
    State_Horizontal = 0x00000040,   // 水平
    State_HasFocus = 0x00000080,     // 有焦点
    State_Top = 0x00000100,           // 顶部
    State_Bottom = 0x00000200,        // 底部
    State_FocusAtBorder = 0x00000400, // 焦点在边框
    State_AutoRaise = 0x00000800,     // 自动凸起
    State_MouseOver = 0x00001000,     // 鼠标悬停
    State_UpArrow = 0x00002000,       // 上箭头
    State_Selected = 0x00004000,      // 选中
    State_Active = 0x00008000,         // 活动
    State_Window = 0x00010000,        // 窗口
    State_Open = 0x00020000,           // 打开
    State_Children = 0x00040000,       // 有子项
    State_Item = 0x00080000,           // 项
    State_Sibling = 0x00100000,        // 兄弟
    State_Editing = 0x00200000,        // 编辑
    State_KeyboardFocusChange = 0x00400000, // 键盘焦点变化
    State_ReadOnly = 0x02000000,      // 只读
    State_Small = 0x04000000,          // 小
    State_Mini = 0x08000000            // 迷你
};

样式引擎的调用链

复制代码
控件::paintEvent()
    ↓
QStylePainter::drawControl()
    ↓
QStyle::drawControl()
    ↓
QCommonStyle::drawControl() (或自定义样式)
    ↓
具体绘制方法(如drawPushButton)
    ↓
QPainter绘制

性能考虑

  1. 缓存样式选项:避免重复创建样式选项
  2. 减少重绘:只在必要时重绘
  3. 使用硬件加速:利用GPU加速绘制
  4. 优化绘制路径:减少不必要的绘制操作

3.2 QStyle绘制系统

QStyle的绘制系统提供了多个绘制方法,用于绘制不同类型的控件元素。理解这些方法对于自定义样式至关重要。

drawPrimitive() - 绘制基本元素

作用

drawPrimitive()用于绘制基本图形元素,如按钮背景、复选框、单选按钮等。这些是构成控件的"原子"元素。

函数签名

cpp 复制代码
virtual void drawPrimitive(PrimitiveElement pe,
                           const QStyleOption *opt,
                           QPainter *p,
                           const QWidget *w = nullptr) const = 0;

参数说明

  • pe:基本元素类型(PrimitiveElement枚举)
  • opt:样式选项,包含绘制所需的信息
  • p:绘制器(QPainter),用于实际绘制
  • w:控件指针(可选)

常用PrimitiveElement类型

cpp 复制代码
enum PrimitiveElement {
    PE_PanelButtonCommand,    // 按钮面板
    PE_PanelButtonBevel,      // 按钮斜面
    PE_PanelButtonTool,       // 工具按钮面板
    PE_PanelMenuBar,          // 菜单栏面板
    PE_PanelMenu,             // 菜单面板
    PE_PanelTipLabel,         // 提示标签面板
    PE_PanelItemViewItem,     // 列表项面板
    PE_PanelItemViewRow,      // 列表行面板
    PE_PanelScrollAreaCorner, // 滚动区域角落
    PE_Widget,                // 通用控件
    PE_IndicatorArrowUp,      // 上箭头
    PE_IndicatorArrowDown,    // 下箭头
    PE_IndicatorArrowLeft,     // 左箭头
    PE_IndicatorArrowRight,   // 右箭头
    PE_IndicatorBranch,        // 分支指示器
    PE_IndicatorViewItemCheck, // 列表项复选框
    PE_IndicatorItemViewItemCheck, // 列表项复选框(另一种)
    PE_IndicatorCheckBox,     // 复选框
    PE_IndicatorRadioButton,  // 单选按钮
    PE_IndicatorDockWidgetResizeHandle, // 停靠窗口调整手柄
    PE_FrameFocusRect,        // 焦点矩形
    PE_FrameDefaultButton,    // 默认按钮框架
    PE_FrameButtonBevel,      // 按钮斜面框架
    PE_FrameButtonTool,       // 工具按钮框架
    PE_Frame,                 // 通用框架
    PE_FrameLineEdit,         // 行编辑框框架
    PE_FrameMenu,              // 菜单框架
    PE_FrameTabWidget,        // 标签页控件框架
    PE_FrameTabBarBase,        // 标签栏基础框架
    PE_FrameStatusBar,         // 状态栏框架
    PE_FrameStatusBarItem,     // 状态栏项框架
    PE_FrameWindow,            // 窗口框架
    PE_FrameGroupBox,          // 分组框框架
    PE_FrameButtonBevel,       // 按钮斜面框架
    PE_IndicatorToolBarHandle, // 工具栏手柄
    PE_IndicatorToolBarSeparator, // 工具栏分隔符
    PE_IndicatorHeaderArrow,   // 表头箭头
    PE_IndicatorMenuCheckMark, // 菜单复选标记
    PE_IndicatorProgressChunk, // 进度块
    PE_IndicatorSpinMinus,     // 减号指示器
    PE_IndicatorSpinPlus,      // 加号指示器
    PE_IndicatorSpinUp,        // 上箭头指示器
    PE_IndicatorSpinDown,      // 下箭头指示器
    PE_IndicatorToolBarHandle, // 工具栏手柄
    PE_IndicatorColumnViewArrow, // 列视图箭头
    PE_PanelItemViewRow,       // 列表行面板
    PE_PanelItemViewItem,      // 列表项面板
    PE_PanelStatusBar,          // 状态栏面板
    PE_IndicatorTabTear,       // 标签页撕裂指示器
    PE_PanelTipLabel,          // 提示标签面板
    PE_PanelMenu,              // 菜单面板
    PE_PanelButtonCommand,      // 命令按钮面板
    PE_PanelButtonBevel,       // 斜面按钮面板
    PE_PanelButtonTool,        // 工具按钮面板
    PE_PanelLineEdit,          // 行编辑框面板
    PE_IndicatorItemViewItemDrop, // 列表项拖放指示器
    PE_PanelScrollAreaCorner,   // 滚动区域角落面板
    PE_Widget,                 // 通用控件
    // ... 更多类型
};

使用示例

cpp 复制代码
// 自定义样式:绘制按钮面板
void CustomStyle::drawPrimitive(PrimitiveElement pe,
                                 const QStyleOption *opt,
                                 QPainter *p,
                                 const QWidget *w) const {
    if (pe == PE_PanelButtonCommand) {
        // 绘制按钮面板
        QRect rect = opt->rect;
        QColor backgroundColor;
        
        if (opt->state & QStyle::State_MouseOver) {
            backgroundColor = QColor(69, 160, 73);  // 悬停颜色
        } else if (opt->state & QStyle::State_Sunken) {
            backgroundColor = QColor(61, 139, 64);  // 按下颜色
        } else {
            backgroundColor = QColor(76, 175, 80);  // 默认颜色
        }
        
        p->fillRect(rect, backgroundColor);
        
        // 绘制边框
        p->setPen(QPen(QColor(69, 160, 73), 1));
        p->drawRect(rect.adjusted(0, 0, -1, -1));
    } else {
        // 使用基础样式绘制其他元素
        QProxyStyle::drawPrimitive(pe, opt, p, w);
    }
}
drawControl() - 绘制控件元素

作用

drawControl()用于绘制完整的控件元素,如按钮、复选框、单选按钮、标签等。它通常内部调用drawPrimitive()来绘制基本元素。

函数签名

cpp 复制代码
virtual void drawControl(ControlElement element,
                         const QStyleOption *opt,
                         QPainter *p,
                         const QWidget *w = nullptr) const = 0;

常用ControlElement类型

cpp 复制代码
enum ControlElement {
    CE_PushButton,           // 按钮
    CE_PushButtonBevel,       // 斜面按钮
    CE_PushButtonLabel,       // 按钮标签
    CE_CheckBox,              // 复选框
    CE_CheckBoxLabel,         // 复选框标签
    CE_RadioButton,           // 单选按钮
    CE_RadioButtonLabel,      // 单选按钮标签
    CE_TabBarTab,             // 标签页
    CE_TabBarTabShape,        // 标签页形状
    CE_TabBarTabLabel,        // 标签页标签
    CE_ProgressBar,           // 进度条
    CE_ProgressBarGroove,     // 进度条槽
    CE_ProgressBarContents,   // 进度条内容
    CE_ProgressBarLabel,      // 进度条标签
    CE_MenuItem,              // 菜单项
    CE_MenuScroller,          // 菜单滚动器
    CE_MenuVMargin,           // 菜单垂直边距
    CE_MenuHMargin,           // 菜单水平边距
    CE_MenuTearoff,           // 菜单撕下
    CE_MenuEmptyArea,         // 菜单空区域
    CE_MenuBarItem,           // 菜单栏项
    CE_MenuBarEmptyArea,      // 菜单栏空区域
    CE_ToolButtonLabel,       // 工具按钮标签
    CE_Header,                 // 表头
    CE_HeaderSection,          // 表头节
    CE_HeaderLabel,            // 表头标签
    CE_ScrollBarAddLine,       // 滚动条增加线
    CE_ScrollBarSubLine,       // 滚动条减少线
    CE_ScrollBarAddPage,       // 滚动条增加页
    CE_ScrollBarSubPage,       // 滚动条减少页
    CE_ScrollBarSlider,        // 滚动条滑块
    CE_ScrollBarFirst,         // 滚动条第一个
    CE_ScrollBarLast,          // 滚动条最后一个
    CE_RubberBand,             // 橡皮筋选择框
    CE_FocusFrame,             // 焦点框架
    CE_ItemViewItem,           // 列表项
    CE_ShapedFrame,            // 形状框架
    CE_ToolBoxTab,             // 工具箱标签
    CE_SizeGrip,               // 大小调整手柄
    CE_Splitter,               // 分割器
    CE_ToolBar,                // 工具栏
    CE_ToolButton,             // 工具按钮
    CE_DockWidgetTitle,        // 停靠窗口标题
    CE_HeaderEmptyArea,        // 表头空区域
    CE_ColumnViewGrip,        // 列视图手柄
    CE_ItemViewItemCheckIndicator, // 列表项复选指示器
    CE_ShapedFrame,            // 形状框架
    // ... 更多类型
};

使用示例

cpp 复制代码
// 自定义样式:绘制按钮
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_PushButton) {
        const QStyleOptionButton *btnOpt = qstyleoption_cast<const QStyleOptionButton *>(opt);
        if (!btnOpt) return;
        
        // 绘制按钮背景
        drawPrimitive(PE_PanelButtonCommand, opt, p, w);
        
        // 绘制按钮标签(文本和图标)
        QStyleOptionButton subOpt = *btnOpt;
        subOpt.rect = subControlRect(CC_PushButton, btnOpt, SC_PushButtonLabel, w);
        drawControl(CE_PushButtonLabel, &subOpt, p, w);
    } else {
        // 使用基础样式绘制其他元素
        QProxyStyle::drawControl(element, opt, p, w);
    }
}
drawComplexControl() - 绘制复杂控件

作用

drawComplexControl()用于绘制复杂控件,如组合框、滚动条、滑块、标题栏等。这些控件由多个子控件组成。

函数签名

cpp 复制代码
virtual void drawComplexControl(ComplexControl cc,
                                const QStyleOptionComplex *opt,
                                QPainter *p,
                                const QWidget *w = nullptr) const = 0;

常用ComplexControl类型

cpp 复制代码
enum ComplexControl {
    CC_SpinBox,              // 数字输入框
    CC_ComboBox,             // 组合框
    CC_ScrollBar,             // 滚动条
    CC_Slider,                // 滑块
    CC_ToolButton,            // 工具按钮
    CC_TitleBar,              // 标题栏
    CC_Q3ListView,            // Q3列表视图
    CC_Dial,                  // 拨号盘
    CC_GroupBox,              // 分组框
    CC_MdiControls,           // MDI控件
    CC_CustomBase = 0xf0000000 // 自定义基础
};

使用示例

cpp 复制代码
// 自定义样式:绘制组合框
void CustomStyle::drawComplexControl(ComplexControl cc,
                                     const QStyleOptionComplex *opt,
                                     QPainter *p,
                                     const QWidget *w) const {
    if (cc == CC_ComboBox) {
        const QStyleOptionComboBox *cbOpt = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
        if (!cbOpt) return;
        
        // 绘制组合框框架
        QRect editRect = subControlRect(CC_ComboBox, cbOpt, SC_ComboBoxEditField, w);
        QStyleOptionFrame frameOpt;
        frameOpt.rect = editRect;
        frameOpt.state = opt->state;
        drawPrimitive(PE_FrameLineEdit, &frameOpt, p, w);
        
        // 绘制下拉箭头
        QRect arrowRect = subControlRect(CC_ComboBox, cbOpt, SC_ComboBoxArrow, w);
        QStyleOption arrowOpt;
        arrowOpt.rect = arrowRect;
        arrowOpt.state = opt->state;
        drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w);
    } else {
        // 使用基础样式绘制其他复杂控件
        QProxyStyle::drawComplexControl(cc, opt, p, w);
    }
}
drawItemText() - 绘制文本

作用

drawItemText()用于绘制文本,考虑对齐、换行、省略等。

函数签名

cpp 复制代码
virtual void drawItemText(QPainter *painter,
                           const QRect &rect,
                           int flags,
                           const QPalette &pal,
                           bool enabled,
                           const QString &text,
                           QPalette::ColorRole textRole = QPalette::NoRole) const;

参数说明

  • painter:绘制器
  • rect:文本绘制区域
  • flags:对齐标志(Qt::AlignLeft、Qt::AlignCenter等)
  • pal:调色板
  • enabled:是否启用
  • text:要绘制的文本
  • textRole:文本颜色角色

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_PushButtonLabel) {
        const QStyleOptionButton *btnOpt = qstyleoption_cast<const QStyleOptionButton *>(opt);
        if (!btnOpt) return;
        
        // 绘制文本
        drawItemText(p, btnOpt->rect,
                     Qt::AlignCenter | Qt::TextShowMnemonic,
                     btnOpt->palette,
                     btnOpt->state & State_Enabled,
                     btnOpt->text,
                     QPalette::ButtonText);
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}
drawItemPixmap() - 绘制图片

作用

drawItemPixmap()用于绘制图片(QPixmap),考虑对齐和缩放。

函数签名

cpp 复制代码
virtual void drawItemPixmap(QPainter *painter,
                             const QRect &rect,
                             int alignment,
                             const QPixmap &pixmap) const;

参数说明

  • painter:绘制器
  • rect:图片绘制区域
  • alignment:对齐标志
  • pixmap:要绘制的图片

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_PushButtonLabel) {
        const QStyleOptionButton *btnOpt = qstyleoption_cast<const QStyleOptionButton *>(opt);
        if (!btnOpt) return;
        
        // 绘制图标
        if (!btnOpt->icon.isNull()) {
            QRect iconRect = btnOpt->rect;
            iconRect.setWidth(btnOpt->iconSize.width());
            drawItemPixmap(p, iconRect,
                          Qt::AlignCenter,
                          btnOpt->icon.pixmap(btnOpt->iconSize));
        }
        
        // 绘制文本
        QRect textRect = btnOpt->rect;
        textRect.adjust(btnOpt->iconSize.width() + 4, 0, 0, 0);
        drawItemText(p, textRect,
                     Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
                     btnOpt->palette,
                     btnOpt->state & State_Enabled,
                     btnOpt->text,
                     QPalette::ButtonText);
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}

3.3 QStyle布局系统

QStyle不仅负责绘制控件,还负责计算控件的尺寸、间距等布局相关的度量值。

sizeFromContents() - 计算控件尺寸

作用

sizeFromContents()根据控件的内容尺寸,计算控件的最佳尺寸(包括内边距、边框等)。

函数签名

cpp 复制代码
virtual QSize sizeFromContents(ContentsType ct,
                                const QStyleOption *opt,
                                const QSize &contentsSize,
                                const QWidget *w = nullptr) const = 0;

参数说明

  • ct:内容类型(ContentsType枚举)
  • opt:样式选项
  • contentsSize:内容尺寸(不包括内边距、边框等)
  • w:控件指针(可选)

常用ContentsType类型

cpp 复制代码
enum ContentsType {
    CT_PushButton,        // 按钮
    CT_CheckBox,         // 复选框
    CT_RadioButton,       // 单选按钮
    CT_ToolButton,        // 工具按钮
    CT_ComboBox,          // 组合框
    CT_Splitter,          // 分割器
    CT_ProgressBar,       // 进度条
    CT_MenuItem,          // 菜单项
    CT_MenuBarItem,       // 菜单栏项
    CT_MenuCheckMark,     // 菜单复选标记
    CT_MenuItemCheckMark, // 菜单项复选标记
    CT_SizeGrip,          // 大小调整手柄
    CT_TabBarTab,         // 标签页
    CT_HeaderSection,     // 表头节
    CT_LineEdit,           // 行编辑框
    CT_Menu,              // 菜单
    CT_MenuBar,           // 菜单栏
    CT_ToolBar,           // 工具栏
    CT_CustomBase = 0xf0000000 // 自定义基础
};

使用示例

cpp 复制代码
// 自定义样式:计算按钮尺寸
QSize CustomStyle::sizeFromContents(ContentsType ct,
                                     const QStyleOption *opt,
                                     const QSize &contentsSize,
                                     const QWidget *w) const {
    if (ct == CT_PushButton) {
        const QStyleOptionButton *btnOpt = qstyleoption_cast<const QStyleOptionButton *>(opt);
        if (!btnOpt) return contentsSize;
        
        // 计算按钮尺寸 = 内容尺寸 + 内边距 + 边框
        QSize size = contentsSize;
        size += QSize(20, 10);  // 左右内边距20px,上下内边距10px
        size += QSize(4, 4);    // 边框宽度2px * 2
        
        return size;
    }
    
    return QProxyStyle::sizeFromContents(ct, opt, contentsSize, w);
}
layoutSpacing() - 计算布局间距

作用

layoutSpacing()计算布局中控件之间的间距。

函数签名

cpp 复制代码
virtual int layoutSpacing(QSizePolicy::ControlType control1,
                          QSizePolicy::ControlType control2,
                          Qt::Orientation orientation,
                          const QStyleOption *option = nullptr,
                          const QWidget *widget = nullptr) const;

参数说明

  • control1:第一个控件的类型
  • control2:第二个控件的类型
  • orientation:方向(水平或垂直)
  • option:样式选项(可选)
  • widget:控件指针(可选)

使用示例

cpp 复制代码
// 自定义样式:计算布局间距
int CustomStyle::layoutSpacing(QSizePolicy::ControlType control1,
                                QSizePolicy::ControlType control2,
                                Qt::Orientation orientation,
                                const QStyleOption *option,
                                const QWidget *widget) const {
    // 按钮之间的间距
    if (control1 == QSizePolicy::PushButton && control2 == QSizePolicy::PushButton) {
        return orientation == Qt::Horizontal ? 10 : 5;
    }
    
    // 使用基础样式的间距
    return QProxyStyle::layoutSpacing(control1, control2, orientation, option, widget);
}
pixelMetric() - 获取像素度量

作用

pixelMetric()返回样式相关的像素度量值,如边框宽度、间距、图标大小等。

函数签名

cpp 复制代码
virtual int pixelMetric(PixelMetric metric,
                         const QStyleOption *option = nullptr,
                         const QWidget *widget = nullptr) const = 0;

常用PixelMetric类型

cpp 复制代码
enum PixelMetric {
    PM_ButtonMargin,           // 按钮边距
    PM_ButtonDefaultIndicator, // 默认按钮指示器宽度
    PM_MenuButtonIndicator,    // 菜单按钮指示器宽度
    PM_ButtonShiftHorizontal,   // 按钮水平偏移
    PM_ButtonShiftVertical,    // 按钮垂直偏移
    PM_DefaultFrameWidth,       // 默认框架宽度
    PM_SpinBoxFrameWidth,      // 数字输入框框架宽度
    PM_ComboBoxFrameWidth,      // 组合框框架宽度
    PM_MaximumDragDistance,    // 最大拖拽距离
    PM_ScrollBarExtent,         // 滚动条宽度/高度
    PM_ScrollBarSliderMin,     // 滚动条滑块最小尺寸
    PM_SliderThickness,         // 滑块厚度
    PM_SliderControlThickness,  // 滑块控制厚度
    PM_SliderLength,            // 滑块长度
    PM_SliderTickmarkOffset,    // 滑块刻度偏移
    PM_SliderSpaceAvailable,    // 滑块可用空间
    PM_DockWidgetSeparatorExtent, // 停靠窗口分隔符宽度
    PM_DockWidgetHandleExtent,   // 停靠窗口手柄宽度
    PM_DockWidgetFrameWidth,     // 停靠窗口框架宽度
    PM_DockWidgetTitleMargin,    // 停靠窗口标题边距
    PM_MenuBarPanelWidth,        // 菜单栏面板宽度
    PM_MenuBarItemSpacing,       // 菜单栏项间距
    PM_MenuBarHMargin,            // 菜单栏水平边距
    PM_MenuBarVMargin,            // 菜单栏垂直边距
    PM_ToolBarFrameWidth,        // 工具栏框架宽度
    PM_ToolBarHandleExtent,      // 工具栏手柄宽度
    PM_ToolBarItemSpacing,       // 工具栏项间距
    PM_ToolBarItemMargin,        // 工具栏项边距
    PM_ToolBarSeparatorExtent,   // 工具栏分隔符宽度
    PM_ToolBarExtensionExtent,    // 工具栏扩展宽度
    PM_TabBarTabOverlap,         // 标签页重叠
    PM_TabBarTabHSpace,          // 标签页水平空间
    PM_TabBarTabVSpace,          // 标签页垂直空间
    PM_TabBarBaseHeight,         // 标签栏基础高度
    PM_TabBarBaseOverlap,        // 标签栏基础重叠
    PM_TabBarTabShiftHorizontal, // 标签页水平偏移
    PM_TabBarTabShiftVertical,   // 标签页垂直偏移
    PM_TabBarScrollButtonWidth,  // 标签栏滚动按钮宽度
    PM_TabBarTabShiftHorizontal, // 标签页水平偏移
    PM_TabBarTabShiftVertical,   // 标签页垂直偏移
    PM_ProgressBarChunkWidth,     // 进度条块宽度
    PM_SplitterWidth,             // 分割器宽度
    PM_TitleBarHeight,             // 标题栏高度
    PM_IndicatorWidth,            // 指示器宽度
    PM_IndicatorHeight,            // 指示器高度
    PM_ExclusiveIndicatorWidth,    // 独占指示器宽度
    PM_ExclusiveIndicatorHeight,   // 独占指示器高度
    PM_MenuPanelWidth,             // 菜单面板宽度
    PM_MenuHMargin,                // 菜单水平边距
    PM_MenuVMargin,                // 菜单垂直边距
    PM_MenuScrollerHeight,         // 菜单滚动器高度
    PM_MenuTearoffHeight,          // 菜单撕下高度
    PM_MenuDesktopFrameWidth,      // 菜单桌面框架宽度
    PM_MenuBarPanelWidth,          // 菜单栏面板宽度
    PM_HeaderMargin,               // 表头边距
    PM_HeaderMarkSize,             // 表头标记大小
    PM_HeaderGripMargin,           // 表头手柄边距
    PM_TabBarIconSize,             // 标签栏图标大小
    PM_ListViewIconSize,           // 列表视图图标大小
    PM_IconViewIconSize,           // 图标视图图标大小
    PM_SmallIconSize,              // 小图标大小
    PM_LargeIconSize,              // 大图标大小
    PM_FocusFrameHMargin,          // 焦点框架水平边距
    PM_FocusFrameVMargin,          // 焦点框架垂直边距
    PM_FocusFrameWidth,            // 焦点框架宽度
    PM_LayoutLeftMargin,           // 布局左边距
    PM_LayoutTopMargin,            // 布局上边距
    PM_LayoutRightMargin,          // 布局右边距
    PM_LayoutBottomMargin,         // 布局下边距
    PM_LayoutHorizontalSpacing,    // 布局水平间距
    PM_LayoutVerticalSpacing,      // 布局垂直间距
    PM_MaximumDragDistance,        // 最大拖拽距离
    PM_ScrollBarExtent,            // 滚动条宽度/高度
    PM_ScrollBarSliderMin,         // 滚动条滑块最小尺寸
    PM_SliderThickness,            // 滑块厚度
    PM_SliderControlThickness,     // 滑块控制厚度
    PM_SliderLength,               // 滑块长度
    PM_SliderTickmarkOffset,       // 滑块刻度偏移
    PM_SliderSpaceAvailable,       // 滑块可用空间
    PM_DockWidgetSeparatorExtent,  // 停靠窗口分隔符宽度
    PM_DockWidgetHandleExtent,     // 停靠窗口手柄宽度
    PM_DockWidgetFrameWidth,       // 停靠窗口框架宽度
    PM_DockWidgetTitleMargin,      // 停靠窗口标题边距
    PM_HeaderDefaultSectionSizeHorizontal, // 表头默认节大小(水平)
    PM_HeaderDefaultSectionSizeVertical,   // 表头默认节大小(垂直)
    PM_TabBarIconSize,             // 标签栏图标大小
    PM_TabBarTabShiftHorizontal,   // 标签页水平偏移
    PM_TabBarTabShiftVertical,     // 标签页垂直偏移
    PM_ProgressBarChunkWidth,      // 进度条块宽度
    PM_SplitterWidth,              // 分割器宽度
    PM_TitleBarHeight,             // 标题栏高度
    PM_IndicatorWidth,             // 指示器宽度
    PM_IndicatorHeight,            // 指示器高度
    PM_ExclusiveIndicatorWidth,    // 独占指示器宽度
    PM_ExclusiveIndicatorHeight,   // 独占指示器高度
    PM_MenuPanelWidth,             // 菜单面板宽度
    PM_MenuHMargin,                // 菜单水平边距
    PM_MenuVMargin,                // 菜单垂直边距
    PM_MenuScrollerHeight,         // 菜单滚动器高度
    PM_MenuTearoffHeight,          // 菜单撕下高度
    PM_MenuDesktopFrameWidth,     // 菜单桌面框架宽度
    PM_MenuBarPanelWidth,          // 菜单栏面板宽度
    PM_HeaderMargin,               // 表头边距
    PM_HeaderMarkSize,             // 表头标记大小
    PM_HeaderGripMargin,           // 表头手柄边距
    PM_TabBarIconSize,             // 标签栏图标大小
    PM_ListViewIconSize,           // 列表视图图标大小
    PM_IconViewIconSize,           // 图标视图图标大小
    PM_SmallIconSize,              // 小图标大小
    PM_LargeIconSize,              // 大图标大小
    PM_FocusFrameHMargin,          // 焦点框架水平边距
    PM_FocusFrameVMargin,          // 焦点框架垂直边距
    PM_FocusFrameWidth,            // 焦点框架宽度
    PM_LayoutLeftMargin,           // 布局左边距
    PM_LayoutTopMargin,            // 布局上边距
    PM_LayoutRightMargin,          // 布局右边距
    PM_LayoutBottomMargin,         // 布局下边距
    PM_LayoutHorizontalSpacing,   // 布局水平间距
    PM_LayoutVerticalSpacing,      // 布局垂直间距
    // ... 更多类型
};

使用示例

cpp 复制代码
// 自定义样式:返回像素度量
int CustomStyle::pixelMetric(PixelMetric metric,
                              const QStyleOption *option,
                              const QWidget *widget) const {
    switch (metric) {
        case PM_ButtonMargin:
            return 8;  // 按钮边距8px
        case PM_DefaultFrameWidth:
            return 2;  // 默认框架宽度2px
        case PM_SmallIconSize:
            return 16; // 小图标大小16px
        case PM_LargeIconSize:
            return 32; // 大图标大小32px
        default:
            return QProxyStyle::pixelMetric(metric, option, widget);
    }
}
styleHint() - 获取样式提示

作用

styleHint()返回样式相关的提示信息,如控件行为、布局规则等。

函数签名

cpp 复制代码
virtual int styleHint(StyleHint hint,
                      const QStyleOption *option = nullptr,
                      const QWidget *widget = nullptr,
                      QStyleHintReturn *returnData = nullptr) const = 0;

常用StyleHint类型

cpp 复制代码
enum StyleHint {
    SH_EtchDisabledText,          // 禁用文本是否使用蚀刻效果
    SH_DitherDisabledText,         // 禁用文本是否使用抖动
    SH_ScrollBar_ContextMenu,      // 滚动条上下文菜单
    SH_ScrollBar_LeftClickAbsolutePosition, // 滚动条左键绝对位置
    SH_ScrollBar_RightClickAbsolutePosition, // 滚动条右键绝对位置
    SH_ScrollBar_ScrollWhenPointerLeavesControl, // 指针离开控件时是否滚动
    SH_ScrollBar_StopMouseOverSlider, // 鼠标悬停滑块时是否停止
    SH_ScrollBar_StopMouseOverSlider, // 鼠标悬停滑块时是否停止
    SH_TabBar_Alignment,            // 标签栏对齐
    SH_Header_ArrowAlignment,      // 表头箭头对齐
    SH_Slider_SnapToValue,         // 滑块是否捕捉到值
    SH_Slider_SloppyKeyHandler,     // 滑块是否使用宽松的键盘处理
    SH_ProgressDialog_CenterCancelButton, // 进度对话框取消按钮是否居中
    SH_ProgressDialog_TextLabelAlignment, // 进度对话框文本标签对齐
    SH_ProgressDialog_ElideText,    // 进度对话框文本是否省略
    SH_ScrollView_FrameOnlyAroundContents, // 滚动视图框架是否只围绕内容
    SH_ScrollBar_LeftClickAbsolutePosition, // 滚动条左键绝对位置
    SH_ScrollBar_RightClickAbsolutePosition, // 滚动条右键绝对位置
    SH_MenuBar_AltKeyNavigation,    // 菜单栏Alt键导航
    SH_ComboBox_Popup,              // 组合框弹出方式
    SH_ComboBox_ListMouseTracking,  // 组合框列表鼠标跟踪
    SH_Menu_Scrollable,              // 菜单是否可滚动
    SH_Menu_SloppySubMenus,         // 菜单是否使用宽松的子菜单
    SH_Menu_SubMenuPopupDelay,      // 菜单子菜单弹出延迟
    SH_Menu_SubMenuUniDirection,     // 菜单子菜单单向
    SH_Menu_SubMenuSloppySelectOtherActions, // 菜单子菜单宽松选择其他操作
    SH_Menu_SubMenuSloppyCloseTimeout, // 菜单子菜单宽松关闭超时
    SH_Menu_SubMenuResetWhenReenteringParent, // 菜单子菜单重新进入父菜单时重置
    SH_Menu_SubMenuDontStartSloppyOnLeave, // 菜单子菜单离开时不开始宽松
    SH_Menu_SloppySubMenus,         // 菜单是否使用宽松的子菜单
    SH_Menu_SubMenuPopupDelay,      // 菜单子菜单弹出延迟
    SH_Menu_SubMenuUniDirection,     // 菜单子菜单单向
    SH_Menu_SubMenuSloppySelectOtherActions, // 菜单子菜单宽松选择其他操作
    SH_Menu_SubMenuSloppyCloseTimeout, // 菜单子菜单宽松关闭超时
    SH_Menu_SubMenuResetWhenReenteringParent, // 菜单子菜单重新进入父菜单时重置
    SH_Menu_SubMenuDontStartSloppyOnLeave, // 菜单子菜单离开时不开始宽松
    SH_ItemView_ActivateItemOnSingleClick, // 列表视图是否单击激活项
    SH_ItemView_ChangeHighlightOnFocus, // 列表视图焦点时是否改变高亮
    SH_ItemView_ShowDecorationSelected, // 列表视图是否显示装饰选中
    SH_ItemView_ArrowKeysNavigateIntoChildren, // 列表视图箭头键是否导航到子项
    SH_ItemView_MovementWithoutUpdatingSelection, // 列表视图是否不更新选择就移动
    SH_ItemView_ScrollMode,         // 列表视图滚动模式
    SH_TabBar_ElideMode,            // 标签栏省略模式
    SH_TabBar_CloseButtonPosition,  // 标签栏关闭按钮位置
    SH_DialogButtonBox_ButtonsHaveIcons, // 对话框按钮框按钮是否有图标
    SH_DialogButtonBox_Layout,      // 对话框按钮框布局
    SH_ComboBox_Editable,            // 组合框是否可编辑
    SH_ComboBox_Popup,              // 组合框弹出方式
    SH_ComboBox_ListMouseTracking,  // 组合框列表鼠标跟踪
    SH_ComboBox_AllowWheelScrolling, // 组合框是否允许滚轮滚动
    SH_MessageBox_TextInteractionFlags, // 消息框文本交互标志
    SH_MessageBox_CenterButtons,     // 消息框按钮是否居中
    SH_SpinBox_StepModifier,        // 数字输入框步进修改器
    SH_SpinBox_ButtonsInsideFrame,   // 数字输入框按钮是否在框架内
    SH_ToolButton_PopupDelay,       // 工具按钮弹出延迟
    SH_Menu_KeyboardSearch,         // 菜单键盘搜索
    SH_Menu_AllowActiveAndDisabled, // 菜单是否允许活动和禁用
    SH_Menu_SpaceActivatesItem,     // 菜单空格是否激活项
    SH_Menu_SubMenuPopupDelay,      // 菜单子菜单弹出延迟
    SH_ItemView_ActivateItemOnSingleClick, // 列表视图是否单击激活项
    SH_ItemView_ChangeHighlightOnFocus, // 列表视图焦点时是否改变高亮
    SH_ItemView_ShowDecorationSelected, // 列表视图是否显示装饰选中
    SH_ItemView_ArrowKeysNavigateIntoChildren, // 列表视图箭头键是否导航到子项
    SH_ItemView_MovementWithoutUpdatingSelection, // 列表视图是否不更新选择就移动
    SH_ItemView_ScrollMode,         // 列表视图滚动模式
    SH_TabBar_ElideMode,            // 标签栏省略模式
    SH_TabBar_CloseButtonPosition,  // 标签栏关闭按钮位置
    SH_DialogButtonBox_ButtonsHaveIcons, // 对话框按钮框按钮是否有图标
    SH_DialogButtonBox_Layout,      // 对话框按钮框布局
    SH_ComboBox_Editable,            // 组合框是否可编辑
    SH_ComboBox_Popup,              // 组合框弹出方式
    SH_ComboBox_ListMouseTracking,  // 组合框列表鼠标跟踪
    SH_ComboBox_AllowWheelScrolling, // 组合框是否允许滚轮滚动
    SH_MessageBox_TextInteractionFlags, // 消息框文本交互标志
    SH_MessageBox_CenterButtons,     // 消息框按钮是否居中
    SH_SpinBox_StepModifier,        // 数字输入框步进修改器
    SH_SpinBox_ButtonsInsideFrame,   // 数字输入框按钮是否在框架内
    SH_ToolButton_PopupDelay,       // 工具按钮弹出延迟
    SH_Menu_KeyboardSearch,         // 菜单键盘搜索
    SH_Menu_AllowActiveAndDisabled, // 菜单是否允许活动和禁用
    SH_Menu_SpaceActivatesItem,     // 菜单空格是否激活项
    SH_Menu_SubMenuPopupDelay,      // 菜单子菜单弹出延迟
    // ... 更多类型
};

使用示例

cpp 复制代码
// 自定义样式:返回样式提示
int CustomStyle::styleHint(StyleHint hint,
                            const QStyleOption *option,
                            const QWidget *widget,
                            QStyleHintReturn *returnData) const {
    switch (hint) {
        case SH_EtchDisabledText:
            return true;  // 禁用文本使用蚀刻效果
        case SH_ItemView_ActivateItemOnSingleClick:
            return true;  // 列表视图单击激活项
        case SH_TabBar_ElideMode:
            return Qt::ElideRight;  // 标签栏文本右省略
        default:
            return QProxyStyle::styleHint(hint, option, widget, returnData);
    }
}

3.4 QStyle标准图标

QStyle提供了标准图标的支持,这些图标在不同平台上可能有不同的外观,但功能相同。

standardIcon() - 获取标准图标

作用

standardIcon()返回标准图标(QIcon),用于工具栏、菜单等。

函数签名

cpp 复制代码
virtual QIcon standardIcon(StandardPixmap standardIcon,
                           const QStyleOption *option = nullptr,
                           const QWidget *widget = nullptr) const;

常用StandardPixmap类型

cpp 复制代码
enum StandardPixmap {
    SP_TitleBarMinButton,      // 标题栏最小化按钮
    SP_TitleBarMaxButton,      // 标题栏最大化按钮
    SP_TitleBarCloseButton,    // 标题栏关闭按钮
    SP_TitleBarNormalButton,   // 标题栏正常按钮
    SP_TitleBarShadeButton,    // 标题栏阴影按钮
    SP_TitleBarUnshadeButton,  // 标题栏取消阴影按钮
    SP_TitleBarContextHelpButton, // 标题栏上下文帮助按钮
    SP_MessageBoxInformation,  // 消息框信息图标
    SP_MessageBoxWarning,      // 消息框警告图标
    SP_MessageBoxCritical,     // 消息框严重图标
    SP_MessageBoxQuestion,     // 消息框问题图标
    SP_DesktopIcon,            // 桌面图标
    SP_TrashIcon,              // 垃圾桶图标
    SP_ComputerIcon,           // 计算机图标
    SP_DriveFDIcon,            // 软盘驱动器图标
    SP_DriveHDIcon,            // 硬盘驱动器图标
    SP_DriveCDIcon,            // CD驱动器图标
    SP_DriveDVDIcon,           // DVD驱动器图标
    SP_DriveNetIcon,           // 网络驱动器图标
    SP_DirOpenIcon,            // 打开目录图标
    SP_DirClosedIcon,           // 关闭目录图标
    SP_DirIcon,                // 目录图标
    SP_DirLinkIcon,            // 目录链接图标
    SP_FileIcon,               // 文件图标
    SP_FileLinkIcon,           // 文件链接图标
    SP_FileDialogStart,        // 文件对话框开始
    SP_FileDialogEnd,           // 文件对话框结束
    SP_FileDialogToParent,      // 文件对话框到父目录
    SP_FileDialogNewFolder,     // 文件对话框新建文件夹
    SP_FileDialogDetailedView, // 文件对话框详细视图
    SP_FileDialogInfoView,      // 文件对话框信息视图
    SP_FileDialogContentsView,  // 文件对话框内容视图
    SP_FileDialogListView,      // 文件对话框列表视图
    SP_FileDialogBack,          // 文件对话框返回
    SP_DockWidgetCloseButton,   // 停靠窗口关闭按钮
    SP_ToolBarHorizontalExtensionButton, // 工具栏水平扩展按钮
    SP_ToolBarVerticalExtensionButton,   // 工具栏垂直扩展按钮
    SP_DialogOkButton,          // 对话框确定按钮
    SP_DialogCancelButton,      // 对话框取消按钮
    SP_DialogHelpButton,        // 对话框帮助按钮
    SP_DialogOpenButton,        // 对话框打开按钮
    SP_DialogSaveButton,        // 对话框保存按钮
    SP_DialogCloseButton,       // 对话框关闭按钮
    SP_DialogApplyButton,       // 对话框应用按钮
    SP_DialogResetButton,       // 对话框重置按钮
    SP_DialogDiscardButton,     // 对话框丢弃按钮
    SP_DialogYesButton,         // 对话框是按钮
    SP_DialogNoButton,          // 对话框否按钮
    SP_ArrowUp,                 // 上箭头
    SP_ArrowDown,               // 下箭头
    SP_ArrowLeft,               // 左箭头
    SP_ArrowRight,              // 右箭头
    SP_ArrowBack,               // 返回箭头
    SP_ArrowForward,            // 前进箭头
    SP_FileIcon,                // 文件图标
    SP_DirIcon,                 // 目录图标
    SP_DirLinkIcon,             // 目录链接图标
    SP_FileLinkIcon,            // 文件链接图标
    SP_ComputerIcon,            // 计算机图标
    SP_DesktopIcon,             // 桌面图标
    SP_TrashIcon,               // 垃圾桶图标
    SP_DriveFDIcon,             // 软盘驱动器图标
    SP_DriveHDIcon,             // 硬盘驱动器图标
    SP_DriveCDIcon,             // CD驱动器图标
    SP_DriveDVDIcon,            // DVD驱动器图标
    SP_DriveNetIcon,             // 网络驱动器图标
    SP_DirOpenIcon,              // 打开目录图标
    SP_DirClosedIcon,            // 关闭目录图标
    // ... 更多类型
};

使用示例

cpp 复制代码
// 获取标准图标
QIcon closeIcon = style()->standardIcon(QStyle::SP_TitleBarCloseButton);
QIcon infoIcon = style()->standardIcon(QStyle::SP_MessageBoxInformation);

// 在按钮上使用
QPushButton *closeBtn = new QPushButton(closeIcon, "关闭");
QPushButton *infoBtn = new QPushButton(infoIcon, "信息");
standardPixmap() - 获取标准像素图

作用

standardPixmap()返回标准像素图(QPixmap),用于绘制。

函数签名

cpp 复制代码
virtual QPixmap standardPixmap(StandardPixmap standardPixmap,
                               const QStyleOption *option = nullptr,
                               const QWidget *widget = nullptr) const;

使用示例

cpp 复制代码
// 获取标准像素图
QPixmap closePixmap = style()->standardPixmap(QStyle::SP_TitleBarCloseButton);

// 在标签上使用
QLabel *label = new QLabel();
label->setPixmap(closePixmap);
系统图标的使用

获取系统图标

cpp 复制代码
// 通过QStyle获取
QIcon icon = style()->standardIcon(QStyle::SP_MessageBoxInformation);

// 在控件上使用
QPushButton *btn = new QPushButton(icon, "信息");
QAction *action = new QAction(icon, "信息", this);

在菜单中使用

cpp 复制代码
QMenu *menu = new QMenu(this);
QAction *openAction = menu->addAction(
    style()->standardIcon(QStyle::SP_DialogOpenButton),
    "打开"
);
QAction *saveAction = menu->addAction(
    style()->standardIcon(QStyle::SP_DialogSaveButton),
    "保存"
);
自定义标准图标

重写standardIcon()

cpp 复制代码
class CustomStyle : public QProxyStyle {
public:
    QIcon standardIcon(StandardPixmap standardIcon,
                       const QStyleOption *option = nullptr,
                       const QWidget *widget = nullptr) const override {
        // 自定义特定图标
        if (standardIcon == SP_MessageBoxInformation) {
            return QIcon(":/icons/custom_info.png");
        }
        
        // 使用基础样式的图标
        return QProxyStyle::standardIcon(standardIcon, option, widget);
    }
};

3.5 Qt内置样式详解

Windows样式

特点

  • 平台:Windows
  • 外观:使用Windows原生样式,提供原生Windows外观
  • 适用场景:Windows平台应用程序,需要原生体验

使用

cpp 复制代码
qApp->setStyle("windows");

外观特征

  • 按钮:Windows经典样式
  • 复选框/单选按钮:Windows原生样式
  • 滚动条:Windows原生样式
  • 菜单:Windows原生样式
Fusion样式

特点

  • 平台:所有平台
  • 外观:现代扁平化设计,跨平台统一
  • 适用场景:需要跨平台统一样式的应用程序

使用

cpp 复制代码
qApp->setStyle("fusion");

外观特征

  • 按钮:扁平化设计,圆角边框
  • 复选框/单选按钮:现代扁平化样式
  • 滚动条:细滚动条,现代外观
  • 菜单:扁平化设计

优势

  1. 跨平台统一:在所有平台上外观一致
  2. 现代设计:扁平化设计,符合现代UI趋势
  3. 可定制性强:易于通过QSS定制
macOS样式

特点

  • 平台:macOS
  • 外观:使用macOS原生样式,提供原生macOS外观
  • 适用场景:macOS平台应用程序,需要原生体验

使用

cpp 复制代码
qApp->setStyle("macos");

外观特征

  • 按钮:macOS原生样式
  • 复选框/单选按钮:macOS原生样式
  • 滚动条:macOS原生样式
  • 菜单:macOS原生样式
Android/iOS样式

Android样式

  • 平台:Android
  • 外观:Material Design风格
  • 使用qApp->setStyle("android");

iOS样式

  • 平台:iOS
  • 外观:iOS原生风格
  • 使用qApp->setStyle("ios");
不同平台样式的差异

视觉差异

平台 按钮样式 滚动条样式 菜单样式
Windows 经典3D效果 粗滚动条 经典菜单
macOS 扁平化 细滚动条 原生菜单
Fusion 扁平化 细滚动条 扁平化菜单

功能差异

  • 快捷键:不同平台的快捷键可能不同
  • 菜单行为:菜单的弹出方式和行为可能不同
  • 对话框:对话框的外观和行为可能不同

选择建议

  1. 需要原生体验:使用平台特定样式(Windows、macOS等)
  2. 需要统一样式:使用Fusion样式
  3. 需要自定义:继承QProxyStyle创建自定义样式


4. QPalette调色板系统

4.1 QPalette基础

QPalette是Qt的调色板系统,它定义了应用程序使用的颜色方案。理解QPalette对于创建一致、美观的界面至关重要。

调色板的概念和作用

QPalette是什么?

QPalette是Qt的颜色管理系统,它通过颜色角色(Color Roles)和颜色组(Color Groups)来组织颜色,确保界面颜色的一致性和可访问性。

调色板的核心作用

  1. 统一颜色方案:为应用程序提供统一的颜色方案
  2. 状态适配:根据控件状态(活动、非活动、禁用)使用不同颜色
  3. 主题支持:支持亮色/暗色主题切换
  4. 可访问性:确保颜色对比度符合可访问性要求
  5. 平台适配:在不同平台上提供合适的颜色方案

调色板的设计理念

QPalette的设计遵循"角色-组"模型:

  • 颜色角色(Color Roles):定义颜色的用途(如窗口背景、文本颜色等)
  • 颜色组(Color Groups):定义颜色的状态(如活动、非活动、禁用)

这种设计使得颜色管理更加清晰和灵活。

调色板与直接设置颜色的区别

cpp 复制代码
// ❌ 直接设置颜色(不推荐)
QPushButton *btn = new QPushButton("按钮");
btn->setStyleSheet("background-color: blue; color: white;");

// ✅ 使用调色板(推荐)
QPalette palette;
palette.setColor(QPalette::Button, Qt::blue);
palette.setColor(QPalette::ButtonText, Qt::white);
btn->setPalette(palette);

调色板的优势

  1. 一致性:确保所有控件使用统一的颜色方案
  2. 可维护性:修改调色板即可改变整个应用的颜色
  3. 状态管理:自动处理不同状态的颜色
  4. 主题支持:轻松实现主题切换
调色板的组成部分

1. 颜色角色(Color Roles)

颜色角色定义了颜色的用途。Qt定义了多个颜色角色:

cpp 复制代码
enum ColorRole {
    WindowText,        // 窗口文本色
    Button,            // 按钮背景色
    Light,             // 浅色(用于3D效果)
    Dark,              // 深色(用于3D效果)
    Mid,               // 中间色(用于3D效果)
    Text,              // 文本色
    BrightText,        // 亮文本色
    ButtonText,        // 按钮文本色
    Base,              // 基础背景色(如输入框背景)
    Window,            // 窗口背景色
    Shadow,            // 阴影色
    Highlight,         // 高亮色
    HighlightedText,   // 高亮文本色
    Link,              // 链接色
    LinkVisited,       // 已访问链接色
    AlternateBase,     // 交替背景色(如表格行)
    ToolTipBase,       // 工具提示背景色
    ToolTipText,       // 工具提示文本色
    PlaceholderText,   // 占位符文本色
    NoRole             // 无角色
};

2. 颜色组(Color Groups)

颜色组定义了颜色的状态。Qt定义了三个颜色组:

cpp 复制代码
enum ColorGroup {
    Active,    // 活动状态(窗口有焦点)
    Inactive, // 非活动状态(窗口无焦点)
    Disabled  // 禁用状态(控件被禁用)
};

调色板的结构

复制代码
QPalette
├── Active组
│   ├── WindowText
│   ├── Button
│   ├── Text
│   └── ... (所有颜色角色)
├── Inactive组
│   ├── WindowText
│   ├── Button
│   ├── Text
│   └── ... (所有颜色角色)
└── Disabled组
    ├── WindowText
    ├── Button
    ├── Text
    └── ... (所有颜色角色)

创建调色板

cpp 复制代码
// 创建默认调色板
QPalette palette;

// 创建并设置颜色
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);
palette.setColor(QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Button, Qt::lightGray);
palette.setColor(QPalette::ButtonText, Qt::black);
palette.setColor(QPalette::Highlight, Qt::blue);
palette.setColor(QPalette::HighlightedText, Qt::white);
调色板的继承机制

继承规则

QPalette遵循Qt对象树的继承机制:

  1. 子控件继承父控件的调色板:如果子控件没有设置调色板,它会继承父控件的调色板
  2. 应用级调色板:如果控件没有父控件或父控件没有调色板,使用应用级调色板
  3. 系统默认调色板:如果应用没有设置调色板,使用系统默认调色板

继承示例

cpp 复制代码
// 应用级调色板
QPalette appPalette;
appPalette.setColor(QPalette::Window, Qt::white);
appPalette.setColor(QPalette::WindowText, Qt::black);
qApp->setPalette(appPalette);

// 父控件调色板
QWidget *parent = new QWidget();
QPalette parentPalette = parent->palette();
parentPalette.setColor(QPalette::Window, Qt::lightGray);
parent->setPalette(parentPalette);

// 子控件继承父控件的调色板
QLabel *label = new QLabel("文本", parent);
// label使用parent的调色板(lightGray背景)

// 子控件可以覆盖继承的调色板
QLabel *label2 = new QLabel("文本2", parent);
QPalette label2Palette = label2->palette();
label2Palette.setColor(QPalette::WindowText, Qt::red);
label2->setPalette(label2Palette);
// label2使用自己的调色板(红色文本)

调色板查找顺序

当控件需要获取颜色时,Qt按以下顺序查找:

  1. 控件自身的调色板
  2. 父控件的调色板(向上查找)
  3. QApplication的调色板
  4. 系统默认调色板
调色板与QSS的关系

调色板与QSS的协同工作

QPalette和QSS可以协同工作,但它们的优先级不同:

  1. QSS优先级更高:如果QSS中设置了颜色,会覆盖调色板的颜色
  2. QSS可以引用调色板 :QSS可以使用palette()函数引用调色板的颜色
  3. 调色板作为默认值:如果QSS没有设置颜色,使用调色板的颜色

QSS引用调色板

cpp 复制代码
// 设置调色板
QPalette palette;
palette.setColor(QPalette::Button, Qt::blue);
palette.setColor(QPalette::ButtonText, Qt::white);
qApp->setPalette(palette);

// QSS引用调色板
qApp->setStyleSheet(
    "QPushButton {"
    "    background-color: palette(button);"      // 使用调色板的按钮颜色
    "    color: palette(button-text);"            // 使用调色板的按钮文本颜色
    "}"
);

调色板颜色角色在QSS中的名称

cpp 复制代码
palette(window)           // Window
palette(window-text)      // WindowText
palette(base)             // Base
palette(alternate-base)   // AlternateBase
palette(text)             // Text
palette(button)           // Button
palette(button-text)      // ButtonText
palette(highlight)        // Highlight
palette(highlighted-text) // HighlightedText
palette(link)             // Link
palette(link-visited)     // LinkVisited
palette(tooltip-base)     // ToolTipBase
palette(tooltip-text)     // ToolTipText

实际应用

cpp 复制代码
// 方式1:使用调色板
QPalette palette;
palette.setColor(QPalette::Button, Qt::blue);
qApp->setPalette(palette);

// 方式2:使用QSS
qApp->setStyleSheet("QPushButton { background-color: blue; }");

// 方式3:QSS引用调色板(推荐)
QPalette palette;
palette.setColor(QPalette::Button, Qt::blue);
qApp->setPalette(palette);
qApp->setStyleSheet("QPushButton { background-color: palette(button); }");

最佳实践

  1. 使用调色板定义颜色方案:在调色板中定义主要的颜色
  2. 使用QSS定义样式细节:使用QSS定义边框、圆角等样式细节
  3. QSS引用调色板 :在QSS中使用palette()函数引用调色板的颜色
  4. 保持一致性:确保调色板和QSS的颜色方案一致

4.2 颜色角色(Color Roles)

颜色角色定义了颜色的用途。理解每个颜色角色的作用对于正确使用调色板至关重要。

Window - 窗口背景色

作用:窗口的背景颜色。

使用场景

  • 主窗口背景
  • 对话框背景
  • 面板背景

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QWidget { background-color: palette(window); }");

注意事项

  • Window颜色通常用于窗口和面板的背景
  • 应该与WindowText颜色有足够的对比度
WindowText - 窗口文本色

作用:窗口中的文本颜色。

使用场景

  • 窗口标题文本
  • 标签文本
  • 一般文本

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::WindowText, Qt::black);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QLabel { color: palette(window-text); }");

注意事项

  • WindowText颜色应该与Window颜色有足够的对比度
  • 通常用于窗口中的主要文本
Base - 基础背景色

作用:输入控件(如输入框、文本编辑器)的背景颜色。

使用场景

  • QLineEdit背景
  • QTextEdit背景
  • QPlainTextEdit背景
  • 列表视图背景

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Base, Qt::white);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QLineEdit { background-color: palette(base); }");

注意事项

  • Base颜色通常比Window颜色更亮或更暗,以区分输入区域
  • 应该与Text颜色有足够的对比度
AlternateBase - 交替背景色

作用:交替行的背景颜色(用于表格、列表等)。

使用场景

  • QTableView的交替行
  • QTreeView的交替行
  • 列表的交替项

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::AlternateBase, QColor(240, 240, 240));
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QTableView { alternate-background-color: palette(alternate-base); }");

注意事项

  • AlternateBase颜色应该与Base颜色有轻微差异
  • 用于提高表格和列表的可读性
Text - 文本色

作用:输入控件中的文本颜色。

使用场景

  • QLineEdit中的文本
  • QTextEdit中的文本
  • 列表项文本

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Text, Qt::black);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QLineEdit { color: palette(text); }");

注意事项

  • Text颜色应该与Base颜色有足够的对比度
  • 用于输入控件中的文本
Button - 按钮背景色

作用:按钮的背景颜色。

使用场景

  • QPushButton背景
  • QToolButton背景
  • 按钮类控件

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Button, QColor(240, 240, 240));
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QPushButton { background-color: palette(button); }");

注意事项

  • Button颜色通常比Window颜色稍暗或稍亮
  • 应该与ButtonText颜色有足够的对比度
ButtonText - 按钮文本色

作用:按钮中的文本颜色。

使用场景

  • QPushButton文本
  • QToolButton文本
  • 按钮类控件的文本

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::ButtonText, Qt::black);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QPushButton { color: palette(button-text); }");

注意事项

  • ButtonText颜色应该与Button颜色有足够的对比度
  • 用于按钮中的文本
Highlight - 高亮色

作用:选中项的高亮背景颜色。

使用场景

  • 列表选中项背景
  • 表格选中行背景
  • 菜单选中项背景

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Highlight, Qt::blue);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QListView::item:selected { background-color: palette(highlight); }");

注意事项

  • Highlight颜色应该醒目,但不要太刺眼
  • 应该与HighlightedText颜色有足够的对比度
HighlightedText - 高亮文本色

作用:选中项中的文本颜色。

使用场景

  • 列表选中项文本
  • 表格选中行文本
  • 菜单选中项文本

示例

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::HighlightedText, Qt::white);
qApp->setPalette(palette);

// 在QSS中使用
qApp->setStyleSheet("QListView::item:selected { color: palette(highlighted-text); }");

注意事项

  • HighlightedText颜色应该与Highlight颜色有足够的对比度
  • 通常使用白色或浅色
其他颜色角色

Light、Dark、Mid

用于3D效果的阴影和高光:

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Light, QColor(255, 255, 255));
palette.setColor(QPalette::Dark, QColor(128, 128, 128));
palette.setColor(QPalette::Mid, QColor(192, 192, 192));

BrightText

用于在暗色背景上显示的亮文本:

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::BrightText, Qt::yellow);

Link、LinkVisited

用于链接文本:

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Link, Qt::blue);
palette.setColor(QPalette::LinkVisited, Qt::magenta);

ToolTipBase、ToolTipText

用于工具提示:

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::ToolTipBase, Qt::yellow);
palette.setColor(QPalette::ToolTipText, Qt::black);

PlaceholderText

用于占位符文本(Qt 5.12+):

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::PlaceholderText, QColor(128, 128, 128));

Shadow

用于阴影效果:

cpp 复制代码
QPalette palette;
palette.setColor(QPalette::Shadow, QColor(64, 64, 64));

完整示例

cpp 复制代码
// 创建完整的调色板
QPalette palette;

// 窗口相关
palette.setColor(QPalette::Window, Qt::white);
palette.setColor(QPalette::WindowText, Qt::black);

// 输入控件相关
palette.setColor(QPalette::Base, Qt::white);
palette.setColor(QPalette::AlternateBase, QColor(240, 240, 240));
palette.setColor(QPalette::Text, Qt::black);

// 按钮相关
palette.setColor(QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::ButtonText, Qt::black);

// 高亮相关
palette.setColor(QPalette::Highlight, Qt::blue);
palette.setColor(QPalette::HighlightedText, Qt::white);

// 链接相关
palette.setColor(QPalette::Link, Qt::blue);
palette.setColor(QPalette::LinkVisited, Qt::magenta);

// 工具提示相关
palette.setColor(QPalette::ToolTipBase, Qt::yellow);
palette.setColor(QPalette::ToolTipText, Qt::black);

// 应用调色板
qApp->setPalette(palette);

4.3 颜色组(Color Groups)

颜色组定义了颜色的状态。Qt定义了三个颜色组,用于在不同状态下显示不同的颜色。

Active - 活动状态

作用:窗口有焦点时的颜色。

使用场景

  • 活动窗口的控件
  • 有焦点的控件

示例

cpp 复制代码
QPalette palette;
// 设置活动状态的颜色
palette.setColor(QPalette::Active, QPalette::Window, Qt::white);
palette.setColor(QPalette::Active, QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Active, QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::black);
qApp->setPalette(palette);

特点

  • 活动状态的颜色通常最鲜明
  • 用于表示控件处于活动状态
Inactive - 非活动状态

作用:窗口无焦点时的颜色。

使用场景

  • 非活动窗口的控件
  • 无焦点的控件

示例

cpp 复制代码
QPalette palette;
// 设置非活动状态的颜色
palette.setColor(QPalette::Inactive, QPalette::Window, QColor(245, 245, 245));
palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor(128, 128, 128));
palette.setColor(QPalette::Inactive, QPalette::Button, QColor(245, 245, 245));
palette.setColor(QPalette::Inactive, QPalette::ButtonText, QColor(128, 128, 128));
qApp->setPalette(palette);

特点

  • 非活动状态的颜色通常较淡
  • 用于表示控件处于非活动状态
Disabled - 禁用状态

作用:控件被禁用时的颜色。

使用场景

  • 禁用状态的控件
  • 不可交互的控件

示例

cpp 复制代码
QPalette palette;
// 设置禁用状态的颜色
palette.setColor(QPalette::Disabled, QPalette::Window, QColor(240, 240, 240));
palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(192, 192, 192));
palette.setColor(QPalette::Disabled, QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(192, 192, 192));
qApp->setPalette(palette);

特点

  • 禁用状态的颜色通常较淡,对比度较低
  • 用于表示控件不可用
颜色组的切换机制

自动切换

Qt会根据控件和窗口的状态自动切换颜色组:

  1. 窗口焦点变化:当窗口获得或失去焦点时,自动切换Active和Inactive组
  2. 控件启用/禁用:当控件被启用或禁用时,自动切换Enabled和Disabled组

手动切换

cpp 复制代码
// 获取当前颜色组
QPalette::ColorGroup currentGroup = widget->palette().currentColorGroup();

// 设置特定颜色组的颜色
QPalette palette = widget->palette();
palette.setColor(QPalette::Active, QPalette::Button, Qt::blue);
palette.setColor(QPalette::Inactive, QPalette::Button, QColor(200, 200, 255));
palette.setColor(QPalette::Disabled, QPalette::Button, QColor(240, 240, 240));
widget->setPalette(palette);

颜色组优先级

当控件需要获取颜色时,Qt按以下优先级选择颜色组:

  1. Disabled组:如果控件被禁用,使用Disabled组
  2. Active/Inactive组:根据窗口焦点状态选择Active或Inactive组

完整示例

cpp 复制代码
// 创建完整的调色板(包含所有颜色组)
QPalette palette;

// 活动状态
palette.setColor(QPalette::Active, QPalette::Window, Qt::white);
palette.setColor(QPalette::Active, QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Active, QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::black);

// 非活动状态
palette.setColor(QPalette::Inactive, QPalette::Window, QColor(245, 245, 245));
palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor(128, 128, 128));
palette.setColor(QPalette::Inactive, QPalette::Button, QColor(245, 245, 245));
palette.setColor(QPalette::Inactive, QPalette::ButtonText, QColor(128, 128, 128));

// 禁用状态
palette.setColor(QPalette::Disabled, QPalette::Window, QColor(240, 240, 240));
palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(192, 192, 192));
palette.setColor(QPalette::Disabled, QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(192, 192, 192));

qApp->setPalette(palette);

4.4 调色板的使用

获取和设置调色板

获取调色板

cpp 复制代码
// 获取应用级调色板
QPalette appPalette = qApp->palette();

// 获取控件调色板
QPalette widgetPalette = widget->palette();

设置调色板

cpp 复制代码
// 设置应用级调色板
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);
qApp->setPalette(palette);

// 设置控件调色板
QPalette palette;
palette.setColor(QPalette::Button, Qt::blue);
widget->setPalette(palette);

复制调色板

cpp 复制代码
// 复制调色板
QPalette newPalette = widget->palette();
newPalette.setColor(QPalette::Button, Qt::red);
widget->setPalette(newPalette);
修改特定颜色角色

修改单个颜色角色

cpp 复制代码
// 获取调色板
QPalette palette = widget->palette();

// 修改特定颜色角色
palette.setColor(QPalette::Button, Qt::blue);
palette.setColor(QPalette::ButtonText, Qt::white);

// 应用调色板
widget->setPalette(palette);

修改特定颜色组的颜色角色

cpp 复制代码
// 获取调色板
QPalette palette = widget->palette();

// 修改活动状态的按钮颜色
palette.setColor(QPalette::Active, QPalette::Button, Qt::blue);

// 修改禁用状态的按钮颜色
palette.setColor(QPalette::Disabled, QPalette::Button, QColor(240, 240, 240));

// 应用调色板
widget->setPalette(palette);

批量修改颜色角色

cpp 复制代码
// 创建调色板
QPalette palette;

// 批量设置颜色
palette.setColor(QPalette::Window, Qt::white);
palette.setColor(QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Base, Qt::white);
palette.setColor(QPalette::Text, Qt::black);
palette.setColor(QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::ButtonText, Qt::black);
palette.setColor(QPalette::Highlight, Qt::blue);
palette.setColor(QPalette::HighlightedText, Qt::white);

// 应用调色板
qApp->setPalette(palette);
调色板的全局设置

应用级调色板

通过QApplication::setPalette()设置应用级调色板,影响所有控件:

cpp 复制代码
// 创建调色板
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);
palette.setColor(QPalette::WindowText, Qt::black);
palette.setColor(QPalette::Button, QColor(240, 240, 240));
palette.setColor(QPalette::ButtonText, Qt::black);

// 设置应用级调色板
qApp->setPalette(palette);

// 所有控件都会使用这个调色板
QPushButton *btn1 = new QPushButton("按钮1");
QPushButton *btn2 = new QPushButton("按钮2");
QLabel *label = new QLabel("标签");

全局调色板的特点

  1. 影响范围:影响应用程序中的所有控件
  2. 继承机制:子控件会继承父控件的调色板,如果没有父控件,使用应用级调色板
  3. 优先级:控件自身的调色板优先级最高
调色板的局部设置

控件级调色板

通过QWidget::setPalette()设置控件级调色板,只影响该控件及其子控件:

cpp 复制代码
// 应用级调色板
QPalette appPalette;
appPalette.setColor(QPalette::Button, Qt::blue);
qApp->setPalette(appPalette);

// 局部调色板(只影响sidebar及其子控件)
QWidget *sidebar = new QWidget();
QPalette sidebarPalette;
sidebarPalette.setColor(QPalette::Button, Qt::green);
sidebar->setPalette(sidebarPalette);

// 主窗口使用应用级调色板(蓝色按钮)
QPushButton *mainBtn = new QPushButton("主窗口按钮");

// 侧边栏使用局部调色板(绿色按钮)
QPushButton *sidebarBtn = new QPushButton("侧边栏按钮", sidebar);

局部调色板的特点

  1. 影响范围:只影响该控件及其子控件
  2. 优先级:局部调色板优先级高于应用级调色板
  3. 继承机制:子控件会继承父控件的局部调色板

实际应用

cpp 复制代码
// 全局主题
QPalette globalPalette;
globalPalette.setColor(QPalette::Window, Qt::white);
globalPalette.setColor(QPalette::WindowText, Qt::black);
qApp->setPalette(globalPalette);

// 侧边栏局部主题
QWidget *sidebar = new QWidget();
QPalette sidebarPalette;
sidebarPalette.setColor(QPalette::Window, QColor(50, 50, 50));
sidebarPalette.setColor(QPalette::WindowText, Qt::white);
sidebar->setPalette(sidebarPalette);

// 主内容区使用全局主题(白色背景)
QWidget *mainContent = new QWidget();

// 侧边栏使用局部主题(深色背景)
QWidget *sidebarContent = new QWidget(sidebar);

4.5 调色板与主题

亮色主题

亮色主题的特点

  • 背景颜色较亮(白色或浅灰色)
  • 文本颜色较深(黑色或深灰色)
  • 高对比度,适合阅读

创建亮色主题

cpp 复制代码
QPalette lightPalette;

// 窗口相关
lightPalette.setColor(QPalette::Window, Qt::white);
lightPalette.setColor(QPalette::WindowText, Qt::black);

// 输入控件相关
lightPalette.setColor(QPalette::Base, Qt::white);
lightPalette.setColor(QPalette::AlternateBase, QColor(240, 240, 240));
lightPalette.setColor(QPalette::Text, Qt::black);

// 按钮相关
lightPalette.setColor(QPalette::Button, QColor(240, 240, 240));
lightPalette.setColor(QPalette::ButtonText, Qt::black);

// 高亮相关
lightPalette.setColor(QPalette::Highlight, QColor(0, 120, 215));
lightPalette.setColor(QPalette::HighlightedText, Qt::white);

// 链接相关
lightPalette.setColor(QPalette::Link, QColor(0, 102, 204));
lightPalette.setColor(QPalette::LinkVisited, QColor(128, 0, 128));

// 工具提示相关
lightPalette.setColor(QPalette::ToolTipBase, Qt::yellow);
lightPalette.setColor(QPalette::ToolTipText, Qt::black);

qApp->setPalette(lightPalette);
暗色主题

暗色主题的特点

  • 背景颜色较暗(深灰色或黑色)
  • 文本颜色较亮(白色或浅灰色)
  • 低对比度,适合长时间使用

创建暗色主题

cpp 复制代码
QPalette darkPalette;

// 窗口相关
darkPalette.setColor(QPalette::Window, QColor(45, 45, 45));
darkPalette.setColor(QPalette::WindowText, Qt::white);

// 输入控件相关
darkPalette.setColor(QPalette::Base, QColor(35, 35, 35));
darkPalette.setColor(QPalette::AlternateBase, QColor(50, 50, 50));
darkPalette.setColor(QPalette::Text, Qt::white);

// 按钮相关
darkPalette.setColor(QPalette::Button, QColor(60, 60, 60));
darkPalette.setColor(QPalette::ButtonText, Qt::white);

// 高亮相关
darkPalette.setColor(QPalette::Highlight, QColor(0, 120, 215));
darkPalette.setColor(QPalette::HighlightedText, Qt::white);

// 链接相关
darkPalette.setColor(QPalette::Link, QColor(100, 150, 255));
darkPalette.setColor(QPalette::LinkVisited, QColor(200, 100, 255));

// 工具提示相关
darkPalette.setColor(QPalette::ToolTipBase, QColor(60, 60, 60));
darkPalette.setColor(QPalette::ToolTipText, Qt::white);

qApp->setPalette(darkPalette);
主题切换的实现

主题管理器类

cpp 复制代码
class ThemeManager {
public:
    enum Theme {
        Light,
        Dark
    };
    
    static void setTheme(Theme theme) {
        QPalette palette;
        
        if (theme == Dark) {
            // 暗色主题
            palette.setColor(QPalette::Window, QColor(45, 45, 45));
            palette.setColor(QPalette::WindowText, Qt::white);
            palette.setColor(QPalette::Base, QColor(35, 35, 35));
            palette.setColor(QPalette::AlternateBase, QColor(50, 50, 50));
            palette.setColor(QPalette::Text, Qt::white);
            palette.setColor(QPalette::Button, QColor(60, 60, 60));
            palette.setColor(QPalette::ButtonText, Qt::white);
            palette.setColor(QPalette::Highlight, QColor(0, 120, 215));
            palette.setColor(QPalette::HighlightedText, Qt::white);
        } else {
            // 亮色主题
            palette.setColor(QPalette::Window, Qt::white);
            palette.setColor(QPalette::WindowText, Qt::black);
            palette.setColor(QPalette::Base, Qt::white);
            palette.setColor(QPalette::AlternateBase, QColor(240, 240, 240));
            palette.setColor(QPalette::Text, Qt::black);
            palette.setColor(QPalette::Button, QColor(240, 240, 240));
            palette.setColor(QPalette::ButtonText, Qt::black);
            palette.setColor(QPalette::Highlight, QColor(0, 120, 215));
            palette.setColor(QPalette::HighlightedText, Qt::white);
        }
        
        qApp->setPalette(palette);
    }
};

// 使用
ThemeManager::setTheme(ThemeManager::Dark);

结合QSS的主题切换

cpp 复制代码
void MainWindow::switchTheme(bool dark) {
    QPalette palette;
    QString styleSheet;
    
    if (dark) {
        // 暗色主题调色板
        palette.setColor(QPalette::Window, QColor(45, 45, 45));
        palette.setColor(QPalette::WindowText, Qt::white);
        palette.setColor(QPalette::Button, QColor(60, 60, 60));
        palette.setColor(QPalette::ButtonText, Qt::white);
        
        // 暗色主题QSS
        styleSheet = R"(
            QWidget {
                background-color: palette(window);
                color: palette(window-text);
            }
            QPushButton {
                background-color: palette(button);
                color: palette(button-text);
                border: 1px solid #555;
                padding: 5px;
            }
            QPushButton:hover {
                background-color: #666;
            }
        )";
    } else {
        // 亮色主题调色板
        palette.setColor(QPalette::Window, Qt::white);
        palette.setColor(QPalette::WindowText, Qt::black);
        palette.setColor(QPalette::Button, QColor(240, 240, 240));
        palette.setColor(QPalette::ButtonText, Qt::black);
        
        // 亮色主题QSS
        styleSheet = R"(
            QWidget {
                background-color: palette(window);
                color: palette(window-text);
            }
            QPushButton {
                background-color: palette(button);
                color: palette(button-text);
                border: 1px solid #ccc;
                padding: 5px;
            }
            QPushButton:hover {
                background-color: #e0e0e0;
            }
        )";
    }
    
    qApp->setPalette(palette);
    qApp->setStyleSheet(styleSheet);
}
系统主题的适配

检测系统主题

cpp 复制代码
// Windows系统
#ifdef Q_OS_WIN
    QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
                       QSettings::NativeFormat);
    bool isDark = settings.value("AppsUseLightTheme", 1).toInt() == 0;
    if (isDark) {
        ThemeManager::setTheme(ThemeManager::Dark);
    } else {
        ThemeManager::setTheme(ThemeManager::Light);
    }
#endif

// macOS系统
#ifdef Q_OS_MAC
    // macOS 10.14+
    if (@available(macOS 10.14, *)) {
        NSAppearance *appearance = [NSAppearance currentAppearance];
        NSString *name = [appearance name];
        if ([name containsString:@"Dark"]) {
            ThemeManager::setTheme(ThemeManager::Dark);
        } else {
            ThemeManager::setTheme(ThemeManager::Light);
        }
    }
#endif

监听系统主题变化

cpp 复制代码
// Windows系统
#ifdef Q_OS_WIN
    // 监听注册表变化
    QWinEventNotifier *notifier = new QWinEventNotifier(this);
    connect(notifier, &QWinEventNotifier::activated, [this]() {
        // 检测系统主题并切换
        // ...
    });
#endif

// macOS系统
#ifdef Q_OS_MAC
    // 监听NSAppearance变化
    [[NSDistributedNotificationCenter defaultCenter]
        addObserverForName:@"AppleInterfaceThemeChangedNotification"
        object:nil
        queue:nil
        usingBlock:^(NSNotification *note) {
            // 检测系统主题并切换
            // ...
        }];
#endif

自动跟随系统主题

cpp 复制代码
class SystemThemeWatcher : public QObject {
    Q_OBJECT
public:
    SystemThemeWatcher(QObject *parent = nullptr) : QObject(parent) {
        // 初始化时检测系统主题
        detectSystemTheme();
        
        // 设置定时器定期检测(作为备选方案)
        QTimer *timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &SystemThemeWatcher::detectSystemTheme);
        timer->start(1000);  // 每秒检测一次
    }
    
private slots:
    void detectSystemTheme() {
        // 检测系统主题并切换
        // ...
    }
};


5. QStyleOption样式配置

5.1 QStyleOption基础

QStyleOption是Qt样式系统中用于传递样式信息的核心类。理解QStyleOption对于自定义样式和控件绘制至关重要。

QStyleOption的作用

QStyleOption是什么?

QStyleOption是一个数据结构,用于在控件和QStyle之间传递绘制所需的信息。它包含了绘制控件所需的所有参数,如位置、大小、状态、文本、图标等。

QStyleOption的核心作用

  1. 信息传递:将控件的状态和信息传递给QStyle
  2. 解耦合:将控件和样式引擎解耦,样式引擎不需要直接访问控件
  3. 性能优化:避免样式引擎频繁访问控件属性
  4. 线程安全:样式选项是值类型,可以安全地在不同线程间传递

为什么需要QStyleOption?

在Qt的早期版本中,QStyle的方法直接接受QWidget指针,这导致:

  • 样式引擎需要访问控件的所有属性
  • 控件和样式引擎紧密耦合
  • 难以实现线程安全的绘制

QStyleOption解决了这些问题:

  • 控件将信息打包到QStyleOption中
  • 样式引擎只使用QStyleOption中的信息
  • 实现了控件和样式引擎的解耦

QStyleOption的基本结构

cpp 复制代码
class QStyleOption {
public:
    enum StyleOptionType {
        SO_Default,
        SO_Button,
        SO_ComboBox,
        SO_Complex,
        // ... 更多类型
    };
    
    enum StyleOptionVersion {
        Version = 1
    };
    
    StyleOptionType type;      // 选项类型
    int version;                // 版本号
    QRect rect;                 // 绘制区域
    QPalette palette;           // 调色板
    QFont font;                 // 字体
    State state;                // 状态
    Direction direction;        // 方向(LTR/RTL)
    // ... 更多属性
};
QStyleOption的继承体系

继承层次结构

复制代码
QStyleOption (基类)
├── QStyleOptionButton (按钮)
├── QStyleOptionComboBox (组合框)
├── QStyleOptionComplex (复杂控件基类)
│   ├── QStyleOptionComboBox
│   ├── QStyleOptionSlider (滑块)
│   ├── QStyleOptionSpinBox (数字输入框)
│   ├── QStyleOptionProgressBar (进度条)
│   ├── QStyleOptionTab (标签页)
│   ├── QStyleOptionTabBarBase (标签栏)
│   ├── QStyleOptionTitleBar (标题栏)
│   ├── QStyleOptionGroupBox (分组框)
│   ├── QStyleOptionToolButton (工具按钮)
│   └── QStyleOptionHeader (表头)
├── QStyleOptionFocusRect (焦点矩形)
├── QStyleOptionFrame (框架)
├── QStyleOptionGraphicsItem (图形项)
├── QStyleOptionMenuItem (菜单项)
├── QStyleOptionRubberBand (橡皮筋)
├── QStyleOptionSizeGrip (大小调整手柄)
├── QStyleOptionTab (标签页)
├── QStyleOptionTabWidgetFrame (标签页控件框架)
├── QStyleOptionTitleBar (标题栏)
├── QStyleOptionToolBar (工具栏)
├── QStyleOptionToolBox (工具箱)
└── QStyleOptionViewItem (列表项)

QStyleOption(基类)

所有样式选项的基类,包含通用属性:

cpp 复制代码
class QStyleOption {
public:
    QRect rect;              // 绘制区域
    QPalette palette;        // 调色板
    QFont font;              // 字体
    State state;             // 状态
    Direction direction;     // 方向
    // ...
};

QStyleOptionComplex(复杂控件基类)

用于复杂控件的样式选项基类:

cpp 复制代码
class QStyleOptionComplex : public QStyleOption {
public:
    QStyle::SubControls subControls;  // 子控件
    QStyle::ComplexControlFeatures activeSubControls; // 活动子控件
    // ...
};
QStyleOption的工作原理

工作流程

复制代码
控件需要绘制
    ↓
控件创建QStyleOption对象
    ↓
填充QStyleOption的属性(位置、大小、状态等)
    ↓
调用QStyle::drawControl()或drawComplexControl()
    ↓
QStyle使用QStyleOption中的信息绘制控件
    ↓
完成绘制

示例流程

cpp 复制代码
// 控件绘制流程(简化)
void QPushButton::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QStyleOptionButton option;
    
    // 初始化样式选项
    initStyleOption(&option);
    
    // 调用样式引擎绘制
    style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
}

// 初始化样式选项
void QPushButton::initStyleOption(QStyleOptionButton *option) const {
    option->initFrom(this);  // 从控件初始化基本属性
    option->features = QStyleOptionButton::None;
    option->text = text();
    option->icon = icon();
    option->iconSize = iconSize();
    // ... 设置其他属性
}

QStyleOption的特点

  1. 值类型:QStyleOption是值类型,可以安全地复制和传递
  2. 版本控制:每个QStyleOption子类都有版本号,用于兼容性检查
  3. 类型安全:使用类型枚举确保类型安全
  4. 线程安全:值类型,可以在不同线程间安全传递
何时需要使用QStyleOption

1. 自定义控件绘制

当自定义控件需要绘制时,必须创建QStyleOption:

cpp 复制代码
class CustomButton : public QPushButton {
protected:
    void paintEvent(QPaintEvent *event) override {
        QStylePainter painter(this);
        QStyleOptionButton option;
        initStyleOption(&option);
        
        // 自定义绘制逻辑
        style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
    }
};

2. 自定义样式

当创建自定义样式时,需要处理QStyleOption:

cpp 复制代码
class CustomStyle : public QProxyStyle {
public:
    void drawControl(ControlElement element,
                     const QStyleOption *opt,
                     QPainter *p,
                     const QWidget *w) const override {
        if (element == CE_PushButton) {
            const QStyleOptionButton *btnOpt = 
                qstyleoption_cast<const QStyleOptionButton *>(opt);
            if (btnOpt) {
                // 使用btnOpt中的信息绘制按钮
                // ...
            }
        } else {
            QProxyStyle::drawControl(element, opt, p, w);
        }
    }
};

3. 绘制到其他设备

当需要将控件绘制到其他设备(如打印机、图片)时:

cpp 复制代码
void printWidget(QWidget *widget, QPrinter *printer) {
    QPainter painter(printer);
    QStyleOption opt;
    opt.initFrom(widget);
    opt.rect = widget->rect();
    
    // 使用样式选项绘制到打印机
    widget->style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, widget);
}

4. 预览控件

在控件设计器中预览控件时:

cpp 复制代码
void previewWidget(QWidget *widget) {
    QPixmap pixmap(widget->size());
    QPainter painter(&pixmap);
    
    QStyleOption opt;
    opt.initFrom(widget);
    opt.rect = widget->rect();
    
    widget->style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, widget);
}

最佳实践

  1. 总是使用initFrom() :使用initFrom()初始化基本属性
  2. 类型转换 :使用qstyleoption_cast<>()进行安全的类型转换
  3. 检查版本:检查QStyleOption的版本号以确保兼容性
  4. 不要直接访问控件:在样式引擎中,只使用QStyleOption中的信息

5.2 常用QStyleOption类

QStyleOptionButton - 按钮样式选项

作用:用于传递按钮控件的样式信息。

主要属性

cpp 复制代码
class QStyleOptionButton : public QStyleOption {
public:
    enum ButtonFeature {
        None = 0x00,
        Flat = 0x01,           // 扁平按钮
        HasMenu = 0x02,        // 有菜单
        DefaultButton = 0x04,  // 默认按钮
        AutoDefaultButton = 0x08, // 自动默认按钮
        CommandLinkButton = 0x10 // 命令链接按钮
    };
    
    QString text;              // 按钮文本
    QIcon icon;                // 按钮图标
    QSize iconSize;            // 图标大小
    ButtonFeature features;    // 按钮特性
    // ...
};

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_PushButton) {
        const QStyleOptionButton *btnOpt = 
            qstyleoption_cast<const QStyleOptionButton *>(opt);
        if (!btnOpt) return;
        
        // 使用按钮选项中的信息
        QString text = btnOpt->text;
        QIcon icon = btnOpt->icon;
        bool isFlat = btnOpt->features & QStyleOptionButton::Flat;
        bool isDefault = btnOpt->features & QStyleOptionButton::DefaultButton;
        
        // 绘制按钮
        // ...
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}
QStyleOptionComboBox - 组合框样式选项

作用:用于传递组合框控件的样式信息。

主要属性

cpp 复制代码
class QStyleOptionComboBox : public QStyleOptionComplex {
public:
    bool editable;              // 是否可编辑
    QRect frameRect;           // 框架矩形
    QRect currentTextRect;     // 当前文本矩形
    QRect popupRect;           // 弹出框矩形
    QString currentText;       // 当前文本
    QIcon currentIcon;         // 当前图标
    int currentIndex;          // 当前索引
    QSize iconSize;            // 图标大小
    // ...
};

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawComplexControl(ComplexControl cc,
                                     const QStyleOptionComplex *opt,
                                     QPainter *p,
                                     const QWidget *w) const {
    if (cc == CC_ComboBox) {
        const QStyleOptionComboBox *cbOpt = 
            qstyleoption_cast<const QStyleOptionComboBox *>(opt);
        if (!cbOpt) return;
        
        // 使用组合框选项中的信息
        bool editable = cbOpt->editable;
        QString text = cbOpt->currentText;
        QIcon icon = cbOpt->currentIcon;
        
        // 绘制组合框
        // ...
    } else {
        QProxyStyle::drawComplexControl(cc, opt, p, w);
    }
}
QStyleOptionSlider - 滑块样式选项

作用:用于传递滑块控件的样式信息。

主要属性

cpp 复制代码
class QStyleOptionSlider : public QStyleOptionComplex {
public:
    Qt::Orientation orientation; // 方向(水平/垂直)
    int minimum;                 // 最小值
    int maximum;                 // 最大值
    int sliderPosition;          // 滑块位置
    int sliderValue;             // 滑块值
    int tickPosition;            // 刻度位置
    int tickInterval;            // 刻度间隔
    bool upsideDown;             // 是否倒置
    // ...
};

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawComplexControl(ComplexControl cc,
                                     const QStyleOptionComplex *opt,
                                     QPainter *p,
                                     const QWidget *w) const {
    if (cc == CC_Slider) {
        const QStyleOptionSlider *sliderOpt = 
            qstyleoption_cast<const QStyleOptionSlider *>(opt);
        if (!sliderOpt) return;
        
        // 使用滑块选项中的信息
        Qt::Orientation orientation = sliderOpt->orientation;
        int min = sliderOpt->minimum;
        int max = sliderOpt->maximum;
        int value = sliderOpt->sliderValue;
        
        // 绘制滑块
        // ...
    } else {
        QProxyStyle::drawComplexControl(cc, opt, p, w);
    }
}
QStyleOptionProgressBar - 进度条样式选项

作用:用于传递进度条控件的样式信息。

主要属性

cpp 复制代码
class QStyleOptionProgressBar : public QStyleOption {
public:
    Qt::Orientation orientation; // 方向(水平/垂直)
    int minimum;                 // 最小值
    int maximum;                 // 最大值
    int progress;                // 当前进度
    QString text;                // 文本
    bool textVisible;            // 文本是否可见
    int textAlignment;           // 文本对齐
    // ...
};

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_ProgressBar) {
        const QStyleOptionProgressBar *pbOpt = 
            qstyleoption_cast<const QStyleOptionProgressBar *>(opt);
        if (!pbOpt) return;
        
        // 使用进度条选项中的信息
        int min = pbOpt->minimum;
        int max = pbOpt->maximum;
        int progress = pbOpt->progress;
        QString text = pbOpt->text;
        
        // 计算进度百分比
        double percentage = (double)(progress - min) / (max - min) * 100.0;
        
        // 绘制进度条
        // ...
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}
QStyleOptionTab - 标签页样式选项

作用:用于传递标签页控件的样式信息。

主要属性

cpp 复制代码
class QStyleOptionTab : public QStyleOption {
public:
    enum TabPosition {
        Beginning,  // 开始位置
        Middle,     // 中间位置
        End,        // 结束位置
        OnlyOneTab  // 只有一个标签
    };
    
    enum SelectedPosition {
        NotAdjacent,  // 不相邻
        NextIsSelected, // 下一个被选中
        PreviousIsSelected // 上一个被选中
    };
    
    enum CornerWidget {
        NoCornerWidgets = 0x00,
        LeftCornerWidget = 0x01,
        RightCornerWidget = 0x02
    };
    
    TabPosition position;      // 位置
    SelectedPosition selectedPosition; // 选中位置
    CornerWidget cornerWidgets; // 角落控件
    QString text;               // 文本
    QIcon icon;                 // 图标
    QSize iconSize;             // 图标大小
    int row;                    // 行号
    // ...
};

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_TabBarTab) {
        const QStyleOptionTab *tabOpt = 
            qstyleoption_cast<const QStyleOptionTab *>(opt);
        if (!tabOpt) return;
        
        // 使用标签页选项中的信息
        QString text = tabOpt->text;
        QIcon icon = tabOpt->icon;
        bool isSelected = tabOpt->state & QStyle::State_Selected;
        QStyleOptionTab::TabPosition position = tabOpt->position;
        
        // 绘制标签页
        // ...
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}
QStyleOptionMenuItem - 菜单项样式选项

作用:用于传递菜单项控件的样式信息。

主要属性

cpp 复制代码
class QStyleOptionMenuItem : public QStyleOption {
public:
    enum MenuItemType {
        Normal,      // 普通菜单项
        DefaultItem, // 默认菜单项
        Separator,   // 分隔符
        SubMenu,     // 子菜单
        Scroller,    // 滚动器
        TearOff,     // 撕下
        Margin       // 边距
    };
    
    enum CheckType {
        NotCheckable,  // 不可选中
        Exclusive,     // 独占(单选)
        NonExclusive   // 非独占(多选)
    };
    
    MenuItemType menuItemType;  // 菜单项类型
    CheckType checkType;        // 选中类型
    bool checked;               // 是否选中
    QString text;               // 文本
    QIcon icon;                 // 图标
    QString shortcut;           // 快捷键
    int maxIconWidth;           // 最大图标宽度
    int tabWidth;               // 标签宽度
    // ...
};

使用示例

cpp 复制代码
// 在自定义样式中使用
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_MenuItem) {
        const QStyleOptionMenuItem *menuItemOpt = 
            qstyleoption_cast<const QStyleOptionMenuItem *>(opt);
        if (!menuItemOpt) return;
        
        // 使用菜单项选项中的信息
        QString text = menuItemOpt->text;
        QIcon icon = menuItemOpt->icon;
        bool isChecked = menuItemOpt->checked;
        QStyleOptionMenuItem::MenuItemType type = menuItemOpt->menuItemType;
        
        // 绘制菜单项
        if (type == QStyleOptionMenuItem::Separator) {
            // 绘制分隔符
        } else {
            // 绘制普通菜单项
        }
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}

5.3 QStyleOption的使用

初始化QStyleOption

使用initFrom()方法

initFrom()是初始化QStyleOption的最常用方法,它从控件中复制基本属性:

cpp 复制代码
QStyleOptionButton option;
option.initFrom(button);  // 从按钮控件初始化
// 现在option包含了按钮的基本属性:rect、palette、font、state等

initFrom()做了什么

cpp 复制代码
void QStyleOption::initFrom(const QWidget *widget) {
    rect = widget->rect();
    palette = widget->palette();
    font = widget->font();
    state = QStyle::State_None;
    
    if (widget->isEnabled())
        state |= QStyle::State_Enabled;
    if (widget->hasFocus())
        state |= QStyle::State_HasFocus;
    if (widget->window()->isActiveWindow())
        state |= QStyle::State_Active;
    if (widget->underMouse())
        state |= QStyle::State_MouseOver;
    // ... 更多状态
}

手动初始化

cpp 复制代码
QStyleOptionButton option;
option.initFrom(button);

// 手动设置按钮特定属性
option.text = button->text();
option.icon = button->icon();
option.iconSize = button->iconSize();
option.features = QStyleOptionButton::None;
if (button->isFlat())
    option.features |= QStyleOptionButton::Flat;
if (button->isDefault())
    option.features |= QStyleOptionButton::DefaultButton;
设置样式选项参数

设置基本属性

cpp 复制代码
QStyleOptionButton option;
option.initFrom(button);

// 设置文本
option.text = "确定";

// 设置图标
option.icon = QIcon(":/icons/ok.png");
option.iconSize = QSize(16, 16);

// 设置特性
option.features = QStyleOptionButton::None;
if (isFlat) {
    option.features |= QStyleOptionButton::Flat;
}

设置状态

cpp 复制代码
QStyleOptionButton option;
option.initFrom(button);

// 设置状态
if (button->isEnabled()) {
    option.state |= QStyle::State_Enabled;
}
if (button->hasFocus()) {
    option.state |= QStyle::State_HasFocus;
}
if (button->underMouse()) {
    option.state |= QStyle::State_MouseOver;
}
if (button->isDown()) {
    option.state |= QStyle::State_Sunken;
}

设置区域

cpp 复制代码
QStyleOptionButton option;
option.initFrom(button);

// 设置绘制区域
option.rect = QRect(10, 10, 100, 30);

// 或者使用控件的区域
option.rect = button->rect();
传递给QStyle绘制函数

基本用法

cpp 复制代码
void CustomButton::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QStyleOptionButton option;
    initStyleOption(&option);
    
    // 传递给样式引擎
    style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
}

类型转换

在样式引擎中,需要进行类型转换:

cpp 复制代码
void CustomStyle::drawControl(ControlElement element,
                               const QStyleOption *opt,
                               QPainter *p,
                               const QWidget *w) const {
    if (element == CE_PushButton) {
        // 安全的类型转换
        const QStyleOptionButton *btnOpt = 
            qstyleoption_cast<const QStyleOptionButton *>(opt);
        if (!btnOpt) {
            // 类型转换失败,使用基础样式
            QProxyStyle::drawControl(element, opt, p, w);
            return;
        }
        
        // 使用btnOpt绘制按钮
        // ...
    } else {
        QProxyStyle::drawControl(element, opt, p, w);
    }
}

检查版本

cpp 复制代码
const QStyleOptionButton *btnOpt = 
    qstyleoption_cast<const QStyleOptionButton *>(opt);
if (btnOpt && btnOpt->version >= QStyleOptionButton::Version) {
    // 版本兼容,可以使用
    // ...
}
从控件初始化样式选项

使用initStyleOption()方法

Qt控件通常提供initStyleOption()方法来初始化样式选项:

cpp 复制代码
class QPushButton {
public:
    void initStyleOption(QStyleOptionButton *option) const;
};

// 使用
QPushButton *button = new QPushButton("确定");
QStyleOptionButton option;
button->initStyleOption(&option);

自定义控件的initStyleOption()

cpp 复制代码
class CustomButton : public QPushButton {
public:
    void initStyleOption(QStyleOptionButton *option) const {
        // 调用基类方法
        QPushButton::initStyleOption(option);
        
        // 添加自定义属性
        option->features |= QStyleOptionButton::Flat;
        // ... 其他自定义设置
    }
};

完整示例

cpp 复制代码
class CustomButton : public QPushButton {
protected:
    void paintEvent(QPaintEvent *event) override {
        QStylePainter painter(this);
        QStyleOptionButton option;
        
        // 初始化样式选项
        initStyleOption(&option);
        
        // 自定义修改
        if (m_customState) {
            option.state |= QStyle::State_MouseOver;
        }
        
        // 绘制
        style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
    }
    
private:
    bool m_customState = false;
};

5.4 QStyleOption高级应用

自定义样式选项

创建自定义样式选项

cpp 复制代码
class QStyleOptionCustomButton : public QStyleOptionButton {
public:
    enum StyleOptionType {
        Type = SO_Button + 1
    };
    
    enum StyleOptionVersion {
        Version = 1
    };
    
    QStyleOptionCustomButton() : QStyleOptionButton(Version, Type) {}
    
    // 自定义属性
    QColor customColor;
    int customRadius;
    // ...
};

使用自定义样式选项

cpp 复制代码
class CustomButton : public QPushButton {
protected:
    void paintEvent(QPaintEvent *event) override {
        QStylePainter painter(this);
        QStyleOptionCustomButton option;
        
        // 初始化基本属性
        option.initFrom(this);
        option.text = text();
        option.icon = icon();
        
        // 设置自定义属性
        option.customColor = QColor(76, 175, 80);
        option.customRadius = 5;
        
        // 传递给自定义样式
        style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
    }
};

在自定义样式中处理

cpp 复制代码
class CustomStyle : public QProxyStyle {
public:
    void drawControl(ControlElement element,
                     const QStyleOption *opt,
                     QPainter *p,
                     const QWidget *w) const override {
        if (element == CE_PushButton) {
            // 尝试转换为自定义选项
            const QStyleOptionCustomButton *customOpt = 
                qstyleoption_cast<const QStyleOptionCustomButton *>(opt);
            
            if (customOpt) {
                // 使用自定义选项
                QColor color = customOpt->customColor;
                int radius = customOpt->customRadius;
                // 绘制自定义按钮
                // ...
                return;
            }
            
            // 使用标准选项
            const QStyleOptionButton *btnOpt = 
                qstyleoption_cast<const QStyleOptionButton *>(opt);
            if (btnOpt) {
                // 绘制标准按钮
                // ...
            }
        } else {
            QProxyStyle::drawControl(element, opt, p, w);
        }
    }
};
样式选项的扩展

使用QStyleOption的子类

cpp 复制代码
// 扩展QStyleOptionButton
class ExtendedButtonOption : public QStyleOptionButton {
public:
    // 扩展属性
    QLinearGradient gradient;
    QPixmap backgroundPixmap;
    QString tooltip;
    // ...
};

在控件中使用扩展选项

cpp 复制代码
class ExtendedButton : public QPushButton {
protected:
    void paintEvent(QPaintEvent *event) override {
        QStylePainter painter(this);
        ExtendedButtonOption option;
        
        // 初始化基本属性
        option.initFrom(this);
        option.text = text();
        
        // 设置扩展属性
        option.gradient = createGradient();
        option.backgroundPixmap = m_backgroundPixmap;
        option.tooltip = toolTip();
        
        // 注意:需要自定义样式支持
        // 或者使用属性系统
        setProperty("extendedOption", QVariant::fromValue(option));
        
        // 绘制
        style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
    }
};
样式选项的优化

缓存样式选项

对于频繁绘制的控件,可以缓存样式选项:

cpp 复制代码
class CachedButton : public QPushButton {
private:
    mutable QStyleOptionButton m_cachedOption;
    mutable bool m_optionDirty = true;
    
    void updateCachedOption() const {
        if (m_optionDirty) {
            initStyleOption(&m_cachedOption);
            m_optionDirty = false;
        }
    }
    
protected:
    void paintEvent(QPaintEvent *event) override {
        updateCachedOption();
        
        QStylePainter painter(this);
        style()->drawControl(QStyle::CE_PushButton, &m_cachedOption, &painter, this);
    }
    
    void changeEvent(QEvent *event) override {
        if (event->type() == QEvent::EnabledChange ||
            event->type() == QEvent::FontChange ||
            event->type() == QEvent::PaletteChange) {
            m_optionDirty = true;
        }
        QPushButton::changeEvent(event);
    }
};

减少样式选项创建

cpp 复制代码
// ❌ 每次绘制都创建新选项(性能差)
void paintEvent(QPaintEvent *event) {
    QStyleOptionButton option;
    initStyleOption(&option);
    // ...
}

// ✅ 复用样式选项(性能好)
class CustomButton : public QPushButton {
private:
    QStyleOptionButton m_option;
    
protected:
    void paintEvent(QPaintEvent *event) override {
        initStyleOption(&m_option);
        // ...
    }
};

最佳实践

  1. 总是使用initFrom():确保基本属性正确初始化
  2. 类型安全 :使用qstyleoption_cast<>()进行类型转换
  3. 版本检查:检查版本号以确保兼容性
  4. 避免直接访问控件:在样式引擎中只使用QStyleOption
  5. 缓存优化:对于频繁绘制的控件,考虑缓存样式选项


6. 自定义样式的实现

相关推荐
深蓝海拓18 小时前
PySide6从0开始学习的笔记(二十三)使用QRunnable在线程池中执行临时任务
笔记·python·qt·学习·pyqt
嘿嘿潶黑黑19 小时前
关于QButtonGroup 在Qt5和Qt6之间的差异
开发语言·qt
hqwest19 小时前
码上通QT实战09--监控页面01-区域划分
开发语言·qt·layout·qss·qt 布局
mingren_131419 小时前
c++和qml交互
c++·qt·交互
cn_mengbei19 小时前
鸿蒙PC原生应用开发避坑指南:Qt 6.6与Electron 28兼容性问题全解析
qt·electron·harmonyos
cn_mengbei19 小时前
鸿蒙PC上Qt原生应用开发:从零搭建开发环境到部署实战,附HarmonyOS SDK配置与避坑指南(C++实现)
c++·qt·harmonyos
cn_mengbei19 小时前
鸿蒙PC跨端开发实战:从Qt环境配置到Electron应用鸿蒙化的完整指南
qt·electron·harmonyos
六点的晨曦20 小时前
Qt常用的开发架构模式与UI组件
qt·ui·架构
开开心心就好20 小时前
音频格式互转工具,支持Mp3ApeWavFlac互转
java·网络·c++·windows·qt·电脑·excel