首页 > 解决方案 > 如何更新样式表的单个属性?

问题描述

我有一个窗口:

class MyWindow : public QWindow
{
.....
};

MyWindow *window;

和一组样式表属性:

MyWindow
{
    style1: value1;
    style2: value2;
}

为了在窗口上设置这些属性,我必须调用:

window->setStyleSheet( "style1: value1" );
window->setStyleSheet( "style2: value2" );

例如设置 a 的对齐方式QPushButton需要设置text-align属性。

现在假设我要修改 style1 的 value1 值。我可以通过两种方式做到这一点:

  1. window->setStyleSheet( "style1: new-value" );

或者

  1. window->setStyleSheet( "style1: new-value; style2: value2" );

不同之处在于,对于第二种情况,我需要重建之前设置的整个样式表并附加我的更改。

现在的问题 -据你所知,是否有任何窗口/样式集我绝对必须按照 #2 的方式进行操作?

当然,为了更改 1 个属性值而必须重建属性表会很奇怪,但我想问一下以防万一。

标签: c++cssqt

解决方案


Background

In order to set those properties on the window I have to call:

window->setStyleSheet( "style1: value1" );
window->setStyleSheet( "style2: value2" );

The stylesheets are cascading, but not cumulative, meaning that the later stylesheet will cancel the previous one.

Consider this example:

auto *label = new QLabel("test", this);

label->setStyleSheet("background-color: yellow");
label->setStyleSheet("color: red");

The result is: the text is red, but the background has the default color.

If the last two rows switch places, the result is: the background is yellow, but the text has now the default color.

So, the answer to your question about when you absolutely have to do the way #2 is:

always

Solution

Having this background in mind, in order to answer the question from the title, I would suggest you the following solution:

  1. Convert the stylesheet to a JSON
  2. Update the value of choice
  3. Convert the JSON back to a stylesheet
  4. Set the new stylesheet to the widget

Example

The proposed solution might sound complicated, but fortunately I have prepared a class StylesheetManipulator, which has the neccessary functionality, as well as an example of how to use it:

StylesheetManipulator.h

#ifndef STYLESHEETMANIPULATOR_H
#define STYLESHEETMANIPULATOR_H

#include <qglobal.h>
#include <QJsonArray>

class StylesheetManipulator
{
public:
    static QString updateStylesheetProperty(const QString &styleSheet, const QString &selector, const QString &property, const QString &newValue);

private:
    static QJsonArray styleSheetToJson(const QString &styleSheet);
    static QJsonArray styleSheetPropertiesToJson(const QString &properties);
    static QJsonArray updateValue(const QString &selector, const QString &propertyName, const QString &newValue, const QJsonArray &jsonStyleSheet);
    static QString jsonToStyleSheet(const QJsonArray &jsonStyleSheet);
};

#endif // STYLESHEETMANIPULATOR_H

StylesheetManipulator.cpp

QString StylesheetManipulator::updateStylesheetProperty(const QString &styleSheet, const QString &selector, const QString &property, const QString &newValue)
{
    return jsonToStyleSheet(updateValue(selector, property, newValue, styleSheetToJson(styleSheet)));
}

QJsonArray StylesheetManipulator::styleSheetToJson(const QString &styleSheet)
{
    QJsonArray jsonStyleSheet;

    if (styleSheet.isEmpty())
        return jsonStyleSheet;

    foreach (const QString &style, styleSheet.trimmed().split("}")) {
        const QString &trimmedStyle(style.trimmed());

        if (!trimmedStyle.isEmpty()) {
            const QStringList &list(trimmedStyle.split("{"));

            jsonStyleSheet.append(QJsonObject {
                                 {"selector", list.first().trimmed()},
                                 {"properties", styleSheetPropertiesToJson(list.last())}
                             });
        }
    }

    return jsonStyleSheet;
}

QJsonArray StylesheetManipulator::styleSheetPropertiesToJson(const QString &properties)
{
    QJsonArray jsonProperties;

    if (properties.isEmpty())
        return jsonProperties;

    foreach (const QString &property, properties.trimmed().split(";")) {
        const QString &trimmedProperty(property.trimmed());

        if (!trimmedProperty.isEmpty()) {
            const QStringList &list(trimmedProperty.split(":"));

            jsonProperties.append(QJsonObject{
                                      {"name", list.first().trimmed()},
                                      {"value", list.last().trimmed()}
                                  });
        }
    }

    return jsonProperties;
}

QJsonArray StylesheetManipulator::updateValue(const QString &selector, const QString &propertyName, const QString &newValue, const QJsonArray &jsonStyleSheet)
{
    QJsonArray a;

    foreach (const QJsonValue &value, jsonStyleSheet) {
        const QJsonObject &currentStyle(value.toObject());
        const QString &currentSelector(currentStyle["selector"].toString());
        bool selectorFound = currentSelector == selector;
        QJsonArray properties;

        foreach (const QJsonValue &value, currentStyle["properties"].toArray()) {
            QJsonObject property(value.toObject());

            if (selectorFound && (property["name"].toString() == propertyName))
                property["value"] = newValue;

            properties.append(property);
        }

        a.append(QJsonObject{
                     {"selector", currentSelector},
                     {"properties", properties}
                 });
    }

    return a;
}

QString StylesheetManipulator::jsonToStyleSheet(const QJsonArray &jsonStyleSheet)
{
    QString styleSheet;

    foreach (const QJsonValue &value, jsonStyleSheet) {
        const QJsonObject &currentStyle(value.toObject());

        styleSheet.append(currentStyle["selector"].toString() + " {");

        foreach (const QJsonValue &value, currentStyle["properties"].toArray()) {
            QJsonObject property(value.toObject());

            styleSheet.append(" " + property["name"].toString() + ": " + property["value"].toString() + ";");
        }

        styleSheet.append(" } ");
    }

    return styleSheet;
}

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
    auto *label = new QLabel("test", this);
    auto *l = new QVBoxLayout(this);

    label->setStyleSheet("QFrame { background-color: yellow; border: 2px solid blue } QLabel { color: red; }");
    label->setStyleSheet(StylesheetManipulator::updateStylesheetProperty(label->styleSheet(), "QLabel", "color", "green"));

    l->addWidget(label);

    resize(300, 200);
}

The complete code of the example is available on GitHub

The example produces the following result:

Window with a green text on yellow background surrounded by a blue border

Please note, that although initially the text color was set to red (QLabel { color: red; }), it has been effectively changed to green.


推荐阅读