QWidget's background applied to all its QWidget children - c++

I chose to use Qt to manage the GUI of a project I am working on.
After finding how to apply a picture at the bottom of my QWidget, I noticed that it has an impact on all the components that are added to it.
Whatever the style applied through the setStyleSheet method or even with a QPixmap, the background of these elements is always the image defined for the QWidget container.
How can I avoid this behavior ?
Here is my code :
MainMenu::MainMenu(QWidget* Parent, const QPoint& Position, const QSize& Size) : QWidget(Parent) {
QString qwidgetStyle = "QWidget {background-image: url(background.jpg); border: 5px solid rgba(3, 5, 28, 1);}";
QString buttonStyle = "color: rgba(73, 123, 176, 1); font-size:30px; background-color: rgba(73, 123, 176, 1);";
move(Position);
resize(Size);
setStyleSheet(qwidgetStyle);
// Menu title
QLabel *title = new QLabel(this);
title->setText("Menu");
title->setStyleSheet(buttonStyle);
title->setAlignment(Qt::AlignCenter);
// Menu buttons
// Play
buttonPlay = new QPushButton("Play");
(*buttonPlay).setEnabled(true);
(*buttonPlay).setStyleSheet(buttonStyle);
connect(buttonPlay, SIGNAL(clicked()), this, SLOT(handleButton()));
// Option
buttonOptions = new QPushButton("Options", this);
(*buttonOptions).setEnabled(true);
(*buttonOptions).setGeometry(250, 175, 100, 50);
(*buttonOptions).setStyleSheet(buttonStyle);
connect(buttonOptions, SIGNAL(clicked()), this, SLOT(handleButton()));
// Quit
buttonQuit = new QPushButton("Quit", this);
(*buttonQuit).setEnabled(true);
(*buttonQuit).setGeometry(250, 275, 100, 50);
(*buttonQuit).setStyleSheet(buttonStyle);
connect(buttonQuit, SIGNAL(clicked()), this, SLOT(handleButton()));
// Layout
QGridLayout *layout = new QGridLayout;
layout->setMargin(50);
layout->addWidget(title, 0, 0, 1, 5);
layout->addWidget(buttonPlay, 3, 1, 2, 3);
layout->addWidget(buttonOptions, 4, 1, 2, 3);
layout->addWidget(buttonQuit, 5, 1, 2, 3);
setLayout(layout);
show();
}

The behavior you encountered is perfectly normal, because of the following lines :
QString qwidgetStyle = "QWidget {background-image: url(background.jpg); border: 5px solid rgba(3, 5, 28, 1);}";
...
setStyleSheet(qwidgetStyle);
Here, you just told Qt to apply qwidgetstyle to every QWidget of your application, with the keyword QWidget. That's why in Qt, you better set a name to your object if you want to apply a style to this particular object.
In your code, QLabel and QPushButton both inherit from QWidget, so they will have the style you defined for a QWidget, unless you name them or you specify the style for each one.
If you want to set style sheet for your MainMenu which inherits directly from QWidget (which is what you are doing in the first place), you have to set a name, and then apply the style :
setObjectName("MainMenu");
QString qwidgetStyle = "QWidget#MainMenu {background-image: url(background.jpg); border: 5px solid rgba(3, 5, 28, 1);}";
setStyleSheet(qwidgetStyle); // here, only your MainMenu will have the style "qwidgetstyle"
Notice that you can, for example, set the same style sheet for every QWidget, and only add a particular color for your MainMenu :
// this is in a CSS, but you can apply it directly from the MainMenu constructor of course
QWidget, QWidget#MainMenu {
background-image: url(background.jpg);
border: 5px solid rgba(3, 5, 28, 1);
} // aplied to all QWidget
QWidget#MainMenu {
color : #9b9b9b; // a nice grey, only applied to MainMenu
}
Again, be specific when using style sheets or you will end up having strange colors/alignments everywhere in your application :). Hope that helps!
NB : you can also thank #PaulRooney who gave a very good link in the comments.

Related

