如何在 Qt StyleSheet 中只覆盖一对 property:value
How to override just one property:value pair in Qt StyleSheet
我正在 OSX Mavericks 上编写新手 Qt5 代码,并且只想覆盖给定小部件的一对 property:value 样式表。
如果我运行下面的自包含演示代码:
#include <QApplication>
#include <QMainWindow>
#include <QtGui>
#include <QPushButton>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
QPushButton* AButton = new QPushButton( "A Button", mw );
mw->show();
return app.exec();
}
我得到了一个带有 Macintosh 风格默认设置的漂亮按钮——圆角、标准 OSX- 按下时为蓝色等:
但是,如果我将样式表设置为使背景按钮颜色为红色,似乎我在此过程中丢失了所有其他 OSX 样式默认值——不再有圆角、标准边距等:
#include <QApplication>
#include <QMainWindow>
#include <QtGui>
#include <QPushButton>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
QPushButton* AButton = new QPushButton( "A Button", mw );
AButton->setStyleSheet("QPushButton { background-color: red; }");
mw->show();
return app.exec();
}
结果如下:
如何只覆盖一对 property:value 而同时保留小部件的其余样式元素,例如在上面的示例中,将背景颜色设置为红色,但保持所有边框圆角、边距等不变?
非常感谢
正如并行 post 中所阐明的那样,我最初的问题是基于混淆的前提。
在 Qt 中,所有小部件都通过 QStyle(). By default for Qt code on OSX (as in my first block of demonstration code in the original question), Qt widgets are styled by a subclass of QStyle() called QMacStyle() (actually now apparently a derivative of QProxyStyle(), per the page QMacStyle -- File Not Found) 设置样式。
setStyleSheet() 函数调用,就像我在原始问题中的第二个演示代码块中一样,创建了一个 QStyleSheetStyle() 实例,然后它会批量替换之前用于小部件的任何 QStyle - 在此以我一直希望保留的漂亮 QMacStyle 为例。人们可以在例如qtbase/src/widgets/kernel/qapplication.cpp
在 QApplication::setStyleSheet()
方法中。 QStyleSheetStyle() 本身在 qtbase/src/widgets/styles/qstylesheetstyle.cpp
中。作为琐事,QStyleSheetStyle() 派生自 QWindowsStyle(),因此在我的原始问题中修改后的按钮具有 windows-ish 外观。
简而言之,Qt StyleSheets 是在 QStyle() 之上实现的。调用 setStyleSheet() 隐含地决定您将使用 QStyleSheetStyle() 而不是 QMacStyle()。
要点是,在设计小部件样式时,您需要选择自己的方法,并权衡两种方式。您需要选择要使用的 QStyle()。如果您 运行 默认代码在 Mac 上,则您已选择从 QMacStyle() 开始。然后,您可以根据现有文档修改该 QStyle() 。如果您调用 setStyleSheet(),则您已隐式选择从 QStyleSheetStyle() 开始,默认情况下它具有 QWindowsStyle() 的外观。您随后应用的任何样式表 属性-values 都会修改该外观。
对于我上面提出的问题,有两种选择。一个是一个人可以完全通过 QStyle() 可用的机制进行任何和所有外观修改。其他地方记录了如何执行此操作。另一种选择是从头开始生成一个样式表,该样式表再现了相关小部件的 Mac 外观,然后使用所需的调整对其进行修改并通过 setStyleSheet() 应用它。
在一个理想的世界中,有人已经完成了该练习——即将 qtbase/src/widgets/styles/qmacstyle_mac.mm
消化到其等效样式表中——但是这项工作似乎很繁重,而且似乎没有人做过,至少不是 public posting。我想另一个遥远可行的选择是基于 QMacStyle 而不是 QWindowsStyle 重新实现 QStyleSheetStyle,然后以某种方式将结果整合回代码中(可能有一个 setStyleSheet( QStyle* baseStyle, QString styleSheet))。然而,这远远超出了 Qt 新手的技能,更不用说当前的任务了。
您在评论中的分析是对 QApplication::setStyleSheet() will completely replace the currently active style is incorrect. You are right that a the current style is replaced with QStyleSheetStyle
. However, QStyleSheetStyle
delegates its drawing to the original style, in your case the Mac style. If you look at the source of QStyleSheetStyle 的调用,您会在很多地方看到这一点,对 baseStyle()->drawControl()
.
的调用
这意味着风格sheet适用于任何风格。现在,它显然不适用于您的情况,所以发生了什么?如果样式 sheet 规则无法应用于基本样式,QStyleSheetStyle
将回退到 Windows 样式中进行绘制。这意味着某些样式 sheet 规则可以很好地工作,而其他样式会触发回退。您的规则触发了回退。
我认为没有记录哪些规则会触发回退。为此,我们需要查看源代码,在本例中为 QStyleSheetStyle::drawControl()。我们会在其中找到以下内容:
case CE_PushButton:
if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() ||
((btn->features & QStyleOptionButton::HasMenu) && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator))) {
ParentStyle::drawControl(ce, opt, p, w);
return;
}
}
ParentSyle
是后备 Windows 样式。您的规则 background-color
使 rule.hasPalette()
return 为真,因此触发回退。
我正在 OSX Mavericks 上编写新手 Qt5 代码,并且只想覆盖给定小部件的一对 property:value 样式表。
如果我运行下面的自包含演示代码:
#include <QApplication>
#include <QMainWindow>
#include <QtGui>
#include <QPushButton>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
QPushButton* AButton = new QPushButton( "A Button", mw );
mw->show();
return app.exec();
}
我得到了一个带有 Macintosh 风格默认设置的漂亮按钮——圆角、标准 OSX- 按下时为蓝色等:
但是,如果我将样式表设置为使背景按钮颜色为红色,似乎我在此过程中丢失了所有其他 OSX 样式默认值——不再有圆角、标准边距等:
#include <QApplication>
#include <QMainWindow>
#include <QtGui>
#include <QPushButton>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
QPushButton* AButton = new QPushButton( "A Button", mw );
AButton->setStyleSheet("QPushButton { background-color: red; }");
mw->show();
return app.exec();
}
结果如下:
如何只覆盖一对 property:value 而同时保留小部件的其余样式元素,例如在上面的示例中,将背景颜色设置为红色,但保持所有边框圆角、边距等不变?
非常感谢
正如并行 post
在 Qt 中,所有小部件都通过 QStyle(). By default for Qt code on OSX (as in my first block of demonstration code in the original question), Qt widgets are styled by a subclass of QStyle() called QMacStyle() (actually now apparently a derivative of QProxyStyle(), per the page QMacStyle -- File Not Found) 设置样式。
setStyleSheet() 函数调用,就像我在原始问题中的第二个演示代码块中一样,创建了一个 QStyleSheetStyle() 实例,然后它会批量替换之前用于小部件的任何 QStyle - 在此以我一直希望保留的漂亮 QMacStyle 为例。人们可以在例如qtbase/src/widgets/kernel/qapplication.cpp
在 QApplication::setStyleSheet()
方法中。 QStyleSheetStyle() 本身在 qtbase/src/widgets/styles/qstylesheetstyle.cpp
中。作为琐事,QStyleSheetStyle() 派生自 QWindowsStyle(),因此在我的原始问题中修改后的按钮具有 windows-ish 外观。
简而言之,Qt StyleSheets 是在 QStyle() 之上实现的。调用 setStyleSheet() 隐含地决定您将使用 QStyleSheetStyle() 而不是 QMacStyle()。
要点是,在设计小部件样式时,您需要选择自己的方法,并权衡两种方式。您需要选择要使用的 QStyle()。如果您 运行 默认代码在 Mac 上,则您已选择从 QMacStyle() 开始。然后,您可以根据现有文档修改该 QStyle() 。如果您调用 setStyleSheet(),则您已隐式选择从 QStyleSheetStyle() 开始,默认情况下它具有 QWindowsStyle() 的外观。您随后应用的任何样式表 属性-values 都会修改该外观。
对于我上面提出的问题,有两种选择。一个是一个人可以完全通过 QStyle() 可用的机制进行任何和所有外观修改。其他地方记录了如何执行此操作。另一种选择是从头开始生成一个样式表,该样式表再现了相关小部件的 Mac 外观,然后使用所需的调整对其进行修改并通过 setStyleSheet() 应用它。
在一个理想的世界中,有人已经完成了该练习——即将 qtbase/src/widgets/styles/qmacstyle_mac.mm
消化到其等效样式表中——但是这项工作似乎很繁重,而且似乎没有人做过,至少不是 public posting。我想另一个遥远可行的选择是基于 QMacStyle 而不是 QWindowsStyle 重新实现 QStyleSheetStyle,然后以某种方式将结果整合回代码中(可能有一个 setStyleSheet( QStyle* baseStyle, QString styleSheet))。然而,这远远超出了 Qt 新手的技能,更不用说当前的任务了。
您在评论中的分析是对 QApplication::setStyleSheet() will completely replace the currently active style is incorrect. You are right that a the current style is replaced with QStyleSheetStyle
. However, QStyleSheetStyle
delegates its drawing to the original style, in your case the Mac style. If you look at the source of QStyleSheetStyle 的调用,您会在很多地方看到这一点,对 baseStyle()->drawControl()
.
这意味着风格sheet适用于任何风格。现在,它显然不适用于您的情况,所以发生了什么?如果样式 sheet 规则无法应用于基本样式,QStyleSheetStyle
将回退到 Windows 样式中进行绘制。这意味着某些样式 sheet 规则可以很好地工作,而其他样式会触发回退。您的规则触发了回退。
我认为没有记录哪些规则会触发回退。为此,我们需要查看源代码,在本例中为 QStyleSheetStyle::drawControl()。我们会在其中找到以下内容:
case CE_PushButton:
if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() ||
((btn->features & QStyleOptionButton::HasMenu) && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator))) {
ParentStyle::drawControl(ce, opt, p, w);
return;
}
}
ParentSyle
是后备 Windows 样式。您的规则 background-color
使 rule.hasPalette()
return 为真,因此触发回退。