应用样式表适合统一默认字体和颜色;自定义 QWidget 还需要明确谁来绘制样式背景。红色背景或边框不出现时,应检查规则匹配、绘制路径和子控件几何关系。
本文完整程序已用 Qt 6.10.2 Widgets 编译,并在 Fusion 样式下检查背景、边框与子控件的实际合成像素。原生平台主题可能有不同外观,不能以这里的配色代替目标平台检查。
应用默认值与局部背景
跳转到“应用默认值与局部背景”QApplication::setStyleSheet() 设置全局规则。原有白色背景、黑色文字、14px 字号和 Microsoft YaHei 字体可以保留;缺少这款字体的平台会回退到可用字体。把背景写在 QWidget 类型选择器上会匹配大量派生控件,适用于确实需要这个全局默认值的场景。
指定对象的局部规则可以覆盖全局默认值。为某一个面板设置背景时,使用 QWidget#BalanceSetupItem,不要仅为了缩小范围而写泛指所有 QWidget 的选择器。
自定义控件怎样参与样式绘制
跳转到“自定义控件怎样参与样式绘制”普通 QWidget 支持样式背景,不能笼统说它必须手动开启一个属性才会显示 QSS。对于自己实现的 QWidget 子类,可以按 Qt 的 QWidget 样式说明 在 paintEvent() 中调用 QStyle::PE_Widget,随后再画自己的内容。使用类名作为选择器还需要正确的 Qt 元对象信息;下面保留 Q_OBJECT,并由 CMake 的 AUTOMOC 处理。
Qt::WA_StyledBackground 也是要求按样式绘制背景的属性,适用于有意使用 Qt 背景绘制路径的控件。下面选择显式 paintEvent() 路径,不再重复开启该属性。任意自绘函数随后覆盖整个控件时,仍可能遮住先前的背景。
完整的 BalanceSetupItem 示例
跳转到“完整的 BalanceSetupItem 示例”保存为 main.cpp。窗口包含一个固定高 70px 的自定义条目,背景红色,上下各有 1px 灰色边框。原示例里未声明的 JP_SettingScreen 已替换为这里完整构建的普通窗口。
#include <QApplication>#include <QHBoxLayout>#include <QLabel>#include <QPainter>#include <QPushButton>#include <QStyle>#include <QStyleOption>#include <QVBoxLayout>
class BalanceSetupItem final : public QWidget{ Q_OBJECTpublic: explicit BalanceSetupItem(QWidget *parent = nullptr) : QWidget(parent) { setObjectName("BalanceSetupItem"); setFixedHeight(70); setStyleSheet(R"QSS( QWidget#BalanceSetupItem { background-color: red; border-top: 1px solid gray; border-bottom: 1px solid gray; } QLabel#balanceTitle { background-color: transparent; color: black; } )QSS"); auto *layout = new QHBoxLayout(this); layout->setContentsMargins(1, 1, 1, 1); auto *label = new QLabel("Balance setup", this); label->setObjectName("balanceTitle"); auto *button = new QPushButton("Configure", this); button->setObjectName("configureButton"); layout->addWidget(label); layout->addStretch(); layout->addWidget(button); }
protected: void paintEvent(QPaintEvent *) override { QStyleOption option; option.initFrom(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this); }};
QWidget *makeWindow(){ qApp->setStyleSheet(R"QSS( QWidget { background-color: white; color: black; font-family: "Microsoft YaHei"; font-size: 14px; } )QSS"); auto *window = new QWidget; window->setWindowTitle("Global style and custom background"); auto *layout = new QVBoxLayout(window); layout->addWidget(new QLabel("The application default is white.", window)); layout->addWidget(new BalanceSetupItem(window)); window->resize(480, 180); return window;}
int main(int argc, char *argv[]){ QApplication app(argc, argv); QWidget *window = makeWindow(); window->show(); const int result = app.exec(); delete window; return result;}
#include "main.moc"配套 CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)project(QssExample LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_AUTOMOC ON)find_package(Qt6 REQUIRED COMPONENTS Widgets)add_executable(qss-example main.cpp)target_link_libraries(qss-example PRIVATE Qt6::Widgets)用正确配置 Qt Kit 的 Qt Creator 打开工程后构建运行。两个教程的 main.cpp 各自是独立程序,应分别建工程。
边框为什么还可能被遮住
跳转到“边框为什么还可能被遮住”QLayout::setContentsMargins(1, 1, 1, 1) 在布局区域四边留出空间;QSS 的 padding 属于控件的样式盒模型。它们作用于不同环节,不要假定给自定义父控件写 padding: 1px 就等于设置其子布局边距。示例直接给布局保留 1px,并检查标签与按钮都处于边框内侧。
标签另外设置透明背景,是为了显示条目的红色。应用的 QWidget { background-color: white; } 本来还会匹配标签;仅修改父对象的背景并不会撤销那条白色规则。
排查时依次确认对象名、有效样式的来源、绘制顺序和子对象是否覆盖边缘。不要加 !important,Qt 的 QSS 没有这项优先级机制。规则冲突详见 选择器与作用域。