Setting an icon's size on a QPushButton through Stylesheets - c++

I'm trying to set an icon's size on a QPushButton through Stylesheets. I am unable to locate the proper syntax from the Qt documentation that would allow me to modify the icon's size when I implement the icon image from the stylesheet. This application is for use on the icon of a QPushButton on multiple uis and the Stylesheet settings will be set on a parent ui.
This is my code, based on this suggestion. Adjusting the size to 64 or 256 did not change the size of the object.
"QPushButton#pushButton_Calibration {image: url(:/images/toolkit.png); qproperty-iconSize: 128px;}"
This is my other code, based on this other suggestion. Adjusting the width/height to 64 or 256 did not change the size of the object.
"QPushButton#pushButton_Calibration {image: url(:/images/toolkit.png); width: 128px; height: 128px;}"
I am aware that something like this is an option:
ui->pushButton_Calibration->setIconSize(QSize(128, 128));
But I am unsure on how to implement this to something with the format QPushButton#pushButton_Calibration or how to use this to implement it globally to the children of my ui element since this syntax directly points to only the element on the particular ui file (at least, this is my understanding).
Please let me know if more information is required to solve this issue. I am unfamiliar with the syntax needed to change the size of the icon and haven't been able to locate it from the documentation.

If you want to set an icon, you should use the icon property, instead of the image property, like this.
QPushButton#pushButton_Calibration {
icon: url(:/images/toolkit.png);
qproperty-iconSize: 128px;
}
And the official documentaion is here.
Also be careful on the scaling of the image. It will not scale up for both 'image' and 'icon' properties.

I would recommend to use QPushButton::setIcon() and QPushButton::setIconSize() member functions instead of working with stylesheets.
One rationale behind this is that once you deal with stylesheets, the system style for the given widget may be completely messed up and you may need to restyle the whole widget even if you only wanted to change a specific part or behaviour.
Per the Qt documentation, you can read the following note regarding the icon property:
"Note: It's the application's responsibility to assign an icon to a button (using the QAbstractButton API), and not the style's. So be careful setting it unless your stylesheet is targeting a specific application."
If you want the change to be applied for all buttons of your application, you can create your own button class that inherits QPushButton and sets the properties you want in the constructor.
Example:
.hpp
class MyButton : public QPushButton
{
Q_OBJECT
public:
MyButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr);
MyButton(const QString &text, QWidget *parent = nullptr);
MyButton(QWidget *parent = nullptr);
};
.cpp
MyButton::MyButton(const QIcon &icon, const QString &text, QWidget *parent) : QPushButton(icon, text, parent)
{
setIconSize({128, 128});
}
MyButton::MyButton(const QString &text, QWidget *parent) : QPushButton(text, parent)
{
setIconSize({128, 128});
}
MyButton::MyButton(QWidget *parent) : QPushButton(parent)
{
setIconSize({128, 128});
}
Of course, you can adapt it to your use case (maybe you want to set the icon inside the constructor as well, etc...)

Related

Qt generate UI based on template

