如何仅覆盖一个属性:Qt StyleSheet 中的值对

Posted

技术标签:

【中文标题】如何仅覆盖一个属性:Qt StyleSheet 中的值对【英文标题】:How to override just one property:value pair in Qt StyleSheet 【发布时间】:2015-05-04 13:58:54 【问题描述】:

我正在 OSX Mavericks 上编写新手 Qt5 代码,并且希望只覆盖给定小部件的 StyleSheet 的一个属性:值对。

如果我运行以下独立的演示代码:

#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();

结果如下:

如何只覆盖一个属性:值对,同时保留小部件的其余样式元素,例如在上面的示例中,将背景颜色设为红色,但保持所有边框圆角、边距等相同?

非常感谢

【问题讨论】:

您可以尝试使用AButton-&gt;setStyleSheet(AButton-&gt;styleSheet() + "...");将新样式添加到现有样式中 谢谢,但这似乎仍然会覆盖所有其他平台默认值(我使用了AButton-&gt;setStyleSheet( AButton-&gt;styleSheet() + "QPushButton background-color: red; "); 啊等等...您所说的不是被覆盖的 CSS 样式属性,而是 系统样式 QtWidget 的样式引擎试图模仿。当您手动指定某些属性时,它无法模仿系统样式,AFAIK,并且当样式引擎无法适应您指定的 CSS 属性时,它会退回到“旧 Windows 样式”。尝试改用调色板。看看QWidget::setPalette()palette(),然后尝试为一些角色设置颜色(play around 用于按钮背景,我不记得了)。这将被样式引擎考虑。 看起来QMacStyle 忽略了用于设置背景的QPalette::Button 颜色。您可以使用QPalette::Text 设置文本颜色。 【参考方案1】:

您在评论中对QApplication::setStyleSheet() 的调用将完全替换当前活动样式的分析是不正确的。您是对的,当前样式被替换为QStyleSheetStyle。但是,QStyleSheetStyle 将其绘图委托给原始样式,在您的情况下为 Mac 样式。如果您查看source of QStyleSheetStyle,您会在很多地方看到这个,请致电baseStyle()-&gt;drawControl()

这意味着样式表适用于任何样式。现在,它显然不适用于您的情况,所以发生了什么?如果样式表规则不能应用于基本样式,QStyleSheetStyle 会退回到以 Windows 样式进行绘制。这意味着一些样式表规则可以很好地工作,而另一些则会触发回退。您的规则触发了回退。

我认为没有记录哪些规则会触发回退。为此,我们需要查看源代码,在本例中为 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() 返回 true,因此触发了回退。

【讨论】:

【参考方案2】:

正如平行帖子How to obtain entire Qt StyleSheet for QMacStyle 中所述,我最初的问题是基于混淆的前提。

在 Qt 中,所有小部件都通过 QStyle() 设置样式。默认情况下,对于 OSX 上的 Qt 代码(如我在原始问题中的第一个演示代码块中),Qt 小部件由称为 QMacStyle() 的 QStyle() 的子类设置样式(实际上现在显然是 QProxyStyle() 的派生,根据页QMacStyle -- File Not Found)。

setStyleSheet() 函数调用,就像我在原始问题中的第二个演示代码块中一样,创建了一个 QStyleSheetStyle() 实例,然后它会批量替换事先用于小部件的任何 QStyle——在这种情况下我一直希望保留漂亮的 QMacStyle。可以在例如查看实现细节。 qtbase/src/widgets/kernel/qapplication.cppQApplication::setStyleSheet() 方法中。 QStyleSheetStyle() 本身位于qtbase/src/widgets/styles/qstylesheetstyle.cpp 中。作为一个琐事,QStyleSheetStyle() 是从 QWindowsStyle() 派生的,因此在我原来的问题中修改后的按钮看起来像 Windows。

简而言之,Qt StyleSheets 是在 QStyle() 之上实现的。调用 setStyleSheet() 隐式决定你将使用 QStyleSheetStyle() 而不是 QMacStyle()。

关键信息是,在为小部件设计样式时,您需要选择自己的方法,无论哪种方式都要权衡取舍。您需要选择要使用的 QStyle()。如果您在 Mac 上运行默认代码,则您选择从 QMacStyle() 开始。然后,您可以根据现有文档修改该 QStyle() 。如果调用 setStyleSheet(),则隐式选择从 QStyleSheetStyle() 开始,默认情况下它具有 QWindowsStyle() 的外观。您随后应用的任何样式表属性值都将修改该外观。

对于我上面提出的问题,有两种选择。一是人们可以完全通过QStyle() 提供的机制进行任何和所有外观修改。如何做到这一点记录在别处。另一种选择是从头开始生成一个样式表,该样式表重现了相关小部件的 Mac 外观,然后使用所需的调整对其进行修改,并通过 setStyleSheet() 应用它。

在一个理想的世界里,有人已经完成了这个练习——即将qtbase/src/widgets/styles/qmacstyle_mac.mm消化到它的等效样式表中——但是这项工作似乎很繁重,而且似乎没有人做过,至少没有公开张贴。我想另一个遥远可行的选择是基于 QMacStyle 而不是 QWindowsStyle 重新实现 QStyleSheetStyle,然后以某种方式将结果集成回代码中(可能有一个 setStyleSheet(QStyle* baseStyle,QString styleSheet))。然而,这远远超出了新手 Qt 的技能,更不用说当前的任务了。

【讨论】:

以上是关于如何仅覆盖一个属性:Qt StyleSheet 中的值对的主要内容,如果未能解决你的问题,请参考以下文章

qt里如何给button添加背景图片

qt的stylesheet中如何设置属性使背景图自动调整来适应控件的大小,急求!

Qt学习笔记14.界面的样式 (Qt Stylesheet) (待续)

Qt Quick - 如何仅通过 c++ 代码与 qml 属性交互

为啥在Qt中用qss对同类的控件有不同的效果

如何为 QMacStyle 获取整个 Qt StyleSheet