QMenu item text disappears when icon added - c++

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.

Related

Setting an icon's size on a QPushButton through Stylesheets

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...)

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.

Close button only for some tabs in Qt

I am using Qt for an assignment I have for college, and I want to use QTabWidget to display a chat window much like Pidgin's. I want to make the "group chat" tab always open and impossible to close and the rest of the "private channel" tabs closable.
QTabWidget's setTabsClosable(bool) is not helping.
Any ideas?
I found an easier solution, I think.
Simply access the relevant close button and resize it.
tabWidget->tabBar()->tabButton(0, QTabBar::RightSide)->resize(0, 0);
Find the bar (it is private, so use findChild()) and remove the buttons. Documentation claims that close buttons may be placed on left side too.
QTabBar *tabBar = ui->tabWidget->findChild<QTabBar *>();
tabBar->setTabButton(0, QTabBar::RightSide, 0);
tabBar->setTabButton(0, QTabBar::LeftSide, 0);
Hallo,
I guess this post won't help the author of this thread but perhaps someone else wanders over here.
In most cases a non-closable tab should not only ignore the closevent it also should not show a close symbol in its corner. A nice way to reach this is to modify the QTabBar which is inside the QTabWidget.
Example:
// let tabWidget be a QTabWidget with at least one page
QPushButton *closeButton = new QPushButton();
// set icon and size for PushButton, ...
// connect Signal clicked() from closeButton with Slot closeCurrentTab(), ...
// next line sets closeButton in right corner on tab with index 0
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, closeButton);
Although tabBar() is indeed protected, Klaus pointed into the right direction. Simply subclass QTabWidget and implement a wrapper method.
You should reimplement your widget's event(Event *e) method, check the type of e, find out CloseEvents, and call parent class's event when you can allow tab to close, or e->ignore() when you do not want it.
Note, then you must parent's event() handle othr events, so do not accept(), reject() or forget them Ж)
I guess you can handle the tabCloseRequest signal and decide whether u'll close a given tab or not
http://doc.qt.io/archives/4.6/qtabwidget.html#tabCloseRequested
Edit: I created a small example to check it out. My example is a simple QtGui application with a mainwindow that has a tabwidget. I then added the tabCloseRequested slot. Here is the code
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
if(someCondition){
return;
} else if(anotherCondition){
ui->tabWidget->removeTab(index);
}
}
From this example only tabs where the condition doesn't apply will be closed.
The best way for adding a pushbutton to some tabs and not in other is to define a subclass of QTabWidget for taking the QTabBar that is a potected!
The code below is tested and it works:
//TabWidget.h
#ifndef TABWIDGET_H
#define TABWIDGET_H
#include <QTabWidget>
class TabWidget : public QTabWidget {
public:
TabWidget(QWidget *parent);
~TabWidget();
QTabBar *tabBar() const;
};
#endif /* TABWIDGET_H */
//TabWidget.cpp
#include "TabWidget.h"
TabWidget::TabWidget(QWidget * p=0) : QTabWidget(p) {}
TabWidget::~TabWidget() {}
QTabBar * TabWidget::tabBar() const {return QTabWidget::tabBar();}
For using this subclass and create a new tab with a custom button you have to following this instructions ( ui->tabWidget is a QTabWidget with setClosableTabs=false):
TabWidget *t = (TabWidget *) ui->tabWidget;
t->addTab(new QWidget, "empty");
QTabBar *tab = t->tabBar();
QPushButton *b = new QPushButton();
b->setText("x");
tab->setTabButton(tab->count() -1, QTabBar::RightSide, b);
connect(b,SIGNAL(...),this,SLOT(...));
Not sure, why nobody here mentioned the simplest working solution:
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, 0);
This completely removes the close button, and the space taken by it.
Documentation

setCentralWidget() causing the QMainWindow to crash.. Why?

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
this->setupUi(this);
this->setupActions();
this->setWindowTitle(tr("CuteEdit"));
label = new QLabel(tr("No Open Files"));
this->setCentralWidget(label);
label->setAlignment(Qt::AlignCenter);
}
By above code, I get a GUI like this(Its a screenshot of whole screen, Only observe the window displayed in middle of page of ebook). (I used QT Designer)
Now, i want user to select File->Open.. A Dialog appears and file gets selected.. Its contents are to be displayed in *textEdit widget..
Function for that is below..
void MainWindow::loadFile()
{
QString filename = QFileDialog::getOpenFileName(this);
QFile file(filename);
if (file.open(QIODevice::ReadOnly|QIODevice::Text))
{
label->hide();
textEdit->setPlainText(file.readAll());
mFilePath = filename;
QMainWindow::statusBar()->showMessage(tr("File successfully loaded."), 3000);
}
}
The window crashes at line:-
textEdit->setPlainText(file.readAll());
But if i comment the line:-
this->setCentralWidget(label);
i mean i remove label as being the central widget, the program runs as expected.. Why?
And also, I am not clear about the concept of CentralWidget. Pls guide.
JimDaniel is right in his last edit. Take a look at the source code of setCentralWidget():
void QMainWindow::setCentralWidget(QWidget *widget)
{
Q_D(QMainWindow);
if (d->layout->centralWidget() && d->layout->centralWidget() != widget) {
d->layout->centralWidget()->hide();
d->layout->centralWidget()->deleteLater();
}
d->layout->setCentralWidget(widget);
}
Do you see that if your MainWindow already had centralWidget() Qt schedules this object for deletion by deleteLater()?
And centralWidget() is the root widget for all layouts and other widgets in QMainWindow. Not the widget which is centered on window. So each QMainWindow produced by master in Qt Creator already has this root widget. (Take a look at your ui_mainwindow.h as JimDaniel proposed and you will see).
And you schedule this root widget for deletion in your window constructor! Nonsense! =)
I think for you it's a good idea to start new year by reading some book on Qt. =)
Happy New Year!
Are you sure it's not label->hide() that's crashing the app? Perhaps Qt doesn't like you hiding the central widget. I use Qt but I don't mess with QMainWindow that often.
EDIT: I compiled your code. I can help you a bit. Not sure what the ultimate reason is as I don't use the form generator, but you probably shouldn't be resetting the central widget to your label, as it's also set by the designer, if you open the ui_mainwindow.h file and look in setupGui() you can see that it has a widget called centralWidget that's already set. Since you have used the designer for your GUI, I would use it all the way and put the label widget in there as well. That will likely fix your problems. Maybe someone else can be of more help...
I'm not sure I understood your problem, neither what the guys above said (which I guess are valid information) and it seems to be an old topic.
However, I think I had a problem that looks like this and solved it, so I want to contribute my solution in case it helps anyone.
I was trying to "reset" central widget using QLabels. I had three different ones, switch from first to second, then to third and failed to switch back to the first one.
This is my solution that worked:
Header file
QLabel *imageLabel;
Constructor
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Reset
imageLabel = NULL;
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Hope that helps
Aris