Keep widget central forever after inserting an spaceritem

I want to customize a titlebar:
class TitlebarWidget : public QWidget {
Q_OBJECT
public:
TitlebarWidget(QWidget* parent = nullptr): QWidget(parent) {
setupUi();
}
virtual ~TitlebarWidget();
private:
void setupUi(){
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
// layout->addSpacerItem(new QSpacerItem(width(), height(),
QSizePolicy::Fixed, QSizePolicy::Fixed));
m_homeButton = new QPushButton(this);
m_homeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_homeButton->setMinimumWidth(50);
m_homeButton->setMaximumWidth(50);
m_homeButton->setText(tr("Home"));
layout->addWidget(m_homeButton);
QLabel* label = new QLabel(this);
label->setText("Titlebar");
layout->addWidget(label, 0, Qt::AlignCenter);
m_synButton = new QPushButton(this);
m_synButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_synButton->setMinimumWidth(100);
m_synButton->setMaximumWidth(100);
m_homeButton->setText(tr("Sync"));
}
QPushButton* m_synButton;
QPushButton* m_homeButton;
QPushButton* m_settingButton;
QRCodeWidget* m_synPhoneWidget;
};
The titlebar is as follows:
Home button is covered by the three circles at top-left corner, so I insert an spacer-item at the beginning:
layout->addSpacerItem(new QSpacerItem(width(), height(), QSizePolicy::Fixed, QSizePolicy::Fixed));
And the titlebar is like:
I found the text 'Titlebar' was obviously deviated from the center, but I want keep it central. who can help me with a workaround or a better alternative?
Use layout->addSpacing() instead and addStretch works for me.

Qt StyleSheet to programmatically createdQWidget

I want to apply a stylesheet to a particular Qwidget that I create in the constructor of the parent QWidget. I don't want to create the QWidget in the Designer, but I want to create it dynamically.
This is my code
enum {one = 0,
two = 1,
three = 2};
cMainForm::cMainForm(QWidget *parent) : QWidget(parent), ui(new Ui::cMainForm) {
//...
QWidget* widgetTest[3];
widgetTest[one] = new QWidget(this);
widgetTest[one]->setGeometry(100,100,100,100);
widgetTest[one]->show();
widgetTest[one]->raise();
//...
setStyleSheet("QWidget#widgetTest[one]{"
"background-color: red;"
"}"
);
//...
}
And doesn't work.
If I change the styleSheet:
setStyleSheet("QWidget{"
"background-color: red;"
"}"
);
The stylesheet is applied to all the widgets. But I don't want this; I want to apply the stylesheet only to that particular widget.
Also if I don't use an array, it doesn't work.
QWidget* widgetTest;
widgetTest = new QWidget(this);
widgetTest->setGeometry(100,100,100,100);
widgetTest->show();
widgetTest->raise();
//...
setStyleSheet("QWidget#widgetTest{"
"background-color: red;"
"}"
);
I already searched the documentation.
What's the solution?
The selector you're using (#) refers to the widget objectName property, not the variable name (the style engine knows nothing about your variables). Give the widget an object name:
widgetTest->setObjectName("widgetTest");
then set the stylesheet:
widgetTest->setStyleSheet("QWidget#widgetTest { background-color: red }");

How to create custom widget and use it in Qt Designer?

