Qt read dynamic qproperties in stylesheets - c++

I'm writing an application that contains widgets with different Qt-properties. One of these properties is a simple color-property:
Q_PROPERTY(QColor color GET color SET setColor NOTIFY colorChanged)
I would like to be able to access this property from within a stylesheet to change how the widget looks.
The stylesheet will be supplied by a user and cannot be dynamically created within the application.
I do not know what the user wants to make the application look like, but I want to give them the opportunity to set colors (and other properties) based on dynamic properties of the widget:
MyWidget {
border: 1px solid red;
background-color: <color property value>
}
In terms of color, according to the Qt documentation, the desired behaviour should be possible by accessing the widget's palette:
MyWidget {
border: 1px solid red;
background-color: palette(window);
}
However, as numerous people have already reported, this doesn't seem to be working as intended, since the stylesheet doesn't access the widget's own palette, but the application palette instead.
As mentioned in the Qt wiki, one can access dynamic properties by using either a selector for reading, or using qproperty- as a prefix for writing.
The stylesheet for writing a custom property looks like this:
MyWidget {
border: 1px solid red;
qproperty-color: red;
}
Reading a custom property using a property-selector looks like this:
MyWidget[color="red"] {
border: 1px solid red;
}
(note: i'm not sure if this selector would actually work, I haven't tried this with colors).
Now this would work for my case if I had a small set of possible colors.
However, my application computes a color dynamically, which would result in 2^24 (not counting alpha) colors.
Seeing that write access to properties can be obtained by using qproperty-color: <value>;, i'd have expected read access to be syntactically symmetrical:
MyWidget {
border: 1px solid red;
background-color: qproperty-color;
}
However, this doesn't work, hence me posting here.
Has anyone found any other way to access properties and using them in stylesheets to change the way widgets look without knowing the possible values beforehand?

I had a similar problem around a month back, and I also tried to solve it with StyleSheet but ultimately ditched the idea of using StyleSheet for QPalette.
Using StyleSheet to change the widget's look is a lot of work, especially if the widget is resizable. I would suggest using QPalette instead. However, with QPalette there is a catch: some styles, especially the default ones like window doesn't let you override all the properties of the palette of that style. I would suggest changing the default style of your application to fusion and using its palette in your application:
#include "mainWindow.h"
#include <QtWidgets/QApplication>
#include <QStyleFactory>
#include "start.h"
int main(int argc, char *argv[])
{
QApplication::setStyle(QStyleFactory::create("Fusion")); // Setting Fusion Style
QPalette light = QApplication::palette(); // Getting Fusion Style Palette
Start S(light); // Making Changes to the palette
QApplication A(argc, argv);
mainWindow W(&S, &A); // Passing the palette to main window so that you can change it dynamically
W.show();
return A.exec();
}
Using fusion style has many advantages:
Supports customization of almost all ColorGroup and ColorRole
Has a dark theme: FusionDarkTheme
Easier to maintain than StyleSheet
To be able to change the background of your widget you will also have to set it's autoFillBackground value to true otherwise its parent's background will override the widget's background. It's one of the reasons why you are unable to change the background color of your widget. You don't have to make the change individually for each widget, you can do it like this:
void mainWindow::setAutoBackgroundForWidget()
{
QList<QWidget *> widgets = this->findChildren<QWidget *>();
for(QWidget *wid : qAsConst(widgets))
{
QList<QByteArray> pro = wid->dynamicPropertyNames();
if(!pro.isEmpty())
{
for(QByteArray byt : qAsConst(pro))
{
if(byt == "Level")
{
wid->setAutoFillBackground(true);
}
}
}
}
}
The above function setAutoBackgroundForWidget() is a function created by me which I call before the end of the constructor of mainWindow. This function selects all widget, which has a dynamic property named "Level" to have its own background instead of using its parent's background. You can modify the above function accordingly to select the widgets that you need.
After you are done with the above, all that is left is to use QColorDialog to ask your users which color they need, copy the current palette and change the given ColorRole in it to the new color and apply the new palette to your widget using setPalette(). You can also do it in a single function inside your mainWindow cpp file for all your widget.
As for the StyleSheet, I can confirm that following works:
MyWidget[color="red"] {
border: 1px solid red;
}

Related

Qt QTabWidget background color

I have been trying to set the background color of a QTabWidget to black (or any other color for), but have been unsuccessful in doing so.
It seems that you need the option autoFillBackground set and then also set "background-color: black;" in the stylesheet. This then displays it properly in the Designer, but fails in the application.
This answer suggests to enclose it in another QWidget and then use the transparency, but that is a hack around the issue.
How do I set the background color of a QTabWidget via stylesheets?
EDIT
Setting QTabBar { background-color: black; } results in the following image.
As an alternative to QTreeWidget, use QTabBar + QStackedWidget and the following stylesheet
QTabBar { background-color: black; }
or use
Qt: Styling QTabWidget

How to set only QTabWidget background color stylesheet