I'm looking to generate a set of labels and buttons based on some kind of template, but I don't know how to do the template part.
I'll be using a tab widget which I already have set up, and in one the tabs, I want to have a two labels, a custom button, and a textbox. It'll be repeated around 40-50 times (dependent on a given value at startup) and have spacing as needed.
Once I have a template, I foresee calling it in a loop and setting the appropriate displayed text(Label_1, Label_2, etc) and connect statements where needed.
As I said, I don't know how to template parts of the UI so they can be placed in a kind of auto-generation.
I had thought of making one group, copying the xml, and somehow adding it but that doesn't seem to be a proper way. A little new to Qt.
This is roughly the layout I want to repeat. It has two labels, a lineedit, and one pushbutton.
There's no "good" way to do this in QtDesigner/QtCreator. At best you could copy/paste the set of controls 50 times and then in C++ code hide the ones you don't need. But I wouldn't recommend this.
Instead, just create the controls (labels/button/text box), and a layout to hold them, in C++ code, inside a loop which iterates however many times you need at runtime. Insert the controls layout into the tab widget page layout which you have set up in designer mode. It is not difficult, and will actually be more efficient than what QtDesigner produces since that tends to generate more code than you typically need in the first place.
As a starting point, you could look at the C++ code which is generated by the Qt UI Compiler (UIC) tool for your current design (it takes the XML from designer and turns it into C++ code). You can find this in the build folder for your project, typically named something like ui_ClassName.h, probably in a ui subfolder of the build tree.
UPDATE:
Another, possibly better, way to do this is to create the "template" QWidget class/form, which is going to be used multiple times, as a separate object. The "template" design could be created/maintained using QtCreator/Designer (or just directly in C++). The (possible) advantage here is that as the app requirements evolve, the template widget can be expanded with additional functionality or even re-used in other parts of the UI.
For example, I'd assume the text editor and button in the given mockup image will actually need to do something (eg. edit data and submit it). So some basic functionality can be built into the "template" widget, for example to emit a signal with the text contents of the line editor when the button is pressed.
I put together a quick example. I'm creating the simple MainWindow in pure C++ to simplify/shorten the example code. The "template" I'm calling an Editor. The Editor class and UI form I initially created with the QtCreator wizard (New -> Qt Designer Form Class). I then added the label/control widgets in designer mode. And in C++, a textEdited(const QString &text) signal in the header, and in the Editor() constructor a lambda connection to emit that signal when the button is pressed.
The Editor class code is straight out of the QtCreator wizard except for two edits I'm highlighting below. The designer form has two relevant controls: a QLineEdit (lineEdit) and a QPushButton (pushButton). I'll link to the full files below.
Editor.h
// in the Editor class declarations:
signals:
void textEdited(const QString &text) const;
Editor.cpp
// in the constructor, after ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, [this]() {
emit textEdited(ui->lineEdit->text());
});
Test harness, including MainWindow subclass and main()
#include <QApplication>
#include <QMainWindow>
#include <QTabWidget>
#include <QBoxLayout>
#include <QMessageBox>
#include "Editor.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow() : QMainWindow()
{
// set up a tab widget as the window central widget
QTabWidget *tabWidget = new QTabWidget(this);
setCentralWidget(tabWidget);
// the first/only page will contain all the editors in a vertical layout
QWidget *editorsPage = new QWidget(this);
editorsPage->setLayout(new QVBoxLayout());
// add the editors container page to tab widget
tabWidget->addTab(editorsPage, tr("Editors page"));
// Now create a number of editor widgets using our Editor class "template"
int layoutItems = 5; // number of editors needed, could be dynamic
for (int i=0; i < layoutItems; ++i) {
// Create an Editor instance with the tab page as parent
Editor *editor = new Editor(editorsPage);
// Add the editor widget to the tab page layout
editorsPage->layout()->addWidget(editor);
// A simple connection with the editor signal, as way of example.
connect(editor, &Editor::textEdited, this, [this](const QString &text) {
// just show a message box with the editor text
QMessageBox::information(this, tr("Text Edited"), text, QMessageBox::Ok);
});
}
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
#include "main.moc"
Links The full Editor code:
Editor.h
Editor.cpp
Editor.ui
The XML in Qt Creator is for UIC in QMake to generator code for you.
For example, QMake translates your mainwindow.ui to ui_mainwindow.h, and within you will find void setupUi(QMainWindow *MainWindow) with the actual code that creates and places the widgets.
Look at this code, the docs, and create and place the widgets yourself by code.
For example, adding 5 checkboxes to a groupbox by code:
QVBoxLayout *l = new QVBoxLayout(this);
ui->groupBox_4->setLayout(l);
for(int i=0; i<5; i++){
QCheckBox *c = new QCheckBox(this);
l->addWidget(c);
}

Adjust QCheckbox into QTableWidget : Qt

I am facing issues when I adjust QCheckbox into QTableWidget.
It is working as expected in Mac and Linux but creating problem in Windows.
I have googled it and tried out different solutions, but it did not solve my problem.
Code:
QWidget* cellWidget = new QWidget();
QCheckBox *box = new QCheckBox();
box->setCheckState(Qt::Unchecked);
QHBoxLayout* layout = new QHBoxLayout(cellWidget);
layout->addWidget(box);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0, 0, 0, 0);
cellWidget->setLayout(layout);
ui->twidget_header->setCellWidget(0, 0, cellWidget);
Mac OS O/P : As Expected
Win OS O/P : Problem with Checkbox size and alignment
.
My app is created in Qt 5.9 for Mac, Win and Linux platform.
Let me know if you required more info about the problem.
The design and size of the widgets are determined by the style. To override the native style (whatever QApplication sets as default on your target system) you'll have to derive your own QStyle for that target system and and reimplement pixelMetric() to return the appropriate values for QStyle::PM_IndicatorWidth and QStyle::PM_IndicatorHeight (I think; didn't check that).
The problem can happen with any QWidget while you create Qt app and support different resolutions.
To overcome the size of the QWidget (QCheckbox/QRadiobutton), you just need to overwrite the QWidget class.
Create customcheckbox.h file and overwrite the QCheckbox widget.
class CustomCheckBox : public QCheckBox
{
Q_OBJECT
public:
CustomCheckBox(QWidget *parent=NULL);
private:
bool m_isChecked;
public slots:
void emitToggleSignal(bool);
};
Implement customcheckbox.cpp file as per your requirement.
By doing this, QCheckbox will automatically adjust size on respective resolution.
Hope this will save someone's time in future.
Thanks.

Is it possible to set global QPainter default render hints?

