QT: setStyleSheet from a resource QSS file? - qt

In my widget, I can do something like that:
MyWindow::MyWindow(QWidget *parent) :
QWidget(parent)
{
ui.setupUi(this);
setStyleSheet("QWidget { background-color: red }"); // <--- HERE
}
This will set the widget background red.
I have a QSS file in my resources. How do I instruct my widget to take its style sheet content from there, vs just taking the qss syntax as parameter?

As an alternative to setting a style sheet for each widget, you can just load and set a stylesheet for a whole application. Something like this:
QApplication app( argc, argv );
// Load an application style
QFile styleFile( ":/style.qss" );
styleFile.open( QFile::ReadOnly );
// Apply the loaded stylesheet
QString style( styleFile.readAll() );
app.setStyleSheet( style );
In this case all widgets will pick their styles from the given stylesheet automatically.

Got it: you actually have to "read the file" from the resources, convert it to a QString and feed it to the setStyleSheet. E.g.:
QFile file(":/qss/default.qss");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
setStyleSheet(styleSheet);

Related

Qt set default value for style-sheet property

I have an application where users can modify the Qt stylesheets. I want to set default value for some property in case the user-provided stylesheet does not define them, e.g.
// user provided style sheet for the whole app
qApp->setStyleSheet("file://user-provided.qss");
// default value for my button
myButton->setStyleSheet("color: red"); // I'd like this to apply only if the stylesheet does not provide it
The way Qt cascading works, setting the stylesheet on the widget override anything from the application style-sheet, even if the specifier on the application stylesheet are stronger.
I tried using QPalette, or different foreground roles with custom color in the .ui, but nothing worked. Unless I use setStyleSheet, the foreground color does not change (as expected since QPalette is ignored when a stylesheet is used).
Is there a way to have a default value in case a property is missing from the application stylesheet? Basically reverse the cascading effect of Qt?
You can set the "default" stylesheet with all needed style rules on the QApplication instance (for the whole application) and the "user" stylesheet on the top level widget.
So the stylesheet set on the top level widgets extends and overrides the application stylesheet.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget widget;
auto label_1 = new QLabel(&widget);
label_1->setObjectName(QString::fromUtf8("label_1"));
label_1->setText("Label 1");
auto label_2 = new QLabel(&widget);
label_2->setObjectName(QString::fromUtf8("label_2"));
label_2->setText("Label 2");
auto layout = new QVBoxLayout(&widget);
layout->addWidget(label_1);
layout->addWidget(label_2);
widget.setLayout(layout);
QString defaultStyle = "#label_1{color:red};"; // default for label_1
QString userStyle = "#label_2{color:blue};"; // rule for label_1 is missing
app.setStyleSheet(defaultStyle); // set the default stylesheet on the application
widget.setStyleSheet(userStyle); // set the user stylesheet on the top level widget
widget.show(); // label 1 has blue color and label 2 has red color
return app.exec();
}

Problems while using gtk+3 and Css

