Qt 样式表(QSS):打造个性化界面

一、Qt 样式表概述

Qt 样式表(Qt Style Sheets, QSS)是一种强大的机制,允许开发者使用类似 CSS 的语法来定制 Qt 应用程序的外观。QSS 提供了比传统编程方式更灵活、更高效的界面美化方案,使应用程序能够拥有独特的视觉风格。

1.1 基本语法

QSS 的基本语法与 CSS 类似:

css 复制代码
selector { property: value; }
  • 选择器(Selector):指定哪些控件将受到样式影响
  • 属性(Property):指定要设置的样式属性
  • 值(Value):指定属性的具体值

1.2 应用方式

可以通过以下方式应用样式表:

  • 全局应用 :对整个应用程序生效

    cpp 复制代码
    qApp->setStyleSheet("QPushButton { color: red; }");
  • 局部应用 :对特定窗口或控件生效

    cpp 复制代码
    widget->setStyleSheet("background-color: yellow;");
  • 外部文件 :从文件加载样式表

    cpp 复制代码
    QFile file(":/styles/mystyle.qss");
    file.open(QFile::ReadOnly);
    qApp->setStyleSheet(file.readAll());

二、选择器类型

2.1 通配选择器

匹配所有控件:

css 复制代码
* { color: blue; }

2.2 类型选择器

匹配特定类型的控件:

css 复制代码
QPushButton { background-color: gray; }
QLabel { font-size: 14px; }

2.3 类选择器

匹配具有特定类名的控件:

css 复制代码
.QFrame { border: 1px solid black; }

2.4 ID 选择器

匹配具有特定对象名称的控件:

css 复制代码
#myButton { font-weight: bold; }

2.5 属性选择器

匹配具有特定属性的控件:

css 复制代码
QPushButton[flat="true"] { background: transparent; }

2.6 后代选择器

匹配作为另一个控件后代的控件:

css 复制代码
QDialog QLabel { color: green; }

2.7 子选择器

匹配作为另一个控件直接子控件的控件:

css 复制代码
QListWidget > QAbstractItemView { outline: none; }

三、常用样式属性

3.1 背景属性

css 复制代码
background-color: red;        /* 背景颜色 */
background-image: url(img.png); /* 背景图片 */
background-repeat: no-repeat;  /* 背景重复方式 */
background-position: center;  /* 背景位置 */

3.2 边框属性

css 复制代码
border: 2px solid blue;       /* 边框宽度、样式和颜色 */
border-radius: 5px;           /* 边框圆角 */
border-top: 1px dashed gray;  /* 上边框 */

3.3 字体属性

css 复制代码
font-family: Arial;           /* 字体族 */
font-size: 12pt;              /* 字体大小 */
font-weight: bold;            /* 字体粗细 */
color: white;                 /* 文字颜色 */

3.4 间距和边距

css 复制代码
margin: 10px;                 /* 外边距 */
padding: 5px;                 /* 内边距 */

3.5 其他常用属性

css 复制代码
min-width: 100px;             /* 最小宽度 */
max-height: 30px;             /* 最大高度 */
opacity: 0.8;                 /* 不透明度 */

四、状态选择器

QSS 支持基于控件状态的样式定义:

css 复制代码
QPushButton { background-color: gray; }
QPushButton:hover { background-color: blue; }    /* 鼠标悬停 */
QPushButton:pressed { background-color: red; }  /* 鼠标按下 */
QPushButton:checked { background-color: green; } /* 选中状态 */
QPushButton:disabled { background-color: lightgray; } /* 禁用状态 */

五、盒模型

QSS 使用与 CSS 类似的盒模型,包括内容区、内边距、边框和外边距:

css 复制代码
QWidget {
    margin: 10px;      /* 外边距 */
    padding: 5px;      /* 内边距 */
    border: 2px solid; /* 边框 */
    width: 200px;      /* 宽度 */
    height: 100px;     /* 高度 */
}

六、自定义控件样式

6.1 自定义按钮

