I have a program that can load plugin modules and these plugin modules I don't have much control over (outside of instructing customers about guidelines on how to create their modules).
I'm, however, trying to create some Style Themes (e.g. 'lightTheme' and 'darkTheme') for my application that I'd also like to propagate to any UI elements that may be created in any plugins.
Here's my problem, in one of the plugins I noticed that a bare QWidget (e.g. QWidget *widget = new QWidget(); was created that has no parent and I'm trying to figure out how to style this window.
Qt in this case treats this view kind of like a QDialog, however in the stylesheet I need to use QWidget to style this view (QDialog doesn't do anything). As you might expect adding style to QWidget (e.g. QWidget { background-color: black; } with cause a whole host of other style changes throughout my program that I don't want.
So what I'm looking for is how to "style a QWidget that doesn't have a parent".
I was expecting to do something like:
parent > QWidget { background-color: black; }
But I can't figure out what to put for the 'parent' since I know this widget has no parent.
Any help would be appreciated.
Related
I created a button in Qt and gave it the QSS attribute background-color: gray;, while my external stylesheet has set the QSS attribute of the same button to background-color: blue;. When I run the application the button is gray, even though the style sheet is applied after the QWidget::show() is called and just before QApplication::exec(), as shown below:
MyWidget w;
w.show();
...
app.setStyleSheet("..."); // contents of external stylesheet
return app.exec();
Is it possible to have QApplication::setStyleSheet() override the QSS attributes assigned to a Widget in Qt.
No, it is not possible to override the QSS attributes the way you want, and trust me, you don't want to. It is not the order in which you call setStyleSheet that matters. It is the hierarchy that matters first. The call order matters only on widgets which are situated on the same level of the hierarchy.
The reason is that the widget has its internal style rules defined which override the parent's style thus the application style in your case. It is a hierarchy that is respected. You can look at this in the following way:
Say you have a QWidget with the following child hierarchy:
QWidget
|__QPushButton
|
|__QFrame
| |
| |_QListView
|
|__QProgressBar
Let's say you want to customize the background-color to all the widgets in your hierarchy. If the call to QApplication::setStyleSheet() would overwrite the stylesheet properties for the children, it would be impossible for you to set a custom style for your children. That's why child widget's QSS properties overwrite parent widget's QSS properties.
Look at it like the usual way to look at widgets. QPushButton is shown on top of QWidget. QFrame is shown on top of QWidget. QListView is also shown on top of QWidget. Styles apply the same way.
What I recommend doing is having only one external QSS file in which you define everything you want.
EDIT:
As N1ghtLight pointed out QSS preserves the class inheritance hierarchy so if you set a property for a class all its derived classes will inherit that property. For example if you have the following stylesheet:
QAbstractButton {
background-color: red;
}
QPushButton {
color: blue;
}
All QPushButtons will have the background color red and the text color blue as the QPushButton inherits the background-color property value from QAbstractButton which is its ancestor while QAbstractButtons which are not QPushButtons will have the background color red but the text color will remain unchanged.
The example above used a type selector. You can apply the style to specific objects by using different selector types. You can see different selector types here.
I know that QML does not support CSS styling like widgets do, and I have read up on alternative approaches to styling/theming:
https://qt-project.org/wiki/QmlStyling
http://www.slideshare.net/BurkhardStubert/practical-qml-key-navigation/34
Common for these approaches is that they require the developer to specify the parts of the QML that can be styled, either by binding to a property in a “styling QML file/singleton”, or by using a Loader to load a different QML component based on style name. What I would like is something that works like the "id" selector in CSS instead of the "class" selector, so that the individual QML files do not have to know whether they will be styled later on or not.
My current approach make all the QML files look similar to this (using approach in link 2):
Main.qml
Rectangle {
Id: background
color: g_theme.background.color
//g_theme is defined in root context and loaded dynamically
}
What I would like to do is:
Main.qml
Rectangle {
Id: background
color: “green” // default color
}
And then have a styling file that defines (or similar)
Main.qml #background.color: red
Is this possible at the moment, or something that is in the pipeline for a future Qt version, or will the preferred way of styling continue to be something similar to the approach described in the links above?
The preferred way isn't applying a style on default components, but deriving from these components to create pre-styled custom components.
What I do for my projects :
First, I create one centralized 'theme' file, as a JavaScript shared module :
// MyTheme.js
.pragma library;
var bgColor = "steelblue";
var fgColor = "darkred";
var lineSize = 2;
var roundness = 6;
Next, I create custom components that rely on it :
// MyRoundedRect.qml
import QtQuick 2.0;
import "MyTheme.js" as Theme;
Rectangle {
color: Theme.bgColor;
border {
width: Theme.lineSize;
color: Theme.fgColor;
}
radius: Theme.roundness;
}
Then, I can use my pre-styled component everywhere with a single line of code :
MyRoundedRect { }
And this method has a huge advantage : it's really object-oriented, not simple skinning.
If you want you can even add nested objects in your custom component, like text, image, shadow, etc... or even some UI logic, like color-change on mouse hover.
PS : yeah one can use QML singleton instead of JS module, but it requires extra qmldir file and is supported only from Qt 5.2, which can be limiting. And obviously, a C++ QObject inside a context property would also work (e.g. if you want to load skin properties from a file on the disk...).
It could also be helpful to look at Qt Quick Controls Styles
When using Controls Styles it is not necessary to explicitly assign each property in the target control. All properties can be defined in a separate [ControlName]Style component (e.g. ButtonStyle).
Then in target component (e.g. Button) you can just reference to style component in one line of code.
The only one downside here is that Style components are available for Qt Quick Controls only. Not for any Qt Component.
In my application, a User clicks on any widget of my program (which are at the time; dormant) and picks a color for it.
This color will then be added to a stylesheet for that particular widget.
However, when the program ends and is started again, I would like that particular widget to retain its stylesheet.
I would like to not have to hard code in stylesheets for every widget. In fact, I'd rather not even know which particular widget is having the stylesheet.
What I'd really like to do is have a single style sheet for the application, and code the new color just to the particular widget clicked.
(ie: If the User clicked on a QPushButton and chose a stylesheet of { color: red},
I would like just THAT QPushButton red and none others.
So, if that QPushButton had a variable name of 'Clicky',
to the QApplications stylesheet I would add:
'QPushButton#Clicky { color: red }' )
To do this and not have to hard-code it in for every widget,
I must somehow convert the variable name of my PyQt4 widgets to strings.
How can I do this?
Thanks!
(I've read it can be extremely difficult to get python variable names from their values;
Is there any other form of ID for a widget that can be added to a stylesheet?)
PyQt4
python 2.7.2
Windows 7
You need to first setObjectName("somename") before an object is named, then objectName() will work, or even better - findChild(), or findChildren()
Example
header:
QButton foo;
class:
foo = new QButton();
foo.setObjectName("MySuperButton");
Then, finally in your QSS..
#MySuperButton {
background: black;
}
This also works similarly to CSS with
QButton#MySuperButton {
background: red;
}
The logic behind why you'd want to set multiple object names similarly (for different objects), or use the granularity of only one type of widget with a specific name is also pretty much the same as CSS.
When adding a QComboBox control in Qt Designer, I get a terrible looking, non-native control:
On digging further, it turns out that two of the parent controls, QParentWindow and QStackedWidget, have style sheets that QComboBox is inheriting. If I delete the custom styles, then I get a native QComboBox like the one on the left.
How can I have QComboBox (and widgets generally) NOT inherit parent styles? Or, how can I create a style for, say, QParentWindow, and do it so that it's local only and does not cascade?
I don't think you can prevent it from cascading. But by using more specific selectors in your stylesheet, maybe you could define properties only for your QParentWindow class or specific object.
you need to define a style and then assign it to that object:
QString settingStyle = " QGroupBox#groupBoxSettings {\
background-color: rgb(248,248,248);\
border: 1px solid rgb(170, 170, 255);\
border-radius: 3px;\
border-color:rgb(170, 170, 255);\
}";
ui->groupBoxSettings->setStyleSheet(settingStyle);
here "groupBoxSettings" is the object name. This way any thing inside the groupbox they'll have their own style.
I have a class that inherits QStandardItem and I put the elements in a QTreeWidget. The class receives notifications from the outside and I want to change the background color of the item based on what happened.
If I do not use stylesheets, it works just fine, like this:
void myClass::onExternalEvent()
{
setBackground(0, QColor(255,0,0)));
}
However, as soon as I put a stylesheet on the QTreeWidget, this has no effect : the stylesheet seems to override the setBackground() call.
So I tried :
void myClass::onExternalEvent()
{
this->setStyleSheet("background-color: red");
}
but this is probably all wrong, it changed the color of some other element on my screen, not sure why.
Does anyone have an idea on how I can alter the background color like with setBackgroundColor but still be able to use stylesheet on my QTreeWidget?
Palettes propagate to the children of a widget, and it's bad to mix and match style-sheet controls and native controls (I do not have a citation for the latter handy, but I have read it in the QT docs somewhere).
That being said, try setting setAutoFillBackground(false) on your QStandardItem derived class.
EDIT: Sorry - also, are you specifying the QTreeWidget in the stylesheet or just setting "background-color:"? If you specify the QTreeWidget only in the stylesheet that might take care of it as well.
QTreeWidget { background-color: white; }
But I think you still have to set the autoFillBackground(false).