I extremely need to create my custom widget and use it inside QtDesigner ( promoting QWidget to my widget ). I have never done it before, and can't google anything useful. Widget i need to get is just square box with few QLabel and QLineEdit objects. For this moment i have the following code:
#include "customwidget01.h"
#include "qlabel.h"
#include "qlineedit.h"
#include "QGridLayout"
customWidget01::customWidget01(QWidget *parent) : QWidget(parent)
{
QString textSheets = "QLabel,QLineEdit {width:60;height:20;max-width:60;max-height:20;;min-width:60;min-height:20;}";
QString widgetSheet = "customWidget01 {width:200;height:200;max-width:200;max-height:200;;min-width:120;min-height:200;}";
this->setStyleSheet(widgetSheet + textSheets);
QLabel *label1= new QLabel(this);
label1->setText("1st arg");
QLabel *label2 = new QLabel(this);
label2->setText("2nd arg");
QLabel *label3= new QLabel(this);
label3->setText("3rd arg");
QLabel *label4= new QLabel(this);
label4->setText("4th arg");
QLineEdit *line1 = new QLineEdit(this);
line1->setPlaceholderText("enter 1st arg");
QLineEdit *line2 = new QLineEdit(this);
line2->setPlaceholderText("enter 2nd arg");
QLineEdit *line3 = new QLineEdit(this);
line3->setPlaceholderText("enter 3rd arg");
QLineEdit *line4 = new QLineEdit(this);
line4->setPlaceholderText("enter 4th arg");
QGridLayout *layout = new QGridLayout();
this->setLayout(layout);
layout->setVerticalSpacing(10);
layout->setHorizontalSpacing(10);
layout->addWidget(label1,0,0);
layout->addWidget(label2,1,0);
layout->addWidget(label3,2,0);
layout->addWidget(label4,3,0);
layout->addWidget(line1,0,1);
layout->addWidget(line2,1,1);
layout->addWidget(line3,2,1);
layout->addWidget(line4,3,1);
this->setVisible(true);
}
My problems are:
cant draw border around widget itself
vertical and horizontal spacings do not work
Used QtDesigner for GUI all the time - not really familiar with gui creation in plain code.
let me help you in order to get beautiful interface you need to learn CSS
I will show you how it works
that's what you have right now
This means that you do not correctly write the CSS code
QString textSheets = "QLabel,QLineEdit {width:60;height:20;max-width:60;max-height:20;;min-width:60;min-height:20;}";
QString widgetSheet = "customWidget01 {width:200;height:200;max-width:200;max-height:200;;min-width:120;min-height:200;}";
this->setStyleSheet(widgetSheet + textSheets); // does not work
I will exchange these lines for it
QString textSheets = "QLineEdit{ border-width: 2px; border-style: solid; border-color: red green black rgb(127,255,10); }"
"QLabel { border-width: 2px; border-style: solid; border-color: green black rgb(10,255,180) rgb(180,10,158); }" ;
setStyleSheet(textSheets);
and that's what result
to resize you just need to do so
//label1->setMinimumSize(150,50);
label1->setFixedSize(150,50);
//label1->setMaximumSize(150,50);
//label1->setMidLineWidth(150);
and that's what result
Add a QWidget in design mode.
Right click it and select Promote to... from the context menu.
Write the name (customWidget01) of your from QWidget derived class into Promoted class name.
Make sure the generated text in Header file is correct.
Click add.
Select it and click promote.

Paint QPushButton with QLinearGradient