css 复制代码
QPushButton {
    background-color: #4CAF50;
    border: none;
    color: white;
    padding: 8px 16px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 14px;
    margin: 4px 2px;
    cursor: pointer;
    border-radius: 4px;
}

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

QPushButton:pressed {
    background-color: #3d8b40;
}

6.2 自定义滚动条

css 复制代码
QScrollBar:vertical {
    border: 1px solid #999999;
    background: white;
    width: 15px;
    margin: 22px 0 22px 0;
}

QScrollBar::handle:vertical {
    background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #bbbbbb, stop:1 #aaaaaa);
    min-height: 20px;
    border-radius: 3px;
}

QScrollBar::add-line:vertical {
    border: 1px solid #999999;
    background: #cccccc;
    height: 20px;
    subcontrol-position: bottom;
    subcontrol-origin: margin;
}

QScrollBar::sub-line:vertical {
    border: 1px solid #999999;
    background: #cccccc;
    height: 20px;
    subcontrol-position: top;
    subcontrol-origin: margin;
}

6.3 自定义进度条

css 复制代码
QProgressBar {
    border: 2px solid grey;
    border-radius: 5px;
    text-align: center;
}

QProgressBar::chunk {
    background-color: #05B8CC;
    width: 10px;
    margin: 0.5px;
}

七、高级技巧

7.1 使用渐变

css 复制代码
QPushButton {
    background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #FFFFFF, stop:1 #AAAAAA);
}

7.2 使用图像

css 复制代码
QWidget {
    background-image: url(:/images/background.png);
    background-repeat: repeat;
}

7.3 嵌套样式

css 复制代码
QGroupBox {
    border: 1px solid gray;
    border-radius: 5px;
    margin-top: 1ex; /* leave space at the top for the title */
}

QGroupBox::title {
    subcontrol-origin: margin;
    subcontrol-position: top center; /* position at the top center */
    padding: 0 3px;
    background-color: transparent;
}

7.4 自定义图标

css 复制代码
QPushButton#closeButton {
    qproperty-icon: url(:/icons/close.png);
    background: transparent;
    border: none;
}

八、调试样式表

8.1 使用调试输出

cpp 复制代码
qDebug() << "Style sheet:" << widget->styleSheet();

8.2 分步应用样式

逐步添加样式规则,确定问题所在。

8.3 使用样式表调试工具

可以开发简单的工具来实时预览样式表效果:

cpp 复制代码
class StyleSheetEditor : public QWidget
{
    Q_OBJECT
    
public:
    StyleSheetEditor(QWidget *parent = nullptr) : QWidget(parent)
    {
        QVBoxLayout *layout = new QVBoxLayout(this);
        
        // 创建文本编辑器
        editor = new QTextEdit(this);
        layout->addWidget(editor);
        
        // 创建预览按钮
        previewButton = new QPushButton("Preview", this);
        layout->addWidget(previewButton);
        
        // 连接信号槽
        connect(previewButton, &QPushButton::clicked, this, &StyleSheetEditor::applyStyleSheet);
        
        // 加载初始样式表
        editor->setPlainText("QPushButton { color: red; }");
    }
    
signals:
    void styleSheetChanged(const QString &styleSheet);
    
private slots:
    void applyStyleSheet()
    {
        emit styleSheetChanged(editor->toPlainText());
    }
    
private:
    QTextEdit *editor;
    QPushButton *previewButton;
};

九、最佳实践

9.1 保持样式表模块化

将样式表分为多个文件,例如:

  • main.qss:全局样式
  • buttons.qss:按钮样式
  • scrollbars.qss:滚动条样式
  • dialogs.qss:对话框样式

9.2 使用变量

虽然 QSS 不直接支持变量,但可以通过编程方式实现:

cpp 复制代码
QString primaryColor = "#4CAF50";
QString secondaryColor = "#2196F3";

QString styleSheet = QString("QPushButton { background-color: %1; } "
                             "QLabel { color: %2; }")
                     .arg(primaryColor)
                     .arg(secondaryColor);

qApp->setStyleSheet(styleSheet);

9.3 避免过度使用

