如何在Qt StyleSheet中只覆盖一个属性:值对

lci*_*kgl 15 qt qt5 qtstylesheets qpushbutton

我正在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();
}
Run Code Online (Sandbox Code Playgroud)

我得到了一个很好的按钮,默认为Macintosh风格 - 圆角,按下时标准OSX-蓝色等:

带有OSX默认值的QPushButton

但是,如果我设置样式表以使背景按钮颜色为红色,那么在此过程中我似乎失去了所有其他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();
}
Run Code Online (Sandbox Code Playgroud)

这是结果:

QPushButton样式覆盖,丢失了其他OSX默认值

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

非常感谢

Tho*_*ire 6

您在评论中对QApplication :: setStyleSheet()的调用将完全替换当前活动样式的分析是不正确的.你是正确的,当前的风格被替换QStyleSheetStyle.但是,QStyleSheetStyle将其绘图委托给原始样式,在您的情况下为Mac样式.如果你看一下QStyleSheetStyle来源,你会在很多地方看到这个,调用baseStyle()->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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

ParentSyle是后备Windows风格.您的规则background-color使rule.hasPalette()返回为true,从而触发回退.


lci*_*kgl 5

正如并行帖子如何为 QMacStyle 获取整个 Qt StyleSheet 中所阐明的那样,我最初的问题是基于混淆的前提。

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

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

简而言之,Qt 样式表是在 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 技能,更不用说当前的任务了。