QSS自定义属性
1.基本使用
(參見 Qt 文檔頁章節 Setting QObject Properties:https://doc.qt.io/qt-5/stylesheet-syntax.html)
從 Qt 4.3 及更高版本開始,可以使用 qproperty- <屬性名稱> 語法設置任何 designable 的 Q_PROPERTY ,QWidget 派生類支持該語法,僅繼承 QObject 不會生效。使用該機制可以很方便的擴展我們的程序。
如我們給自己的窗口加上屬性:
class MainWindow : public QMainWindow {Q_OBJECTQ_PROPERTY(int id READ getId WRITE setId)Q_PROPERTY(QString name READ getName WRITE setName)//... ... }就可以在 QSS 樣式表中這樣賦值:
(QString 類型的貌似不能空格分隔,而且不能和顏色值之類的沖突)
MainWindow{ qproperty-id:10; qproperty-name:gongjianbo-1992; }如果我們在屬性的 set 函數中打印的話,是可以看到對應輸出的:
一些常用的類型對應的 QSS 寫法:
/* QIcon QImage 等 */ MyLabel { qproperty-pixmap: url(pixmap.png); }/* QColor */ MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }MyPushButton { /* QSize */ qproperty-iconSize: 20px 20px;/* QRect */ qproperty-myrect:rect(10 20 100 50); /* QBrush 之漸變色 */ qproperty-mycolor:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255)); }2.注意事項
如果該屬性引用用 Q_ENUMS 聲明的枚舉,則應按名稱(而不是其數值)引用其常量。
請謹慎使用 qproperty 語法,因為它會修改正在繪制的小部件。
qproperty 語法僅計算一次,即用樣式修飾小部件時。這意味著在偽狀態(例如 QPushButton:hover)中使用它們的任何嘗試都將無效。但是我們可以給非偽狀態重新設置屬性值。
如果使用 QString 類型,不要和 QColor 之類的屬性值沖突,并且中間不要有分隔。
對于漸變色,可以用 QBrush 類接收。
(2020-6-6補充)正數賦值直接寫數字就行,負數測試發現需要加字符串引號。
3.樣式表與枚舉
(2020-6-6補充)對于自定義屬性的枚舉值,賦值操作使用字符串:
class MyLabel : public QLabel {Q_OBJECTQ_ENUMS(MyColor)Q_PROPERTY(MyColor color READ getColor WRITE setColor) public:enum MyColor{Green=1,Yellow=2,Red=3};//... ... } /*類選擇器*/ .MyLabel{ /*這里有作用域是因為我枚舉是聲明在MyLabel類里的*/ qproperty-color:"MyLabel::Red"; }?對于屬性選擇器中的枚舉值,賦值使用枚舉對應常量的字符串:
.MyLabel[color="1"]{ background:green; } .MyLabel[color="2"]{ background:yellow; } .MyLabel[color="3"]{ background:red; }經測試 Q_ENUMS 和 Q_ENUM 注冊的枚舉是一樣的寫法,雖然 QDebug 打印的時候前者是常量后者是枚舉字符串。(Q_ENUMS 和 Q_ENUM 可以參見文檔,以及相關資料:https://woboq.com/blog/q_enum.html)?
4.相關源碼片段
屬性解析相關
//E:\Qt\qt-everywhere-src-5.15.0\qtbase\src\widgets\styles\qstylesheetstyle.cpp
(可以看到一些支持的基本類型)
void QStyleSheetStyle::setProperties(QWidget *w) {// The final occurrence of each property is authoritative.// Set value for each property in the order of property final occurrence// since properties interact.const QVector<Declaration> decls = declarations(styleRules(w), QString());QVector<int> finals; // indices in reverse order of each property's final occurrence{// scan decls for final occurrence of each "qproperty"QSet<const QString> propertySet;for (int i = decls.count() - 1; i >= 0; --i) {const QString property = decls.at(i).d->property;if (!property.startsWith(QLatin1String("qproperty-"), Qt::CaseInsensitive))continue;if (!propertySet.contains(property)) {propertySet.insert(property);finals.append(i);}}}for (int i = finals.count() - 1; i >= 0; --i) {const Declaration &decl = decls.at(finals[i]);QString property = decl.d->property;property.remove(0, 10); // strip "qproperty-"const QMetaObject *metaObject = w->metaObject();int index = metaObject->indexOfProperty(property.toLatin1());if (Q_UNLIKELY(index == -1)) {qWarning() << w << " does not have a property named " << property;continue;}const QMetaProperty metaProperty = metaObject->property(index);if (Q_UNLIKELY(!metaProperty.isWritable() || !metaProperty.isDesignable())) {qWarning() << w << " cannot design property named " << property;continue;}QVariant v;const QVariant value = w->property(property.toLatin1());switch (value.userType()) {case QMetaType::QIcon: v = decl.iconValue(); break;case QMetaType::QImage: v = QImage(decl.uriValue()); break;case QMetaType::QPixmap: v = QPixmap(decl.uriValue()); break;case QMetaType::QRect: v = decl.rectValue(); break;case QMetaType::QSize: v = decl.sizeValue(); break;case QMetaType::QColor: v = decl.colorValue(); break;case QMetaType::QBrush: v = decl.brushValue(); break; #ifndef QT_NO_SHORTCUTcase QMetaType::QKeySequence: v = QKeySequence(decl.d->values.at(0).variant.toString()); break; #endifdefault: v = decl.d->values.at(0).variant; break;}w->setProperty(property.toLatin1(), v);} }漸變色解析
//E:\Qt\qt-everywhere-src-5.15.0\qtbase\src\gui\text\qcssparser.cpp
static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) {ColorData c = parseColorValue(v);if (c.type == ColorData::Color) {return QBrush(c.color);} else if (c.type == ColorData::Role) {return c.role;}if (v.type != Value::Function)return BrushData();QStringList lst = v.variant.toStringList();if (lst.count() != 2)return BrushData();QStringList gradFuncs;gradFuncs << QLatin1String("qlineargradient") << QLatin1String("qradialgradient") << QLatin1String("qconicalgradient") << QLatin1String("qgradient");int gradType = -1;if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)return BrushData();QHash<QString, qreal> vars;QVector<QGradientStop> stops;int spread = -1;QStringList spreads;spreads << QLatin1String("pad") << QLatin1String("reflect") << QLatin1String("repeat");bool dependsOnThePalette = false;Parser parser(lst.at(1));while (parser.hasNext()) {parser.skipSpace();if (!parser.test(IDENT))return BrushData();QString attr = parser.lexem();parser.skipSpace();if (!parser.test(COLON))return BrushData();parser.skipSpace();if (attr.compare(QLatin1String("stop"), Qt::CaseInsensitive) == 0) {QCss::Value stop, color;parser.next();if (!parser.parseTerm(&stop)) return BrushData();parser.skipSpace();parser.next();if (!parser.parseTerm(&color)) return BrushData();ColorData cd = parseColorValue(color);if(cd.type == ColorData::Role)dependsOnThePalette = true;stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));} else {parser.next();QCss::Value value;(void)parser.parseTerm(&value);if (attr.compare(QLatin1String("spread"), Qt::CaseInsensitive) == 0) {spread = spreads.indexOf(value.variant.toString());} else {vars[attr] = value.variant.toReal();}}parser.skipSpace();(void)parser.test(COMMA);}if (gradType == 0) {QLinearGradient lg(vars.value(QLatin1String("x1")), vars.value(QLatin1String("y1")),vars.value(QLatin1String("x2")), vars.value(QLatin1String("y2")));lg.setCoordinateMode(QGradient::ObjectBoundingMode);lg.setStops(stops);if (spread != -1)lg.setSpread(QGradient::Spread(spread));BrushData bd = QBrush(lg);if (dependsOnThePalette)bd.type = BrushData::DependsOnThePalette;return bd;}if (gradType == 1) {QRadialGradient rg(vars.value(QLatin1String("cx")), vars.value(QLatin1String("cy")),vars.value(QLatin1String("radius")), vars.value(QLatin1String("fx")),vars.value(QLatin1String("fy")));rg.setCoordinateMode(QGradient::ObjectBoundingMode);rg.setStops(stops);if (spread != -1)rg.setSpread(QGradient::Spread(spread));BrushData bd = QBrush(rg);if (dependsOnThePalette)bd.type = BrushData::DependsOnThePalette;return bd;}if (gradType == 2) {QConicalGradient cg(vars.value(QLatin1String("cx")), vars.value(QLatin1String("cy")),vars.value(QLatin1String("angle")));cg.setCoordinateMode(QGradient::ObjectBoundingMode);cg.setStops(stops);if (spread != -1)cg.setSpread(QGradient::Spread(spread));BrushData bd = QBrush(cg);if (dependsOnThePalette)bd.type = BrushData::DependsOnThePalette;return bd;}return BrushData(); }?
總結
- 上一篇: Badi开发步骤
- 下一篇: 网络流量监控软件——MRTG(Multi