保持样式表简洁,避免过于复杂的选择器和规则。

9.4 测试跨平台兼容性

不同平台的默认样式可能有所不同,确保样式表在所有目标平台上都能正常工作。

十、实战案例:设计现代化登录界面

10.1 案例需求

设计一个现代化的登录界面,具有以下特点:

  • 简洁美观的设计
  • 响应式布局
  • 平滑的交互效果
  • 自定义控件样式

10.2 样式表示例

css 复制代码
/* 全局样式 */
QWidget {
    background-color: #f5f5f5;
    font-family: "Segoe UI", "Roboto", "sans-serif";
}

/* 登录框样式 */
QFrame#loginFrame {
    background-color: white;
    border-radius: 10px;
    border: 1px solid #ddd;
    padding: 20px;
    margin: 20px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* 标题样式 */
QLabel#titleLabel {
    font-size: 24px;
    font-weight: bold;
    color: #333;
    margin-bottom: 20px;
}

/* 输入框样式 */
QLineEdit {
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 8px;
    margin: 5px 0;
    font-size: 14px;
}

QLineEdit:focus {
    border: 1px solid #2196F3;
    box-shadow: 0 0 5px rgba(33, 150, 243, 0.5);
}

/* 按钮样式 */
QPushButton {
    background-color: #2196F3;
    color: white;
    border: none;
    border-radius: 4px;
    padding: 10px;
    font-size: 16px;
    font-weight: 500;
    margin: 10px 0;
}

QPushButton:hover {
    background-color: #0b7dda;
}

QPushButton:pressed {
    background-color: #0a69b4;
}

/* 链接样式 */
QLabel[link="true"] {
    color: #2196F3;
    text-decoration: underline;
    cursor: pointer;
}

QLabel[link="true"]:hover {
    color: #0b7dda;
}

10.3 关键代码

cpp 复制代码
// 在登录窗口构造函数中应用样式表
LoginWindow::LoginWindow(QWidget *parent) : QWidget(parent)
{
    // 创建UI元素
    QFrame *loginFrame = new QFrame(this);
    loginFrame->setObjectName("loginFrame");
    
    QLabel *titleLabel = new QLabel("Login", loginFrame);
    titleLabel->setObjectName("titleLabel");
    
    QLabel *usernameLabel = new QLabel("Username:", loginFrame);
    QLineEdit *usernameEdit = new QLineEdit(loginFrame);
    
    QLabel *passwordLabel = new QLabel("Password:", loginFrame);
    QLineEdit *passwordEdit = new QLineEdit(loginFrame);
    passwordEdit->setEchoMode(QLineEdit::Password);
    
    QPushButton *loginButton = new QPushButton("Login", loginFrame);
    
    QLabel *registerLabel = new QLabel("Register", loginFrame);
    registerLabel->setProperty("link", true);
    
    // 设置布局
    QVBoxLayout *frameLayout = new QVBoxLayout(loginFrame);
    frameLayout->addWidget(titleLabel, 0, Qt::AlignCenter);
    frameLayout->addWidget(usernameLabel);
    frameLayout->addWidget(usernameEdit);
    frameLayout->addWidget(passwordLabel);
    frameLayout->addWidget(passwordEdit);
    frameLayout->addWidget(loginButton);
    frameLayout->addWidget(registerLabel, 0, Qt::AlignCenter);
    
    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addStretch();
    mainLayout->addWidget(loginFrame);
    mainLayout->addStretch();
    
    // 应用样式表
    QFile file(":/styles/login.qss");
    file.open(QFile::ReadOnly);
    setStyleSheet(file.readAll());
    
    // 连接信号槽
    connect(loginButton, &QPushButton::clicked, this, &LoginWindow::onLoginClicked);
    connect(registerLabel, &QLabel::linkActivated, this, &LoginWindow::onRegisterClicked);
}

通过 Qt 样式表,可以轻松打造出具有专业水准的个性化界面,提升应用程序的视觉吸引力和用户体验。掌握 QSS 的高级技巧,能够让你的应用在众多同类产品中脱颖而出。