I am trying to use a QLinearGradient to paint a QPushButton with no success. I have found examples on how to paint it with a solid color. But I have been unsuccessful in finding examples for a color gradient. Moreover, my approach did not work.
Here is my complete example where the solid color push button works and the linear gradient one does not:
#include <QApplication>
#include <QGridLayout>
#include <QLinearGradient>
#include <QPalette>
#include <QPushButton>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
// Create layout
QGridLayout* layout = new QGridLayout;
// Create first button
QPushButton* button_1 = new QPushButton();
layout->addWidget(button_1, 0, 0);
QPalette palette_1 = button_1->palette();
palette_1.setColor(QPalette::Button, Qt::red);
button_1->setPalette(palette_1);
button_1->update();
// Create second button
QPushButton* button_2 = new QPushButton();
layout->addWidget(button_2, 0, 1);
QLinearGradient gradient_button(0, 0, button_2->width(), 0);
gradient_button.setColorAt(0, Qt::white);
gradient_button.setColorAt(1, Qt::black);
QPalette palette_2 = button_2->palette();
QBrush brush(gradient_button);
palette_2.setBrush(QPalette::Button, brush);
button_2->setPalette(palette_2);
button_2->update();
// Create widget
QWidget* widget = new QWidget;
widget->setLayout(layout);
widget->resize(300, 50);
/// Show
widget->show();
// Run
return app.exec();
}
Any ideas on what am I doing wrong?
Without a success I've tried it with QPalette and done it successfully using setStyleSheet:
QPushButton* button = new QPushButton();
QString linearGradient = QString("qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));");
button->setStyleSheet(QString("background-color: %1").arg(linearGradient));
Also, we can use QString::arg(...) to set different colors and points for the gradient.
Hope this help you and excuse me for a stupid comment earlier )
Your gradient is configured to go from <0, 0> to <button_2->width(), 0>, but at the moment you create your gradient button_2 is not included in any layout: its width will be computed when the parent widget (therefore the layout where the button is) is resized. If you try fixing the width you'll see the gradient works as expected.
QPushButton* button_2 = new QPushButton();
button_2->setFixedWidth(100);
You can use an event filter to watch for the resize and adjust the gradient accordingly:
class ButtonResizeWatcher : public QObject {
protected:
virtual bool eventFilter(QObject* o, QEvent* e) override {
if (e->type() == QEvent::Resize) {
auto button = qobject_cast<QPushButton*>(o);
QLinearGradient gradient_button(0, 0, button->width(), 0);
gradient_button.setColorAt(0, Qt::white);
gradient_button.setColorAt(1, Qt::red);
auto palette = button->palette();
palette.setBrush(QPalette::Button, QBrush(gradient_button));
button->setPalette(palette);
}
return QObject::eventFilter(o, e);
}
};
Use:
ButtonResizeWatcher resize_watcher;
button_2->installEventFilter(&resize_watcher);
Full code can be found in GitHub.
Another option, as commented in a different answer, would be to use the stylesheet (qlineargradient). It depends on you if you need further control on the brush, such as "show gradient but only until certain width is reached". Also, take into consideration that stylesheets usually conflicts with other QStyles (if used).

How to reset child's style sheet to Qt default style sheet when the "child's parent's style sheet" is changed?

When I change the style sheet of an object, the style sheet of it's child also changes.
how can I reset child's style sheet to Qt default style?
for test of this I use the below code:
in header file:
#include "ui_QtGuiApplication.h"
#include <QGraphicsView>
#include <QtWidgets/QPushButton>
class QtGuiApplication : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplicationClass ui;
QGraphicsView* qGraph;
QGraphicsScene* scene;
};
in source file:
#include "QtGuiApplication.h"
QtGuiApplication::QtGuiApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
// Change centralWidget stylesheet
ui.centralWidget->setStyleSheet(
"background:qlineargradient(x1 : 0, y1 : 0, x2 : 0, y2 : 1,\
stop : 0 rgb(216, 0, 0), stop : 0.4 rgb(155, 0, 0),\
stop : 0.4 rgb(155, 0, 0), stop : 1.0 rgb(216, 0, 0));");
// creat a QGraphicsView an add it to centralWidget
qGraph = new QGraphicsView(ui.centralWidget);
qGraph->setGeometry(QRect(70, 30, 300, 300));
scene = new QGraphicsScene(qGraph);
scene->setSceneRect(0, 0, 300, 300);
qGraph->setScene(scene);
qGraph->show();
// creat a push button and add it in to centralWidget
QPushButton* btn_Ok = new QPushButton(ui.centralWidget);
btn_Ok->setGeometry(QRect(340, 340, 75, 23));
btn_Ok->setText("Ok");
//below code doesn't work
btn_Ok->setStyleSheet("");
btn_Ok->setStyleSheet(styleSheet());
}
I encountered a similar problem and child or ID selector did the trick for me.
For instance, if you want to style btn_Ok which is a QPushButton you can give it a name
btn_Ok->setObjectName("xxx");
and use this name to style it via
ui.centralWidget->setStyleSheet("QPushButton#xxx{background: red;}");
This way the only push button that will be styled is btn_Ok.
If you want to style all the push buttons that are direct descendants from you central widget you can use
ui.centralWidget->setStyleSheet("QWidget#centralWidget > QPushButton{background: red;}");