I'm trying to use a Q_PROPERTY set in my stylesheet to change the value in QPalette, is this possible? For example, if I set QStyle to Fusion in my MainWindow widget, is it possible to change Qt::Window, etc using this method?
Everything compiles OK, but the only color displayed is black, so the variable is probably filled with a garbage value? As far as I know, the stylesheet overrides everything else, so at a guess, the stylesheet is not loaded in time for the constructor?
mainwindow.cpp
#include <QStyleFactory>
#include <QWidget>
#include <QFile>
#include "theme.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
{
QFile File("://stylesheet.qss");
File.open(QFile::ReadOnly);
QString StyleSheet = QLatin1String(File.readAll());
qApp->setStyleSheet(StyleSheet);
Theme *themeInstance = new Theme;
QApplication::setStyle(QStyleFactory::create("Fusion"));
QPalette dp;
dp.setColor(QPalette::Window, QColor(themeInstance->customColor()));
qApp->setPalette(dp);
}
theme.h
#ifndef THEME_H
#define THEME_H
class Theme : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor customColor READ customColor WRITE setCustomColor DESIGNABLE true)
public:
Theme(QWidget *parent = nullptr);
QColor customColor() const { return m_customColor; }
void setCustomColor(const QColor &c) { m_customColor = c; }
private:
QColor m_customColor;
};
#endif // THEME_H
stylesheet.qss
* { // global only for test purposes
qproperty-customColor: red;
}
The QSS are not called automatically, they are usually updated when the widgets are displayed, in your case as themeInstance is not shown does not use the stylesheet. Painting can be forced using the polish() method of QStyle
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr):QMainWindow{parent}{
qApp->setStyleSheet("Theme{qproperty-customColor: red;}");
Theme *themeInstance = new Theme;
qApp->setStyle(QStyleFactory::create("Fusion"));
qApp->style()->polish(themeInstance);
QPalette dp;
dp.setColor(QPalette::Window, QColor(themeInstance->customColor()));
qApp->setPalette(dp);
}
};
Related
There is the complete process:
Create a project, choose Base class: QWidget, including .h .cpp .ui
[Add New...] -> create a [ C++ class] -> choose base class: [QWidget], but named myLabel.
Open mylabel.h, change QWidget of including file and parent class to QLabel
mylabel.h
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QLabel>
class myLabel : public QLabel
{
Q_OBJECT
public:
explicit myLabel(QWidget *parent = nullptr);
signals:
};
#endif // MYLABEL_H
Open mylabel.cpp, change the parent class into QLabel too, and set text content
mylabel.cpp
#include "mylabel.h"
myLabel::myLabel(QWidget *parent)
: QLabel{parent}
{
this->setText("test");
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
Now i got a custom class, and create a label in the widget.ui
add a widget, put the label in, choose widget and label, ctrl+L
just like this
Promote label to myLabel.
label was promoted to myLabel
Run.
running result
This isn't what i expect.
So, why the text of label didn't change? or maybe something ignored? plz, even a keyword that can help me searching...
Check the code of setupUi method.
When you use QT Designer to create your widget, each widget has some properties (like geometry, object name, initial text for label etc) which have to be initialized. This is done in setupUi. The code corresponding your case may look like:
void setupUi() {
label = new myLabel(widgetParent); // setText with test
label->setObjectName(...
label->setGeometry(...
label->setAlignment(...
label->setText(TEXT_FROM_DESIGNER); // <---
}
The text test set by constructor of myLabel widget is overwritten by calling setText in setupUi method with text choosen in Designer.
If you want to change some properties of created widgets it should be done after setupUi:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// change label's text
}
I would like to put an svg image as background to my QGraphicsView without repetition and preserving the ratio. Can you help me?
Thanks.
This is one Example :
First of all add QT += svgwidgets in your .pro.
then add one graphicsView in your UI File :
in mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsScene>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QGraphicsScene *scene;
};
#endif // MAINWINDOW_H
in mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsSvgItem>
#include <QSvgRenderer>
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
QGraphicsSvgItem *item = new QGraphicsSvgItem(":/images/images/diagramTool.svg");
scene->addItem(item);
}
MainWindow::~MainWindow()
{
delete ui;
}
output :
And there is one easy way you can add this stylesheet in your graphics view :
background-image: url(":/images/images/diagramTool.svg");
background-repeat: no-repeat;
background-position: center;
border-style:none;
This will add SVG as your background image.
To put a background that fits the size of the object I created a class that inherits from QGraphicsScene and I rewrote drawBackground by putting my svg image in it.
myscene.h
class myscene : public QGraphicsScene
{
public:
myscene();
~myscene();
void drawBackground(QPainter *painter, const QRectF &rect);
};
myscene.cpp
myscene::myscene():QGraphicsScene()
{
}
myscene::~myscene()
{
}
void myscene::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->drawImage(rect, QImage(":myPathImage.svg"));
}
Then in my QGraphicsView I passed it this scene and it works.
myview.h:
class myview : public QGraphicsView
{
private :
myscene* _scene;
public:
myview();
~myview();
};
myview.cpp:
myview::myview() : QGraphicsView()
{
_scene = new myscene();
this->setScene(_scene);
this->showMaximized();
}
myview::~myview()
{
delete _scene;
}
I am learning Qt using Qt 5.13 on MacOS.
First I define MyWidget inherited from QWidget. MyWidget has a QPushButton, but this button will be created in a slot function called 'fresh', not in constructor.
I add MyWidget in MainWindow (inherited from QMainWindow), and defined another button_2 to emit signal to callMyWidget's 'fresh' function to create button.
If I did not hide MyWidget in MainWindow first, MyWidget's button will not show. If I hide MyWidget first, everything seems OK.
I hope to know the reason. Thanks
I tried to repaint or update MyWidget in 'fresh' function, but did not help.
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include<QPushButton>
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = nullptr);
~MyWidget();
public slots:
void fresh();
private:
QPushButton* myButton;
};
#endif // WIDGET_H
mywidget.cpp
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
}
MyWidget::~MyWidget()
{
}
void MyWidget::fresh()
{
myButton = new QPushButton(this);
myButton->setStyleSheet("QPushButton { background-color: green;}");
show();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include"mywidget.h"
#include<QHBoxLayout>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
signals:
public slots:
private:
MyWidget* myWidget;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QWidget* qwidget = new QWidget;
myWidget = new MyWidget(this);
QPushButton* button = new QPushButton("Show",this);
QHBoxLayout* mainLayout = new QHBoxLayout;
mainLayout->addWidget(myWidget);
mainLayout->addWidget(button);
qwidget->setLayout(mainLayout);
setCentralWidget(qwidget);
//myWidget->hide();
connect(button,&QPushButton::clicked,myWidget,&MyWidget::fresh);
}
main.cpp
#include "mywidget.h"
#include"mainwindow.h"
#include<QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
If I add myWidget->hide(); in mainwindow.cpp, it seems right.
If I remove it, the green button will not show, even if I repaint or update or show in fresh function.
'mywidget' is taking the whole space, if you want to know if it is taking all the space or not :
mywidget->setStyleSheet("* {border: 4px solid orange;}")
Since you are using a layout, you might want to determine the minimum size of a QPushButton. the QPushButton has a default horizontal size policy : "Minimum", by default. Maybe if you set the minimum width using this function : "setMinimumWidth(int width)", might fix your problem.
Also, don't forget to call this :
myButton->show();
Every object that inherits from QObject should be shown with this func ".show".
Here is all the flags for QSizePolicy will help you understand what is going on in layouts (layouts work a lot with QSizePlicy flags) : https://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum .
Unless you don't want the layout, you have to specify the position and the size in this way :
mywidget->setGeometry(QPoint(x, y), QSize(width, height));
and the same thing for your buttons.
When running the program in Qt Creator, the console log gets filled with messages that say...
QMenu(0x21aef3db1c0) does not have a property named "myVar"
I have only main.cpp, mainwindow.cpp/h. I'm using Q_PROPERTY in mainwindow.
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// code here
}
QColor MainWindow::getMyVar() const
{
return myVar;
}
void MainWindow::setMyVar(QColor c)
{
myVar = c;
}
MainWindow::~MainWindow()
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
Q_PROPERTY(QColor myVar READ getMyVar WRITE setMyVar DESIGNABLE true)
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
QColor getMyVar() const;
void setMyVar(QColor c);
private:
QColor myVar;
};
#endif // MAINWINDOW_H
stylesheet.qss
* {
qproperty-myVar: red;
}
What's the point of this message and what can I do to get rid of it?
The * in your stylesheet rule matches everything:
* {
qproperty-myVar: red;
}
This means that this style will be applied to all widgets, not just your MainWindow widget. For example, it will be applied to the QMenu of your main window, and Qt complains here that QMenu does not have a myVar property -- indeed it does not!
Try the following instead:
MainWindow {
qproperty-myVar: red;
}
The following is the smallest example I could make to present the isuue.
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVBoxLayout *vLayout = new QVBoxLayout(this);
QGroupBox *gb = new QGroupBox;
// MyGroupBox *gb = new MyGroupBox;
vLayout->addWidget(gb);
QPushButton *btB = new QPushButton;
vLayout->addWidget(btB);
}
The code above produces the image above, it's just a group box and a button in vertical layout.
If I replace QGropBox by MyGroupBox then it doesn't show there anymore. The code below produces the image below.
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVBoxLayout *vLayout = new QVBoxLayout(this);
// QGroupBox *gb = new QGroupBox;
MyGroupBox *gb = new MyGroupBox;
vLayout->addWidget(gb);
QPushButton *btB = new QPushButton;
vLayout->addWidget(btB);
}
Where mygroupbox.h (the constructor body is empty in the .cpp file):
#include <QWidget>
class MyGroupBox : public QWidget
{
Q_OBJECT
public:
explicit MyGroupBox(QWidget *parent = 0);
signals:
public slots:
};
Why the group box isn't showing there? How to make it appear?
This is why it doesn't appear:
class MyGroupBox : public QWidget
Your "group box" is basically just a QWidget. Inherit from QGroupBox instead.
As an aside, a minimal example could look like the below. Not a single declaration/statement/expression can be removed. The button aids in visualizing the problem, so it should be left in. The use of a failure trigger variable highlights exactly what condition triggers the failure: the code self-documents and you almost need no narrative to explain it. The question could be as concise as the test case below and one sentence "Why is the group box's border not visible when fail is true?". Most likely, had you followed the minimization fully through, you'd realize yourself what the problem was - it becomes rather obvious. It's not so when MyGroupBox is declared in another file!
The technique of putting it all into a single main.cpp file is critical in spotting the problem: all of the code is physically next to each other, making it much easier to spot mistakes! When you minimize, usually the first things that have to go are separate files: cram it all into one file, and then relentlessly remove absolutely everything that's not directly needed in reproducing the issue.
#include <QtWidgets>
struct MyGroupBox : public QWidget {};
int main(int argc, char ** argv) {
bool fail = true;
QApplication app{argc, argv};
QWidget widget;
QVBoxLayout layout{&widget};
QGroupBox groupBox;
MyGroupBox myGroupBox;
QPushButton button;
layout.addWidget(fail ? static_cast<QWidget*>(&myGroupBox) : &groupBox);
layout.addWidget(&button);
widget.show();
return app.exec();
}
This concise style is not only for trivial test cases. In your real code, the Widget's header and implementation could look as follows:
// Widget.h
#include <QtWidgets>
#include "MyGroupBox.h"
class Widget : public QWidget {
Q_OBJECT
QVBoxLayout layout{this};
MyGroupBox groupBox;
QPushButton button{tr("Click Me!")};
public:
explicit Widget(QWidget * parent = nullptr);
};
// Widget.cpp
#include "Widget.h"
Widget::Widget(QWidget * parent) :
QWidget{parent} {
layout.addWidget(&groupBox);
layout.addWidget(&button);
}
If you insist on shielding the interface from implementation details, don't use pointers to widgets etc., use a PIMPL.
// Widget.h
#include <QWidget>
class WidgetPrivate;
class Widget : public QWidget {
Q_OBJECT
Q_DECLARE_PRIVATE(Widget)
QScopedPointer<WidgetPrivate> const d_ptr;
public:
explicit Widget(QWidget * parent = nullptr);
};
// Widget.cpp
#include "Widget.h" // should always come first!
#include "MyGroupBox.h"
class WidgetPrivate {
Q_DECLARE_PUBLIC(Widget)
Widget * const q_ptr;
public:
QVBoxLayout layout{q_func()};
QGroupBox groupBox;
MyGroupBox myGroupBox;
QPushButton button{"Click Me!"};
WidgetPrivate(Widget * q) : q_ptr(q) {
layout.addWidget(&groupBox);
layout.addWidget(&button);
}
};
Widget::Widget(QWidget * parent) :
QWidget{parent}, d_ptr{new WidgetPrivate{this}}
{}