Qt: Style depending on label value - qt

I have what looks like a very simple problem: I want to design a QLabel whose value changes dynamically (no issue here) and whose background color changes accordingly (this is the issue).
Of course, I know I can do something like that (pseudo code):
function on_new_value(value):
label.setText(value)
if value>10:
label.setBackgroundColor(RED)
else if value<0:
label.setBackgroundColor(RED)
else:
label.setBackgroundColor(GREEN)
But that kind of mixes model and view. What I'd like, ideally, would be to be able to use an extended version of Qt Stylesheets as follows:
QLabel { background: green; }
QLabel { if value>10: background: red; }
QLabel { if value<0: background: red; }
Obviously, that is not possible. But I'm wondering if Qt allows for something close in order to embbed (for instance in a class) a graphic behaviour based on a value.
I know about QPalette, but the style condition is only about the widget Active/Disable state, not its "value".
In other words, I'm looking for sort of a ValueDependantStyle class or somehting close.
Any pointers? Am I looking at this all wrong?
Edit: in case this is important, I'm developping with PyQt5.

You could use a "model property" on the label, that defines the color in a style sheet (cf. Qt Style Sheet Reference about properties):
function on_new_value(value):
label.setText(value)
if value>10:
label.setProperty("HasError", "true")
else if value<0:
label.setProperty("HasError", "true")
else:
label.setProperty("HasError", "false")
QLabel[HasError="false"] { background: green; }
QLabel[HasError="true"] { background: red; }

Related

Why can't I use StyleSheet in QLineEdit object?

I have a class DragQLineEdit which inherits the QLineEdit.
I have defined an array as:
DragQLineEdit m_textEdits[FAVORITE_ROWS][FAVORITE_COLUMNS];
So I am able to generate a grid of edit text boxes. FINE.
But when I want to change the color say of the very first edit text box like this:
m_textEdits[0][0].setStyleSheet("QLineEdit { background: rgb(255,255,255); selection-background-color:rgb(233,0,0); }");
It gives me compiler error: no member named StyleSheet.
I did the above after reading the accepted answer of this question.
Basically, I have the following function:
void Favorites::mySlot(int r,int c,int row,int col)
{
m_sendButtons[r][c].setText(m_sendButtons[row][col].text());
m_sendButtons[row][col].setText("Send");
m_textEdits[r][c].setStyleSheet(m_textEdits[row][col].StyleSheet);
m_textEdits[row][col].setStyleSheet("QLineEdit { background: rgb(255,255,255); selection-background-color:rgb(233,0,0); }");
}
You have...
m_textEdits[r][c].setStyleSheet(m_textEdits[row][col].StyleSheet);
It should be...
m_textEdits[r][c].setStyleSheet(m_textEdits[row][col].styleSheet());
Note the lower case 's' in styleSheet and parentheses after styleSheet signifying a function call.

LESS mixins vs classes

I'm looking into LESS because I definitely see some of their benefits. For instance colour declaration.
One thing I don't understand tho, and maybe I'm not getting the flow right is - why use the following LESS snippet
.radius {
-webkit-border-radius:5px;
-moz-border-radius:5px;
border-radius:5px;
}
.btn-red{
background-color:red;
.radius;
}
.btn-green{
background-color:green;
.radius;
}
...
When we can use the .radius class in the html file right away. I'm left with the impression that LESS will add a ton of duplicate code once it gets compiled.
I'm using the following, which makes more sense. Same with font-size, margins, etc... Aren't classes used in such cases?
<div class="btn-red radius">Cancel</div>
<div class="btn-green radius">Go</div>
The snippet above does not benefit from SASS/LESS capabilities that much. Lets have a closer look and check this SCSS snippet.
// Abstract placeholder.
%radius {
border-radius: 5px;
}
// Put your global styling here.
// I'm assuming that you can alter the markup and have button.btn.btn-green
.btn {
// Color modifier.
&-red {
#extend %radius;
background-color: red;
}
&-green {
#extend %radius;
background-color: green;
}
}
The CSS output will be:
.btn-red, .btn-green {
border-radius: 5px;
}
.btn-red {
background-color: red;
}
.btn-green {
background-color: green;
}
And then you have to pick up Autoprefixer and vendor-prefixes issue is solved once and for all.
Because now, you can just specify the class btn_red or btn_green and all the buttons will automatically have a radius.
Your HTML should contain only the semantics, and styling or classes referring to styling should not be part of it.
That applies to the other classes as well. If for instance, you would rename btn_red to btn_cancel, you have a meaningful classname that you can apply to any kind of cancel button. And in the CSS you can specify that a cancel button is red and a 'Go' button is green, and both have a radius, without needing to modify the HTML at all.
So, the ultimate goal is to have the HTML describe the structure and the CSS describe how that structure should look. And a CSS preprocessor is only their to make a bulky spaghetti-like CSS file more structured.
There are several benefits.
You can use more semantic class names. Rather than encoding style information directly in your class names, (btn-red, radius) you could use a single class that conveys the usage of the style, rather than its contents.
You can avoid repeating yourself.
#radius-size: 5px;
-webkit-border-radius:#radius-size;
-moz-border-radius:#radius-size;
border-radius:#radius-size;
You can parameterize it so that you'd be able to use different radiuses (radii?) in different contexts.
.radius(#radius-size) { ... }
Because there are cases that developer has-no-access or don't-want to change the markup. and the only solution is to include all props from a predefined class.
for example:
you have bootstrap loaded (then you already have .has-success and .has-error classes) and if you want to use HTML5's native form validation using input's :valid and :invalid states, you have to use JavaScript to add/remove success/error classes based on input's states. but with this feature of LESS you can include all props of success/error class inside input's states. the code for this example could be something like this:
#myinput {
&:valid { .has-success; }
&:invalid { .has-error; }
}

