Get variable name of Qt Widget (for use in Stylesheet)? - qt

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.

Related

PyQt styling with QSS & #pyqtProperty

As a simple example, suppose I have a QPushButton that has some basic styling applied to it using button.setStyleSheet(). Additionally, I want some parts of the style (background color) to change in response to events triggered by the user.
I could simply make calls to button.setStyleSheet() throughout my code, but these will erase pre-existing style attributes. So I would not be able to edit just one styling attribute in response to some signal, rather I would have to specify all style attributes every time the style changes (even if only one or a few style attributes are actually being modified).
I understand this can be done more neatly with the QSS property selector which can apparently be used with "any Qt property that supports QVariant::toString()". This is also described for C++ here: dynamic properties & stylesheets.
So suppose I have a custom widget class, and I want some of its styling to depend (responsively) on a property of my custom class, e.g. a state property. It sounds like I should be able to do something like
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import pyqtProperty
class StatefulWidget(QPushButton):
""" QPushButton colored to reflect its state. """
def __init__(self, state=0):
super().__init__()
self.state = state
self.setStyleSheet('''
StatefulWidget[state=0] {
background-color: red;
}
StatefulWidget[state=1] {
background-color: green;
}
''')
#pyqtProperty(int)
def state(self):
return self._state
#state.setter
def state(self, state):
# Register change of state
self._state = state
# Update displayed style
self.style().polish(self)
but this does not work for me.
Can anyone suggest the proper way to make this work? The intended behavior is that the style should be updated whenever the property changes, but the underlying CSS/QSS should be fixed.
Related:
Update stylesheet without losing original style
The documentation about the QSS property selector says:
You may use this selector to test for any Qt property that supports QVariant::toString()
The QSS parser code is quite complex and somehow cryptic, and I've never been able to completely follow its logic, but I believe that it always tries to convert string values to numbers whenever they contain digits, so the 0 value for the QSS property selector will not match the "0" resulting from toString().
As a general rule, always use quotes around values:
self.setStyleSheet('''
StatefulWidget[state="0"] {
background-color: red;
}
StatefulWidget[state="1"] {
background-color: green;
}
''')

Dynamically change JavaFX properties for specific classes in CSS

I am writing code that allows a user to build a theme for the application, so they need to be able to effectively communicate that they want to change something about some element of JavaFX.
Suppose I have a bar on the top of every view that lets a user change the way some set of things look: button, label, text, and so on.
Here is a basic stylesheet that I am working with. It just puts style on root and button.
basetheme.css
.root {
-fx-background-color: "teal";
}
Button {
-fx-background-color: "orange";
-fx-font-size: 2em;
-fx-text-fill: #0000ff
}
Right now, all the views I have would load this sheet each time they are loaded:
view.getStylesheets().add("views/basetheme.css");
The Button class and its fx properties here would apply to all buttons in the view.
This is the behavior I want. I want the user to have leverage over Button and its properties during runtime.
For instance, if they want to change Button's -fx-font-size property from -fx-font-size: 2em to -fx-font-size: 3em, they can do that. Is this possible?
Currently, I know setStyle will set properties on some elements, but I am looking for a way to do this for not just a single Button, Label, and so on, but for all them. I want there to be run-time changes. For instance, after a user changes some element like button and one of its properties, it reloads that view and the change is applied.
I want to do something like view.setStyle("Button: some properties") and then it add those properties to Button class or overrides it, instead of view.setStyle("some properties") adding properties to root. The latter would not recognize that the property goes on a button, let alone all Buttons in view.
The obvious reason why this might not work this way is that we are not really changing the css file when we do those inline setStyle calls, just setting over the existing property and thus that inline has higher precedence and is updated.
I know I could technically do somebutton.setStyle("some properties"), but I want the user to be able to modify properties for all Button elements by specifying it at the root of a view so the styles trickle down to subelements in the view. This makes things easier.
You could use CSSFx to constantly pull in a CSS file that has bee written by your app.

Qt stylesheet selector using enumed properties

I'm trying to set different visual styles for a pressed QToolButton depending on whether it displays a menu or not.
In my code, tool buttons having menu set their popupMode property to QToolButton::InstantPopup (value 2), while buttons without an associated menu keep the default value (QToolButton::DelayedPopup, value 0).
I tried to use such property in different ways as selector, but only the last one (QToolButton[popupMode="2"]) worked:
/* Not working */
QToolButton[popupMode=InstantPopup]:pressed,
QToolButton[popupMode="InstantPopup"]:pressed,
QToolButton[popupMode="QToolButton::InstantPopup"]:pressed,
QToolButton[popupMode="QToolButton--InstantPopup"]:pressed,
QToolButton[qproperty-popupMode=InstantPopup]:pressed,
QToolButton[qproperty-popupMode="InstantPopup"]:pressed,
QToolButton[qproperty-popupMode="QToolButton::InstantPopup"]:pressed,
QToolButton[qproperty-popupMode="QToolButton--InstantPopup"]:pressed,
QToolButton[qproperty-popupMode="2"]:pressed
{
background-color: blue;
}
/* Working */
QToolButton[popupMode="2"]:pressed,
{
background-color: red;
}
(This is a compilation of the options, I've tested them separately).
Documentation mentions that if the enum is declared using Q_ENUM (as ToolButtonPopupMode does), then it should be referenced by name, not by value, but, as it can be seen above, it seems it is not the case for selectors.
Question: Would it be possible to use such enum's name as selector in the stylesheet instead of the enum's value?
Note: I understand that other options such as custom properties with a more expressive, Qt-independant value can make the work too. I'm curious about the possibility of using the enum in the described way.
QToolButton[popupMode=InstantPopup]:pressed is the correct one.
setProperty(<property_name>, QVariant::fromValue(<enum_value>)) for enum class.
setProperty(<property_name>, <enum_value>) for enum.
But you need to reload the style if you want it to change dynamically.
Read about QStyle::unpolish and QStyle::polish.

Adding new stylesheet parameters for custom Qt widgets

I would like to add stylesheet options for a custom widget I have developed. We have extended the QPushButton to be a different colour and to flash when it is depressed. This has been done by adding a new property, background color down. And we set this in code. But I would like to set this instead using a Qt stylesheet entry, something like
QFlashingButton
{
background-color-down: yellow;
flashing-interval: 5;
}
I can see one way to do this, read out the stylesheet info using the stylesheet() method, then parse it for parameters relevant to my widget and set them. But I am wondering if there is some way to access the code Qt have themselves for processing stylesheets. At first sight of their code this seems perhaps not to be publically available.
As long as the parameter you want to control in the stylesheet is a QProperty, you can set it in the stylesheet using the syntax: qproperty-<PROPERTY_NAME>: <PROPERTY_VALUE>
I don't think property names can actually have dashes in them, so assuming your QProperties on your custom widget are actually backgroundColorDown and flashingInterval, then your stylesheet would look like:
QFlashingButton
{
qproperty-backgroundColorDown: yellow;
qproperty-flashingInterval: 5;
}

Qt: Background color on QStandardItem using StyleSheet

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).

Resources