I am using C language to create a GUI with GTK+3 and I want to make the style of the app with CSS. The problem is that the widget doesn't accept the style that I gave to them, unless I use the * selector in my CSS file. At first time I try to make a single CSS file for all the app using gtk_style_context_add_provider_for_screen() but that didn't work. So I tried to set the style widget by widget using a function :
void SetStyleWidget (GtkCssProvider *CssProvider, char *Path, GtkWidget *Widget)
{
gtk_css_provider_load_from_path (CssProvider, Path, NULL);
gtk_style_context_add_provider (gtk_widget_get_style_context(Widget), GTK_STYLE_PROVIDER(CssProvider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
gtk_style_context_save (gtk_widget_get_style_context(Widget));
}
This don't work either. I also see that it could be a priority problem but no matter what priority I add it doesn't work. Do someone got an answer to my problem?
Here's my c file and my css :
#include <stdlib.h>
#include <gtk/gtk.h>
#include <gmodule.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "RandFuncGTK.h"
int main(int argc, char **argv)
{
GtkWidget *pWindow;
GtkWidget *pBoxLevel0;
GtkWidget *pTitreImg;
GtkWidget *pBoiteTitreImage;
GtkWidget *pLabTest;
GtkCssProvider *CssProvider;
gtk_init(&argc, &argv);
CssProvider = gtk_css_provider_new ();
pWindow = CreateWindow(pWindow, "Test", 1000, 1000);
pBoxLevel0 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 100);
gtk_container_add(GTK_CONTAINER(pWindow), pBoxLevel0);
pLabTest = gtk_label_new("Test");
SetStyleWidget(CssProvider, "css/labstyle.css", pLabTest);
gtk_container_add(GTK_CONTAINER(pBoxLevel0), pLabTest);
gtk_widget_show_all(pWindow);
g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return EXIT_SUCCESS;
}
Here's my css file
GtkLabel {
color: blue;
}
GTK stopped using widget type names as CSS node names in version 3.18 or so, and from then on, you have to check the C class documentation to see what node names, classes, and so on are available to theme. In this case, it would be
label { [...] }
I also recommend loading the StyleContext to the Display, not individual widgets. So, basically, use a modern version of GTK (ideally latest point 3.24.x, but at least 3.22) and the documented CSS selectors, and you're good to go.
Once doing that, if you only want to affect individual widgets, then just add CSS classes to them and select on those classes:
gtk_style_context_add_class(my_label_style_context, "the-precious");
and then select in CSS on
label.the-precious { [...] }
or just
.the-precious { [...] }
A fuller example is available in this other answer.
That is better than adding StyleContexts to individual widgets because doing that tends not to work how users expect (in terms of inheritance and such).
You can also set CSS IDs on widgets (like #the-precious), but that is less often used and IMO not really needed in GTK and more of a faff to set up IMO.
Note that the default GTK theme, Adwaita, was refreshed during 3.24 - so if you want to theme your application against that, it's best to do so from the latest available version of 3.24 - and hope it doesn't change again in 3.x...

QLabel change font color without changing any other style

I want to change the color of the text in a QLabel dynamically.
I have defined the color and style of the QLabel in the ui file and I want to change it when a certain event takes place.
I want to change the color without changing any other style of my QLabel.
I have found several answers adressing the issue of changing text color in a QLabel (1, 2, 3) and they all use the function setStyleSheet. This function works fine but it changes my font size and other styles related to the QLabel.
I have seen that the problem is related to setStyleSheet ignoring any previous style. The solution proposed there involves retrieving all the styles I want to maintain and setting them again together with the text color change.
This is cumbersome and difficult to maintain. If more styles were defined in the future I would need to review this part of the code to be able to reset all of them.
I would like to be able to change QLabel text color without altering any other syle. Is it possible?
If you want to manage the text color of QLabel you could wrap it with customized class.
For example:
class ColorLabel : public QLabel
{
public:
ColorLabel(const QString &text, QWidget *parent = nullptr)
: QLabel(text, parent)
{
setAutoFillBackground(true);
}
void setTextColor(const QColor &color)
{
QPalette palette = this->palette();
palette.setColor(this->backgroundRole(), color);
palette.setColor(this->foregroundRole(), color);
this->setPalette(palette);
}
};
And to use it in your code:
ColorLabel * poColorLabel = new ColorLabel("My string", this);
poColorLabel->setTextColor(Qt::red); // set label text in red color
FYI: I tested it on Fedora, Qt5.12 and it works fine.
A pragmatic approach:
Utilize the cascadingness of CSS.
Wrap your QLabel in a QWidget (don't forget a QLayout).
Set your default style on the surrounding QWidget.
Set the font color as the QLabel's only style.
You can create some style class to control a widget's style:
class WidgetStyleSheet
{
public:
// change some style's value
void setValue(const QString& styleKey, const QString& value)
{
_styleMap[styleKey] = value;
}
// to default state
void reset() {}
// form stylesheet
QString toStyleSheet() const
{
QString styleSheet;
QMapIterator<QString, QString> iter(_styleMap);
while( iter.hasNext() )
styleSheet += QString("%1: %2").arg(iter.key()).arg(iter.value());
return styleSheet;
}
private:
QMap<QString, QString> _styleMap;
}
Somewhere in your code:
WidgetStyleSheet labelSS;
// ...
labelSS.setValue("color", QString("%1").arg( QColor(255, 10, 0).name() );
labelSS.setValue("background-color", "...");
// ...
label->setStyleSheet(labelSS);
The following works fine. But it is not that elegant. This is in python. You have to pass the button name (or any other) to the following as is defined in the array
btns = ['self.hBeamBtn','self.lBeamBtn','self.allTestBtn','self.prnStatusBtn']
for btn in btns:
if str(btn_name) == str(btn):
styl = btn+'.setStyleSheet("font: bold;background-color: red;font-size: 12px;height: 28px;width: 80px;")'
eval(styl)

styling text regions with class selector from global QSS

How can I style a span that is part of a widget text (e.g.
a QLabel) via global style sheet?
E.g. in below example, both foo and bar should be red.
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
class
some_label : public QLabel
{
Q_OBJECT
public:
some_label(QString text = "") : QLabel(NULL) {
setText(text);
show();
};
};
#include "main.moc"
static const char *css =
"some_label { color : blue; background : black; }"
"span.some_class { color : red; }";
int
main(int argc, char **argv)
{
QApplication a(argc, argv);
a.setStyleSheet(css);
some_label label("before "
"<span style=\"color:red;\">foo</span> " /* works */
"<span class=\"some_class\">bar</span> " /* fails */
"after");
return a.exec();
}
Qmake (Qt 5.1.1) project file:
QT += widgets
SOURCES += main.cpp
I would really appreciate a solution that avoids hardcoding the style as I did
with the foo span.
The goal is for the application look to be determined entirely by a
user-supplied style sheet (represented by css in the example).
At the moment I use a workaround involving separate labels for each element
that is colored and it is a nightmare to maintain.
I have consulted a few online sources as well as Blanchette/Summerfield chapter
19 but those are primarily concerned with styling whole widgets.
If you don't need to change styling after the QLabel loads, you could devise a system where you text-replace the colors you want for each word from a centralized style file:
// These values come from a central, user-supplied style sheet, etc.
QString primary = "red";
QString secondary = "green";
some_label label("before "
"<font color=\"" + secondary + "\">foo</font> "
"<font color=\"" + primary + "\">bar</font> "
"after");
This system is a little hard to read but it could be an improvement over using many QLabels.
(As you may have noticed, Qt doesn't support CSS selection of classes within QLabels.)

Qt StyleSheet custom style attribute custom QGLwidget

I have created a subclass of QGLwidget and I was hoping that I could use a stylesheet to tell openGL how to render a scene.
For Example:
qApp->setStyleSheet("CustomWidget { background-color: yellow }");
Then in my paintGL method:
QColor bg = "Get 'background-color' style somehow"
glClearColorf(bg.redF(), bg.greenF(), bg.blueF(), 0);
glClear(GL_COLOR_BUFFER_BIT)
Also, is it possible to create custom style sheet attributes?
qApp->setStyleSheet("CustomWidget { foo-attr: 1 }");
I have read up on the QStyle and QStyleOption classes, but I don't quite understand how to apply them to a practical application.
You can declare Q_PROPERTY in your custom widget and then set them with
CustomWidget
{
qproperty-yourPropertyName: "value";
}
You can access BG of your custom widget with QPalette
QColor bg = palette().color(QPalette::Window);
But I'm not sure if it will work

Resources