I have a Qt application that, among many other widget types, uses a QTabWidget. I'm having difficulty styling the background color for this object.
I've tried some of the following lines, which I found from other forum posts, in my stylesheet with no effect on the program
QTabWidget { background-color: black; }
QTabWidget::pane { background-color: black; }
QTabWidget#tabWidget { background-color: black; }
QTabWidget#tabWidget::pane { background-color: black; }
If I use QWidget { background-color: black; }, then yes my color is properly changed, but then all of the other widgets in my program are changed as well... so this isn't what I'm looking for...
I've also tried it in code with ui->tabWidget->setStyleSheet("background-color: black"); But this too is undesirable because it changes the background color of all of its children widgets.
Does anyone have any other ideas on how to style a QTabWidgets contents background area?
About a year late but I recently ran into the same problem and got it working.
First of all QTabWidget has a child QWidget for every tab you make. That is the area that you put your other widgets into, and that is what you want to set the background color of.
Set the style-sheet by doing this.
1)Determine the name of your tab widgets from the design object window top right, they should match the currentTabName that you set when creating your tab.
2)Realize this is a QWidget not a QTabWidget this is why QTabWidget { background-color: black; } does not work.
3)Realize that by specifying the object in the style-sheet with the '#' the child object will not inherit the style-sheet.
For me I specified my style-sheet as such, repeating for each tab object name that I had:
#objectName {background-color: rgb(240,240,240);}
This provided me with the exact behavior I needed. In my case I wanted to get the natural gray background onto my Tab pages but not override the child components on the tab pages.
I hope this helps someone in the future...

Styling QListWidget item widgets: selected state

I have a window which displays tiles, each tile having some set of information. Tiles are arranged in a tabular structure. The way in which this is implemented is, a QListWidget is used to hold tiles and each tile is set as the item widget in QListWidgetItems in QListWidget.
I have styled the tiles using a stylesheet. My problem is, I cannot get a tile highlighted in some way when the tile is selected. If I do not use stylesheets at all, default selected highlighting works. But as soon as I apply styles to tiles, there is no difference in the tile in non selected and selected states.
I tried to do it in following way but it does not work.
.tile
{
/*non selected style*/
}
.tileList::item:selected
.tile
{
/*selected style*/
}
Any idea how I can achieve this?
I solved it in Qt Designer by setting the palette how I wanted it and then put
QListView::item:selected { background: palette(Highlight) }
as the styleSheet. Maybe this helps somebody.
If you want to do it from a central qss, I guess you'll have to remove the ".tile" part from the code in the question.
.tileList::item:selected
.tile <--- remove this line
{
/*selected style*/
}
I could get this done to some extent (not a comprehensive solution), by doing following.
Make tile widget semi transparent.
Set a background color to QListWidgetItem
Set a different background color to QListWidgetItem when selected
Styles:
.titleList::item {
background-color: #fff;
}
.lstSnapQuote::item:selected {
background-color: #5555FF;
}

Programmatically retrieve values for QSS style sheet properties

If I have a label that has a margin that is set using setMargin(), then I can use margin() to get the value.
But when if I set the padding using a style sheet?
ui->label->setStyleSheet("QLabel {padding: 0px 5px 10px 15px;}");
How can I get the values programmatically? Is there a function that will give me the value for a given property in the style sheet? Is there a function like ui->label()->styleSheet->getProperty("padding:left")?
I've not found any way to give all properties. I think it doesn't exist for architectural reasons. But you can take most of it from QWidget substrucrutes. For example you may take background-color from palette().color(QPalette::Window). If you want to supply qss background in your QWidget with overridden paint event you can do it this way:
void PulseChart::paintEvent(QPaintEvent*)
{
QPainter p{this};
p.fillRect(QRect{QPoint{0,0}, this->size()}, palette().color(QPalette::Window));
}

Qt 5, QML 2.0 and transparent borderless window incompatibility

Tasks:
Rounded-corners window
Custom borders
QML in QWidget
Because there is no way to change border style in parent widget, I made two of them. First parent widget is transparent, it's set in QSS. Second one is the one with rounded-corners, also set in QSS. p.s. I guess it isn't smartest idea. Not even close.
To make it work, I've set up Qt::WA_TranslucentBackground attribute.
Set up Qt::FramelessWindowHint window flag.
QML 2.0 style.[in code below]
So problem is:
When WA_TranslucentBackground and FramelessWindowHint is on - NO QML
When FramelessWindowHint is on - Only QML view
When WA_TranslucentBackground or both are off - still system BORDERS
Also I've tried to set mask on MainWindow
QPixmap pixmap = QWidget::grab(this->rect());
this->setMask(pixmap.createMaskFromColor(Qt::transparent, Qt::MaskInColor));
Works well, no system borders, custom one is rounded and QML works, but whole other area became white, don't know how to fix.
MainWindow:
QFile styleFile("style.qss");
styleFile.open(QFile::ReadOnly), qApp->setStyleSheet(QLatin1String(styleFile.readAll()));
QWidget *container = QWidget::createWindowContainer(new QQuickView(QUrl("main.qml")), this);
ui->verticalLayout->addWidget(container);
//this->setAttribute(Qt::WA_TranslucentBackground, true);
//this->setWindowFlags(Qt::FramelessWindowHint | Qt::Window);
QPixmap pixmap = QWidget::grab(this->rect());
this->setMask(pixmap.createMaskFromColor(Qt::transparent, Qt::MaskInColor));
Styles:
QWidget#MainWindow{
background:transparent;
}
QWidget#MainWindowRounded{
background-color: grey;
border: 1px solid black;
border-radius: 5px;
}
Is this possible to resolve?
HERE SOURCE CODE