Qt 5- QTextEdit reverts to default font - c++

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.

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

How to draw a QStaticText with a mnemonic underline in Qt?

For a custom widget, there are tabs which ban be accessed with the ALT + <C> shortcut where <C> can be any keyboard character key. In Qt, this is called a Mnemonic
For this shortcut, it is needed to have that letter underlined in the label.
I can see that QPainter::drawText has an argument for flags, which can be provided with Qt::TextShowMnemonic but I would like to have this while using QStaticText for performance purpose. QStaticText allows Rich-Text, however underline seems not supported, or I could not make it work.
#include <QApplication>
#include <QDebug>
#include <QStaticText>
#include <QPainter>
#include <QPaintEvent>
#include <QWidget>
class TestWidget: public QWidget
{
Q_OBJECT
public:
explicit TestWidget( QWidget* parent=nullptr):QWidget(parent){}
auto paintEvent(QPaintEvent *event) -> void override
{
QPainter p(this);
QStaticText staticText; // this is not how it should be used, but for the example...
staticText.setTextFormat(Qt::TextFormat::RichText);
staticText.setText("<u>F</u>ile"); //What happens with Underline?
p.drawStaticText(QPoint(50,50), staticText);
p.drawText(QRect(50, 80, 100, 100), Qt::TextShowMnemonic, "&File"); // Ok, this works, but no static-text
}
};
#include "main.moc"
auto main (int argn, char* args[])-> int
{
QApplication app(argn, args);
qDebug() << QT_VERSION_STR;
TestWidget w;
w.resize(200,200);
w.show();
return app.exec();
}
Results in:
The question is:
How to make underline, or &mnemonic to work with QStaticText ?
.
There seems to be a QT-BUG for this, almost 10 years old (it was created in 2012).
QStaticText doesn't support text-decoration css property.
Properties like font-weight, color, font-style do have an effect but the text-decoration does not. See the attached example program where is HTML string using a element to underline a part of the string. This doesn't seem to have any effect using .... Also when using just plain underline tags it doesn't work.
There is also a conflict in the documentation of QStaticText concerning this issue stating that "For extra convenience, it is possible to apply formatting to the text using the HTML subset supported by QTextDocument.". However in the next chapter of the documention is said that "QStaticText can only represent text, so only HTML tags which alter the layout or appearance of the text will be respected. Adding an image to the input HTML, for instance, will cause the image to be included as part of the layout, affecting the positions of the text glyphs, but it will not be displayed. The result will be an empty area the size of the image in the output. Similarly, using tables will cause the text to be laid out in table format, but the borders will not be drawn."
It seems that the HTML subset supported by QTextDocument is not entirely applicable to QStaticText formatting.

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);
}

mix setStyleSheet and setFont: wrong background

I merge several classes and functions into only two classes,
so it looks strange and ugly.
The problem that my class MyW at the end of constructor
set background to white, but it's child QLabel has background
from Page, not from MyW.
And question why?
I know that if I remove magic with fonts in MyW,
or call setStyleSheet at the begining like this:
setStyleSheet("border:none;background:#ffffff;color:#000000;");
I get the right result (white background),
but I can not understand why font make influence to background,
and why there is difference between set stylesheet in two steps,
instead of one?
#include <QApplication>
#include <QLabel>
class MyW : public QWidget {
public:
MyW(QWidget *parent) : QWidget(parent) {
setStyleSheet("border:none;");
setFont(QFont{"Arial", 42});
setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
auto lbl = new QLabel{"AAAA", this};
lbl->ensurePolished();
}
};
class Page : public QWidget {
public:
Page(QWidget *parent) : QWidget{parent} {
setStyleSheet("background:#f0f4f7;");
auto item = new MyW{this};
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Page p{nullptr};
p.resize(400, 800);
p.show();
return a.exec();
}
Update: I removed all not important parts, like layouts, QApplication::setFont and so on.
I am sure that reason is not in auto font = QApplication::font();, but
in QWidget::setFont call. You can check it, for example, by replacing font stuff with:
QFont font;
font.setPixelSize(42);
setFont(font);
The "magic" behind this is cache that is used inside Qt to deal with style sheets.
You can find hint in qtbase/src/widgets/styles/qstylesheetstyle.cpp, look at usage of
static QStyleSheetStyleCaches *styleSheetCaches = 0;
Qt does not use QWidget::styleSheet property directly,
it parses it and caches result.
There are several triggers for parsing(re-parsing) of QWidget::styleSheet:
Call of QWidget::ensurePolished (it is done automatically when your widget
becomes visible for the first time);
Call of setStyleSheet but only in the case if your widget called QWidget::ensurePolished at least once;
Call of QWidget::setFont or QWidget::setPalette (only if your widget does not have an empty styleSheet).
In your case your problem is a combination of (1-2) and (3):
after force caching of the parsed stylesheet via QWidget::setFont your widget is still not "polished",
so the next call of setStyleSheet does not update the cached style sheet that was created on setFont step,
so on the step with lbl->ensurePolished(); you actually have a style sheet with "border:none;" plus font, plus background of parent.
You can call this->ensurePoslished() before lbl->ensurePoslished() to fix this issue or as suggested by #William Miller use stylesheet to set font,
or place setFont after all calls of setStyleSheet
Per the docs on QApplication::setFont(),
Warning: Do not use this function in conjunction with Qt Style Sheets. The font of an application can be customized using the "font" style sheet property. To set a bold font for all QPushButtons, set the application styleSheet() as "QPushButton { font: bold }"
Since they explicitly warn against this I would expect there is an inheritance conflict when using style sheets in conjunction with the application level default font, so the line
QApplication::setFont(font);
and subsequently,
auto font = QApplication::font();
May not produce the expected behavior. Their alternative is set the application-level styleSheet() for your class, i.e.
setStyleSheet(" MyW { font-family: 'Garamond' }");
So it seems the short answer is that they don't support it.
The reason it makes a difference "between set stylesheet in two steps, instead of one" is not because you are setting the style sheet in two different steps but because you call QApplication::font() between the steps and as this is unsupported behavior, it is producing the unexpected result.

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.