本博文轉載自一去丶二三裏的博客:http://blog.csdn.net/liang19890820css
Qt Creator中默認狀況下打開qss文件(*.qss)不會高亮顯示,須要手動配置,讓其更符合閱讀習慣,以更炫麗的方式展現代碼片斷。app
配置流程以下:ide
A、進入:工具 -> 選項 -> 環境 -> MIME 類型。函數
B、在【已註冊的MIME類型】處輸入「text/css」能夠快速定位,而後在【詳情】中的「模式」處添加 *.qss,即將原來的「模式」改成:*.css;*.CSSL;*.qss。工具
注意:中間用分號(;)分隔ui
效果以下:this
爲了用戶界面外觀的動態變化,屬性選擇器能夠與動態屬性組合使用。動態屬性在QT4.2中引入,容許爲編譯時不存在的QObject屬性分配屬性值。即:若是爲QObject設置一個urgent屬性爲true,該屬性將跟隨該類,但不會爲urgent屬性包含一個Q_PROPERTY宏。url
建立樣式選擇器依賴於動態屬性,例如:urgent,能夠用一個很是動態的方式凸顯用戶界面。例如:spa
QLineEdit[urgent=true] {.net
color: red;
}
使用這種方式有侷限性。最主要的是當一個屬性值變化時,所引用的樣式不會自動更新。相反地,必須手動觸發更新纔會生效。
unpolish()用於清理以前的樣式,而polish()則用於添加新的樣式。
lineEdit->setProperty("urgent", true);
lineEdit->style()->unpolish(lineEdit);
lineEdit->style()->polish(lineEdit);
必須在組件的樣式中使用,QStyle::polish既接受QWidge也接受QApplication做爲參數。
自定義標題欄中的最大化/還原按鈕爲例,進行切換。
void TitleBar::updateMaximize() { QWidget *pWindow = this->window(); if (pWindow->isTopLevel()) { bool bMaximize = pWindow->isMaximized(); m_pMaximizeButton->setToolTip(bMaximize ? tr("Restore") : tr("Maximize")); m_pMaximizeButton->setProperty("maximizeProperty", bMaximize ? "restore" : "maximize"); // 手動更新樣式 m_pMaximizeButton->style()->unpolish(m_pMaximizeButton); m_pMaximizeButton->style()->polish(m_pMaximizeButton); m_pMaximizeButton->update(); //m_pMaximizeButton->setStyle(QApplication::style()); } }
QSS:
QPushButton#maximizeButton[maximizeProperty="maximize"] { border-radius: none; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; background: rgb(50, 50, 50); p_w_picpath: url(:/Images/maximize); } QPushButton#maximizeButton[maximizeProperty="maximize"]:hover { background: rgb(60, 60, 60); p_w_picpath: url(:/Images/maximizeHover); } QPushButton#maximizeButton[maximizeProperty="maximize"]:pressed { background: rgb(55, 55, 55); p_w_picpath: url(:/Images/maximizePressed); } QPushButton#maximizeButton[maximizeProperty="restore"] { border-radius: none; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; background: rgb(50, 50, 50); p_w_picpath: url(:/Images/restore); } QPushButton#maximizeButton[maximizeProperty="restore"]:hover { background: rgb(60, 60, 60); p_w_picpath: url(:/Images/restoreHover); } QPushButton#maximizeButton[maximizeProperty="restore"]:pressed { background: rgb(55, 55, 55); p_w_picpath: url(:/Images/restorePressed);
任何可被識別的Q_PROPERTY均可以使用qproperty-語法設置。
Q_PROPERTY定義的屬性經過QSS按照qproperty-<property name>語法的方式設置。
QLabel的屬性以下:
class Q_WIDGETS_EXPORT QLabel : public QFrame { ... Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap) Q_PROPERTY(bool scaledContents READ hasScaledContents WRITE setScaledContents) ... }; class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice { ... Q_PROPERTY(QSize minimumSize READ minimumSize WRITE setMinimumSize) Q_PROPERTY(QSize maximumSize READ maximumSize WRITE setMaximumSize) ... };
QLabel的屬性有minimumSize、maximumSize、pixmap、scaledContents。
QSS文件:
QLabel#customLabel { qproperty-minimumSize: 100px 100px; qproperty-maximumSize: 100px 100px; qproperty-pixmap: url(:/Images/logo); qproperty-scaledContents: true; } QPushButton#customButton { qproperty-text: "Click Me"; qproperty-icon: url(:/Images/logo); qproperty-iconSize: 20px 20px; } QGroupBox#customGroupBox { qproperty-title: "GroupBox"; }
源碼:
Widget::Widget(QWidget *parent) : QWidget(parent) { QLabel *pLabel = new QLabel(this); QPushButton *pButton = new QPushButton(this); QGroupBox *pGroupBox = new QGroupBox(this); pLabel->setObjectName("customLabel"); pButton->setObjectName("customButton"); pGroupBox->setObjectName("customGroupBox"); QVBoxLayout *pLayout = new QVBoxLayout(); pLayout->addStretch(); pLayout->addWidget(pLabel, 0, Qt::AlignCenter); pLayout->addWidget(pButton); pLayout->addStretch(); pLayout->setSpacing(10); pLayout->setContentsMargins(10, 10, 10, 10); pGroupBox->setLayout(pLayout); }
Main.cpp文件:
#include "Widget.h" #include <QApplication> #include <QFile> 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); CommonHelper::setStyle(":/style.qss"); Widget w; w.show(); return a.exec(); }
以上的解決方法將界面樣式與業務邏輯進行了分離,效果與以下代碼相同:
pLabel->setPixmap(QPixmap(":/Images/logo")); pLabel->setMinimumSize(100, 100); pLabel->setMaximumSize(100, 100); pLabel->setScaledContents(true); pButton->setIcon(QIcon(":/Images/logo")); pButton->setIconSize(QSize(20, 20)); pButton->setText("Click Me"); pGroupBox->setTitle("GroupBox");
QAbstractItemModel、QAbstractItemDelegate均繼承自QObject,而QSS只能用於QWidget及其子類,動態獲取樣式屬性值方法以下:
A、建立一個從QWidget繼承的專用類StyledWidget。
B、爲StyledWidget添加自定義屬性,並使用Q_PROPERTY聲明
C、自定義QSS,使用自定義屬性,語法:qproperty-<property name>
其中,Q_PROPERTY聲明有如下要求:
READ getFunction
用於讀取屬性,使用const限定,返回屬性的類型或者類型的指針或引用。
WRITE setFunction
用於設置屬性,參數是一個屬性的類型,或者屬性的const指針或引用,返回
建立一個從QWidget繼承的專用類StyledWidget,爲其添加自定義屬性,並使用Q_PROPERTY聲明。
StyledWidget.h文件:
#ifndef STYLEDWIDGET_H #define STYLEDWIDGET_H #include <QWidget> class StyledWidget : public QWidget { Q_OBJECT Q_PROPERTY(QColor normalColor READ normalColor WRITE setNormalColor DESIGNABLE true) ... public: explicit StyledWidget(QWidget *parent = 0); ~StyledWidget(); QColor normalColor() const; void setNormalColor(QColor color); ... private: QColor m_normalColor; ... }; #endif // STYLEDWIDGET_H
StyledWidget.cpp文件:
... QColor StyledWidget::normalColor() const { return m_normalColor; } void StyledWidget::setNormalColor(QColor color) { m_normalColor = color; } ...
QSS文件:
StyledWidget { qproperty-normalColor: white; qproperty-disableColor: gray; qproperty-highlightColor: rgb(0, 160, 230); qproperty-errorColor: red; }
使用:
在須要設置樣式的類中聲明StyledWidget:
class TableModel : public QAbstractTableModel { Q_OBJECT public: ... QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; ... private: ... StyledWidget m_styledWidget; };
使用自定義屬性設置樣式:
QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); switch (role) { case Qt::TextColorRole: { if (index.column() == FILE_NAME_COLUMN) return m_styledWidget.normalColor(); if (index.column() == SIZE_COLUMN) return m_styledWidget.highlightColor(); if (index.column() == STATUS_COLUMN) return m_styledWidget.errorColor(); } ... } return QVariant(); }
QT中對於樣式表的使用,爲了下降耦合性(與邏輯代碼分離),一般會定義一個QSS文件,而後編寫各類組件(QLabel、 QLineEdit、QPushButton)的樣式,最後使用QApplication進行樣式加載,讓整個應用程序就共享同一個樣式。
建立一個後綴名爲qss的文件,例如:style.qss,將其加入資源文件(qrc)中。
QLineEdit { border: 1px solid rgb(41, 57, 85); border-radius: 3px; background: white; selection-background-color: green; font-size: 14px ; }
爲了便於調用,能夠寫一個靜態加載樣式的函數
#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(); }
qApp是QCoreApplication的一個單例,而後,將其轉換爲QApplication。
#if defined(qApp) #undef qApp #endif #define qApp (static_cast<QApplication *>(QCoreApplication::instance()))
QApplication調用setStyleSheet()後全部的組件樣式都改變的主要緣由是調用了setStyle()。
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(); } }
主要分爲4步:
A、清理舊樣式 - unpolish()
B、初始化新樣式 - polish()
C、加載新樣式 - polish() + sendEvent()、update()
D、刪除舊樣式 - delete
經過調用QWidgetList all = allWidgets()獲取了全部控件的集合,而後利用迭代器QWidgetList::ConstIterator對每個控件進行處理,通 過QApplication::sendEvent()來發送QEvent::StyleChange事件,達到全局樣式更改。