QSS properties for custom widget: How to implement hover and pressed states

I found this example on the web on how to implement custom properties accessible from QSS for custom QWidgets: https://qt-project.org/wiki/Qt_Style_Sheets_and_Custom_Painting_Example
Does anyone know how can I implement the widget so that I can have different colors for hover or pressed states?
Current stylesheet looks like this:
SWidget
{
qproperty-lineColor: yellow;
qproperty-rectColor: red;
}
I want to be able to have something like this:
SWidget:hover
{
qproperty-lineColor: blue;
qproperty-rectColor: green;
}
SWidget:pressed
{
qproperty-lineColor: orange;
qproperty-rectColor: violet;
}
Note: I know it is possible to implement mouse events and change the colors using qproperties specific to the mouse events, for example:
SWidget
{
qproperty-lineColor: yellow;
qproperty-rectColor: red;
qproperty-lineColor-hover: orange;
qproperty-rectColor-hover: violet;
}
but I would like to be able to make it work using the original qss/css way.
Regards!
When user hover or pressed widget, you should change some widget property. And make different QSS selector for that properties.
After change property you should make unpolish\polish of application styles.
qApp->style()->unpolish( this );
qApp->style()->polish( this );
Where "this" current window pointer. That "magic" code will help to have affect of appropriate QSS selector.

javafx barchart bar colors

I am trying to change the color of all the bars of a series in javafx barcharts.
See for example: http://docs.oracle.com/javafx/2/charts/bar-chart.htm:
All the bars for 2005 are in series3 and are painted in light blue.
I would like to paint them, say, in red.
The css has the .data<n>.chart-bar selectors, but they change the colors of all the bars
at the same position in all series, and not those of a same serie.
E.g. .data0.chart-bar would change all the colors for Austria.
Does anyone know a solution?
Oh.. I know I had this in here somewhere....
Aha! found it! change these properties to the colors you want, for your example, to change series3 it would be the .default-color2.chart-bar bit:
.default-color0.chart-bar { -fx-bar-fill: #f9d900; }
.default-color1.chart-bar { -fx-bar-fill: #a9e200; }
.default-color2.chart-bar { -fx-bar-fill: #22bad9; }
.default-color3.chart-bar { -fx-bar-fill: #0181e2; }
.default-color4.chart-bar { -fx-bar-fill: #2f357f; }
.default-color5.chart-bar { -fx-bar-fill: #860061; }
.default-color6.chart-bar { -fx-bar-fill: #c62b00; }
.default-color7.chart-bar { -fx-bar-fill: #ff5700; }
To help in the future, here's the link to caspian.css (default stylesheet for Java 7) and modena.css (default stylesheet for Java 8) which are perhaps the most useful files in javafx css land, ever. They list every default style that gets applied to javafx, and therefore, lists most (not all) of the properties you could ever want to override in javafx with your own .css Good luck!

Qt Stylesheet syntax: targeting a specific button, not ALL buttons

I have a window with two buttons.
I'd like to decorate each one with a different stylesheet. They both have different object names, of course, but it seems that only the generic QPushButton stylesheet selector works.
I tried:
QPushButton#myBtnObjectName1 {
/* style definitions */
}
QPushButton#myBtnObjectName2 {
/* style definitions */
}
Tried the same with replacing the # with a ., or having the #myBtnObjetNameX only. Nothing works. Just:
QPushButton {
/* style definitions */
}
Am I using a wrong syntax? Or is this simply impossible without deriving from QPushButton in code and using a separate class name for each?
To match instances using the objectName, you can also use the selector ^=. According to the standard:
[att^=val] Represents an element with the att attribute whose value
begins with the prefix "val".
Example in Qt:
QPushButton[objectName^="push"] { background-color: red; }
A QPushButton called pushButton would be matched, but not an object called pbt.
You can use "accessibleName" in Qt Designer for this.
And in qss stylesheet:
more universal:
[accessibleName="alert-error"] {
color: red;
}
or be more specific:
QPushButton[accessibleName="bigred"] {
background-color: red;
}
Ah yes, the "AccessibleName" in Qt Designer needs to be set too, not just "ObjectName"

Resources