Stylesheet for a subset of widgets
-
Hi,
I am trying to apply a stylesheet to a subset of widgets but can't find a easy way to do so.
For simplicity imagine I have 20 text labels, 10 of them should have the same style, what would be the easiest way to achieve this?
One suggestion I found was to apply dynamic property to those similar widgets and the use this syntax QLabel[propertyRole="propertyName"] {}, but I can't easily copy/paste dynamic properties to multiple widgets in qt designer.
What would be the most optimal solution? For context, I develop with PySide6 so Python examples would be preferred.
Thanks.
-
Derive from QLabel and style the new class instead QLabel. Or set the stylesheet directly to the specific objects.
-
Use specific objectName prefix.
For example, name all the labels as "labelFormat1", "labelFormat2".
Then add the stylesheet in the parent widget: QLabel[objectName^="labelFormat"] {} -
-
Use specific objectName prefix.
For example, name all the labels as "labelFormat1", "labelFormat2".
Then add the stylesheet in the parent widget: QLabel[objectName^="labelFormat"] {}@Bonnie said in Stylesheet for a subset of widgets:
Then add the stylesheet in the parent widget: QLabel[objectName^="labelFormat"] {}
Hi Bonnie. I have used dynamic properties in Qt stylesheets in the past. The documentation is incredibly tricky to find, the vital piece of information is buried/mentione d just once at https://doc.qt.io/qt-6/stylesheet-syntax.html#selector-types. I don't understand where you get your
objectName^="labelFormat"
syntax from? I guess it must work because @irakli has said thanks to you. But the only suntax of which I am aware is, per the link,objectName~="labelFormat"
, so where is^=
rather than~=
documented, please? -
@Bonnie said in Stylesheet for a subset of widgets:
Then add the stylesheet in the parent widget: QLabel[objectName^="labelFormat"] {}
Hi Bonnie. I have used dynamic properties in Qt stylesheets in the past. The documentation is incredibly tricky to find, the vital piece of information is buried/mentione d just once at https://doc.qt.io/qt-6/stylesheet-syntax.html#selector-types. I don't understand where you get your
objectName^="labelFormat"
syntax from? I guess it must work because @irakli has said thanks to you. But the only suntax of which I am aware is, per the link,objectName~="labelFormat"
, so where is^=
rather than~=
documented, please?@JonB Yes, it is not documented, actually
^=
is one of the substring matching attribute selectors in CSS3, but the Qt documentation only says "Qt Style Sheets support all the selectors defined in CSS2". I guess not all CSS3 selectors are supported.
So this is just something that I gave a try and found working. -
@JonB Yes, it is not documented, actually
^=
is one of the substring matching attribute selectors in CSS3, but the Qt documentation only says "Qt Style Sheets support all the selectors defined in CSS2". I guess not all CSS3 selectors are supported.
So this is just something that I gave a try and found working. -
Derive from QLabel and style the new class instead QLabel. Or set the stylesheet directly to the specific objects.
@Christian-Ehrlicher said in Stylesheet for a subset of widgets:
Derive from QLabel and style the new class instead QLabel. Or set the stylesheet directly to the specific objects.
Would it not be better to aggregate a “style-aware” instance than to use inheritance? I am thinking of an Interface, of course, but would like to know why your approach should be preferable.
TIA.
-
@Christian-Ehrlicher said in Stylesheet for a subset of widgets:
Derive from QLabel and style the new class instead QLabel. Or set the stylesheet directly to the specific objects.
Would it not be better to aggregate a “style-aware” instance than to use inheritance? I am thinking of an Interface, of course, but would like to know why your approach should be preferable.
TIA.
@Simplicius-Simplicissimus said in Stylesheet for a subset of widgets:
Would it not be better to aggregate a “style-aware” instance than to use inheritance?
Well, first of all it is much easier to just inherit from a class and thus get all the member functions instead of forwarding each member function individually. (This will get a little easier with reflection eventually, but not necessarily in C++26, yet.)
The more important reason is that a label with some special styling still "is-a" QLabel. The "is-a" relationship is best modeled with inheritance and not composition. Furthermore, we are talking about Qt here: every single GUI element MUST inherit from QWidget (directly or transitively). Otherwise it will not work. Most important in this context is Liskov's substitution principle: Everywhere you expect a QLabel you can also provide your own new class for a styled label (more specifically in C++ we are using pointers or references to QLabel to avoid slicing). The default for this in C++ is inheritance. (In theory you could provide an
operator QLabel
which returns the underlying type.) OOP is not inherently bad; it is just not the silver bullet for every problem.To speak in the concepts of OOP and not its implementation in C++: What you really want here is subclassing. Other programming languages are using prototypes as its implementation. Or they are using dynamic typing as its implementation. A class in OOP (conceptually) is just all the objects that have the same behavior. It is just easy to define a type for a class which automatically makes all the instances of this type behave in the same way. Subclassing means that an object has the same behavior for the same message (in C++ we know messages as member functions), but it might add some more specific behavior on top of it. C++ has chosen to implement subclassing using inheritance: subclassing is the OOP concept, inheritance is the mechanism that C++ has chosen. This has all to do with dynamic polymorphism of types. In theory, you could also use generic code (which we call static polymorphism) to implement this. But, Qt has not chosen this path (and you cannot do everything with static polymorphism that you can do with dynamic polymorphism). So, inheritance is really the right choice here.
-
@SimonSchroeder : I see that my attitude originates from a time when I participated in the production of generated code and drafted documentation for a Design Pattern course. Mission statements like “Aggregation is better than Inheritance” left their mark.
Qt has nothing to do with that.
It would probably mean a long succession of trial-and-error sessions with lots of dynamic casts, would I try to replace any QWidget by my own Interface (although you can still call it a QWidget and talk to it like to a QWidget).
Thank you for your response, the best point is probably that I can still make sense of it, although my C++ knowledge has evaporated (still only) years ago.
P.S.: and ... where I write Interface, it should better be named an abstract Class, although they play the almost same role.
-
@SimonSchroeder : I see that my attitude originates from a time when I participated in the production of generated code and drafted documentation for a Design Pattern course. Mission statements like “Aggregation is better than Inheritance” left their mark.
Qt has nothing to do with that.
It would probably mean a long succession of trial-and-error sessions with lots of dynamic casts, would I try to replace any QWidget by my own Interface (although you can still call it a QWidget and talk to it like to a QWidget).
Thank you for your response, the best point is probably that I can still make sense of it, although my C++ knowledge has evaporated (still only) years ago.
P.S.: and ... where I write Interface, it should better be named an abstract Class, although they play the almost same role.
@Simplicius-Simplicissimus said in Stylesheet for a subset of widgets:
with lots of dynamic casts, would I try to replace any QWidget by my own Interface
There is no need for any casts if you want to pass an instance of a QWidget subclass where QWidget is expected.
-
@SimonSchroeder : I see that my attitude originates from a time when I participated in the production of generated code and drafted documentation for a Design Pattern course. Mission statements like “Aggregation is better than Inheritance” left their mark.
Qt has nothing to do with that.
It would probably mean a long succession of trial-and-error sessions with lots of dynamic casts, would I try to replace any QWidget by my own Interface (although you can still call it a QWidget and talk to it like to a QWidget).
Thank you for your response, the best point is probably that I can still make sense of it, although my C++ knowledge has evaporated (still only) years ago.
P.S.: and ... where I write Interface, it should better be named an abstract Class, although they play the almost same role.
@Simplicius-Simplicissimus said in Stylesheet for a subset of widgets:
I see that my attitude originates from a time when I participated in the production of generated code and drafted documentation for a Design Pattern course. Mission statements like “Aggregation is better than Inheritance” left their mark.
I know that currently there is a strong push against traditional OOP, especially inheritance. Inheritance is not a silver bullet and sometimes there are better solutions. But also, never using inheritance is also not a silver bullet. I'm not saying you should use inheritance instead of aggregation in general, but rather you should make an informed decision (instead of just blindly following rules like "Aggregation is better than Inheritance").
@Simplicius-Simplicissimus said in Stylesheet for a subset of widgets:
Qt has nothing to do with that.
Actually, Qt has something to do with that. Qt does not use interfaces/abstract classes. This is a design decision that was made and you have to conform to this with your own classes. Qt dictates that you MUST use inheritance instead of aggregation/composition. If you want to use Qt it is not your choice anymore (except for classes that don't directly interact with the Qt eco system).
As you have mentioned interfaces are implemented as abstract classes in C++. The mechanism is still inheritance to implement an interface. You gain nothing by using interfaces instead of just regular inheritance in C++. As I said before, you'd need to forward a lot of member functions when using aggregation. Nobody wants to write that much code! And with the design Qt has chosen you certainly don't need any dynamic_casts. Don't go through the trouble of rewriting Qt to use interfaces instead, just because of some stupid rule (most "rules" should actually be "guidelines"). BTW, the original design pattern book just collected patterns they observed in existing source code and gave them a name. The authors never said to force the patterns everywhere in your own code. If a pattern solves your problem–good, use it. But don't try to use as many patterns as possible. This was never the intention. Use them as guidelines.