Qt QSS(二)之應用篇

Qt QSS(二)之應用篇

將QSS應用到Qt應用程序中

直接使用setStyleSheet("")來設置樣式;

  1. 在一個應用程序性中設置背景顏色爲黃色
    qApp->setStyleSheet("QLineEdit { background-color: yellow }");
  2. 如果需要設置指定對話框裏的的 QLineEdits樣式
    myDialog->setStyleSheet("QLineEdit { background-color: yellow }");
  3. 如果想使用在指定的 QLineEdit, 我們可以使用對象名QObject::setObjectName()和使用選擇器ID:
    myDialog->setStyleSheet("QLineEdit#nameEdit { background-color: yellow }");
  4. 爲文本設置合適顏色,用於形成明顯的對比
    nameEdit->setStyleSheet("color: blue; background-color: yellow");
  5. 設置文本被選中時的顏色
nameEdit->setStyleSheet("color: blue;"
                        "background-color: yellow;"
                        "selection-color: yellow;"
                        "selection-background-color: blue;");

加載 QSS 文件的形式設置樣式

  1. 新建QSS文件,後綴名爲qss。例如:qstyle.qss
    爲了方便使用,可以在Qt新建一個資源文件qstyle.qrc,用於存放樣式文件。
    當然,也可以直接用絕對路徑指向樣式文件。

  2. 打開qstyle.qss,編寫樣式內容

QLineEdit { background-color: yellow }
  1. 加載QSS文件
    首先封裝一個靜態函數,用於實現樣式的加載,方便在應用程序中使用。
#include <QFile>
#include <QApplication>

class CommonHelper
{
public:
    static void setStyle(const QString &style) {
        QFile qss(style);
        qss.open(QFile::ReadOnly);
        qApp->setStyleSheet(qss.readAll());
        qss.close();
    }
};

具體使用如下:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 加載QSS樣式
    CommonHelper::setStyle("style.qss");

    MainWindow window;
    window.show();

    return a.exec();
}
  1. 爲了瞭解QApplication調用setStyleSheet()後,可以改變應用程序裏的所有樣式,我們需要進行源碼的調試。QtCreator 設置了源碼位置的,調試時可以進入到源碼。
  • 首先我們進入到setStyleSheet(const QString& )查看其實現
void QApplication::setStyleSheet(const QString& styleSheet)
{
    //將樣式內容保存到內存,以備候用
    QApplicationPrivate::styleSheet = styleSheet;
    //獲取當前應用程序的樣式
    QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplicationPrivate::app_style);
    //第一個判斷條件:如果傳入樣式爲空,則保持當前應該用程序樣式
    if (styleSheet.isEmpty()) { // application style sheet removed
        if (!proxy)
            return; // there was no stylesheet before
        setStyle(proxy->base);
    //如果應用程序已經設置了樣式,則只是刷新樣式,而不會使用函數傳入的樣式。
    //這也就告訴我們,爲qApp設置樣式前,需要卸載當前樣式,之後安裝樣式才能生效
    } else if (proxy) { // style sheet update, just repolish
        proxy->repolish(qApp);
   //當前qApp沒有樣式,設置我們傳進來的樣式
    } else { // stylesheet set the first time
        QStyleSheetStyle *newProxy = new QStyleSheetStyle(QApplicationPrivate::app_style);
        QApplicationPrivate::app_style->setParent(newProxy);
        setStyle(newProxy);
    }
}

上面的中文註釋,解釋了這段代碼的運行機制。我們最終設置樣式是通過setStyle(QStyle *style)這個函數實現的。 源碼如下:
從上到下解釋運行邏輯。

  • 傳入樣式必須有效,且樣式必須是新樣式
  • QWidgetList all = allWidgets(); 獲取應用程序所有控件
  • 清除所有老樣式 unpolish(QWidget*)
  • 樣式有效, 關聯新樣式QApplicationPrivate::app_style->setParent(qApp);
  • 初始化樣式 polish()
  • 將新樣式應用到所有子控件中 polish() + sendEvent()、update()
  • 刪除舊樣式 - delete
void QApplication::setStyle(QStyle *style)
{
    if (!style || style == QApplicationPrivate::app_style)
        return;

    QWidgetList all = allWidgets();

    // clean up the old style
    if (QApplicationPrivate::app_style) {
        if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
            for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
                QWidget *w = *it;
                if (!(w->windowType() == Qt::Desktop) &&        // except desktop
                     w->testAttribute(Qt::WA_WState_Polished)) { // has been polished
                    QApplicationPrivate::app_style->unpolish(w);
                }
            }
        }
        QApplicationPrivate::app_style->unpolish(qApp);
    }

    QStyle *old = QApplicationPrivate::app_style; // save

    QApplicationPrivate::overrides_native_style =
        nativeStyleClassName() == QByteArray(style->metaObject()->className());

#ifndef QT_NO_STYLE_STYLESHEET
    if (!QApplicationPrivate::styleSheet.isEmpty() && !qobject_cast<QStyleSheetStyle *>(style)) {
        // we have a stylesheet already and a new style is being set
        QStyleSheetStyle *newProxy = new QStyleSheetStyle(style);
        style->setParent(newProxy);
        QApplicationPrivate::app_style = newProxy;
    } else
#endif // QT_NO_STYLE_STYLESHEET
        QApplicationPrivate::app_style = style;
    QApplicationPrivate::app_style->setParent(qApp); // take ownership

    // take care of possible palette requirements of certain gui
    // styles. Do it before polishing the application since the style
    // might call QApplication::setPalette() itself
    if (QApplicationPrivate::set_pal) {
        QApplication::setPalette(*QApplicationPrivate::set_pal);
    } else if (QApplicationPrivate::sys_pal) {
        clearSystemPalette();
        initSystemPalette();
        QApplicationPrivate::initializeWidgetPaletteHash();
        QApplicationPrivate::initializeWidgetFontHash();
        QApplicationPrivate::setPalette_helper(*QApplicationPrivate::sys_pal, /*className=*/0, /*clearWidgetPaletteHash=*/false);
    } else if (!QApplicationPrivate::sys_pal) {
        // Initialize the sys_pal if it hasn't happened yet...
        QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette());
    }

    // initialize the application with the new style
    QApplicationPrivate::app_style->polish(qApp);

    // re-polish existing widgets if necessary
    if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
        for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
            QWidget *w = *it;
            if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) {
                if (w->style() == QApplicationPrivate::app_style)
                    QApplicationPrivate::app_style->polish(w);                // repolish
#ifndef QT_NO_STYLE_STYLESHEET
                else
                    w->setStyleSheet(w->styleSheet()); // touch
#endif
            }
        }

        for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
            QWidget *w = *it;
            if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) {
                    QEvent e(QEvent::StyleChange);
                    QApplication::sendEvent(w, &e);
                    w->update();
            }
        }
    }

#ifndef QT_NO_STYLE_STYLESHEET
    if (QStyleSheetStyle *oldProxy = qobject_cast<QStyleSheetStyle *>(old)) {
        oldProxy->deref();
    } else
#endif
    if (old && old->parent() == qApp) {
        delete old;
    }

    if (QApplicationPrivate::focus_widget) {
        QFocusEvent in(QEvent::FocusIn, Qt::OtherFocusReason);
        QApplication::sendEvent(QApplicationPrivate::focus_widget->style(), &in);
        QApplicationPrivate::focus_widget->update();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章