When a QPainter is created, it has some default render hints. Some widgets override them when painting themselves. Is it possible to override these defaults and disable the per-widget overrides for the entire application?
I'd like to override the defaults as follows, and make all widget classes follow these:
painter->setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing, false);
painter->setRenderHints(QPainter::TextAntialiasing , true);
Is it possible?
UPDATE:
Short answer: not possible without changing Qt source code.
Unfortunately, Qt doesn't implement any public way of doing this.
There are two issues:
The default render hint - QPainter::TextAntialiasing is set in QPainter::begin(QPaintDevice*). This is exactly what you wanted according to your question, but
The widgets are free to override these defaults. And many of them do. There is no way to disable that, without inserting a shim paint engine (or similar) that would intercept these and ignore them.
The simplest way to change it is to modify the QPainter::setRenderHint and QPainter::setRenderHints to disable the overrides on certain widget types, and rebuild Qt. In any professional setting you'll be using your own build of Qt anyway, so that shouldn't be an issue.
There probably is a way of hooking it using Qt's private headers, most likely by offering a shim paint engine and swapping it out on the backing store, without modifying Qt itself, but it'll be messy and not worth it.
You can subclass QPainter with:
class MyQPainter: public QWidget
{
Q_OBJECT;
public:
MyQPainter(QWidget *parent = 0);
QPainter painter;
}
and:
MyQPainter::MyQPainter(QWidget *parent)
: QWidget(parent)
{
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing, false);
painter.setRenderHints(QPainter::TextAntialiasing , true);
}
now, you can declare MyQPainter *pPainter = new MyQPainter();

Qt 5- QTextEdit reverts to default font

I am working on a text editor using the QT library. I am subclassing QTextEdit for my main editor widget.
Here is my code:
editorwidget.hpp
#ifndef EDITORWIDGET_H_INCLUDED
#define EDITORWIDGET_H_INCLUDED
#include <QTextEdit>
#include <QFile>
class EditorWidget : public QTextEdit
{
Q_OBJECT
public:
EditorWidget(const QString& filename, QWidget* parent = 0);
~EditorWidget();
public slots:
void saveRequested();
//...
private:
QFile* editorFile;
};
#endif
editorwidget.cpp
#include "editorwidget.hpp"
EditorWidget::EditorWidget(const QString& filename, QWidget* parent)
: QTextEdit(parent)
{
this->setFontPointSize(getFontSize()); // this is in another file
this->setFontFamily(getFont()); // also in another file
// those two functions get the font and font size from the user's settings
this->editorFile = new QFile(filename);
}
EditorWidget::~EditorWidget()
{
if(this->editorFile->isOpen()) this->editorFile->close():
delete editorFile;
}
...
When the EditorWidget is created, the font shows up correctly. However, when I enter some text, and then delete it, the widget reverts to the default font.
I don't understand what's going on; I've searched Google and Stack Overflow but found nothing. Any help would be greatly appreciated. Thanks!
This thread might be helpful. The setFont...() functions set the format behind the edit cursor, but the default format is free from it. The QT Docs also explains this situation.
"...The current style, which is used to render the content of all standard Qt widgets, is free to choose to use the widget font, or in some cases, to ignore it (partially, or completely). In particular, certain styles like GTK style, Mac style, Windows XP, and Vista style, apply special modifications to the widget font to match the platform's native look and feel. Because of this, assigning properties to a widget's font is not guaranteed to change the appearance of the widget."
In your case, you may try setStyleSheet() instead.

QMenu item text disappears when icon added

I am attempting to add an icon to my QMenu using Qt Designer, however I realized that my text disappears when my icon is added. Is there any way for me to show my icon next to my text?
It was not supported in Qt 4, maybe it is in Qt5 I haven't checked.
In Designer itself there isn't much you can do. In the code one option is to customize the style to draw both the icon and text:
- sizeFromContents for QStyle::CT_MenuBarItem
- drawControl for QStyle::CE_MenuBarItem
- drawCustomControl for QStyleOptionMenuItem
This is not supported by default, mostly because it is not usual an operation that you wish to achieve in here. Of course, you could always use an image with text included, but that is also hackish, unless you paint the image dynamically and then load it later. Although even that would be quite a bit of work.
In order to do, you will need to fiddle with Qt a bit. This is the closest experiment that I would start off with, personally. I have not had time to check whether it actually works, but there should be something among these lines:
class CustomMenuBarWidget : public QWidget
{
public:
explicit CustomMenuBarWidget(QWidget *parent = Q_NULLPTR)
: QWidget(parent)
, menuBar(new QMenuBar())
{
}
virtual void paintEvent(QPaintEvent *event) {
QStyleOptionMenuItem styleOptionMenuItem;
QIcon icon("path/to/my/icon");
styleOptionMenuItem.icon = icon;
styleOptionMenuItem.text = "Hello World!";
QPainter painter(this);
menuBar->style()->drawControl(QStyle::CE_MenuBarItem, &styleOptionMenuItem, &painter, menuBar);
}
private:
QMenuBar *menuBar;
};
You could probably also have a look at QWidgetAction how to insert custom widgets into toolbars and menubars. I have never used that myself in any serious project, but might be useful to be aware of.