Problem with Tristate QCheckBox not repainting itself when set programmatically - qt

When I have a QCheckBox with tristate set true, it does not repaint itself when transitioning from Qt:PartiallyChecked to setChecked(true) programatically.
A minimal example built in QDesigner places a QCheckBox and QPushButton on the central widget of the default MainWindow. The QCheckBox is default configured except tristate is checked. In code, the ui checkBox is set to Qt::PartiallyChecked in the constructor, and an on_pushButton_clicked() function calls ui->checkBox->setChecked( true );
Expected behavior: when pushButton is clicked, checkBox should change from partially checked to checked appearance.
Observed behavior: checkBox appearance does not change until moused over.
Note: it's even worse when the checkbox has been restyled to be used as a tri-state indicator and is not enabled for user input... the disabled checkbox doesn't repaint on mouseover then.
I discovered this behavior in Ubuntu 18.04 default using the native 5.9.5 Qt libraries running in release mode, but it is also reproducible in 5.14.2 and many other library versions.
The sample code below is 99% the default Qt Widgets application with modification as described above.
The only workaround I have found so far is to repaint the QCheckBox widget anytime its state is changed... not great, but at least it works.
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{ ui->setupUi(this);
ui->checkBox->setCheckState( Qt::PartiallyChecked );
}
MainWindow::~MainWindow()
{ delete ui; }
void MainWindow::on_pushButton_clicked()
{ ui->checkBox->setChecked( true );
// Uncomment the repaint() for a kludgey fix
// ui->checkBox->repaint();
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>173</width>
<height>98</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QCheckBox" name="checkBox">
<property name="geometry">
<rect>
<x>40</x>
<y>10</y>
<width>92</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>CheckBox</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>40</x>
<y>50</y>
<width>89</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
Tristate.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

Best patch I know so far is to repaint the QCheckBox whenever its state is changed.

Related

Gtk+3 change label coloring on the fly doesn't change text background

I am new to Gtk+3. I'm used to the Visual Basic way of designing GUIs. I've been very frustrated by all the hoops Gtk put me through, but I think I've researched and solved all my problems but one. This is latest Gtk+3 on a raspberry pi, and I used Glade to tack together the layout. The goal is to have individual labels change background color and text color under software control. Note this is strictly a display - no input controls, just grids, layout boxes, and labels.
I almost have it working. When my code runs, it alternates applying and removing a given css style. I can see the result. But the label has 3 separate attributes of interest: the background color of the label itself, the background color of the text (the text doesn't fill the whole label), and the color of the text itself. My code successfully changes the background of the label, and the color of the text, but not the background of the text. I need the text background to match the label background in all cases. Making the text background color be always transparent would be one approach; changing both background colors at the same time would be another. How do I?
Here's the CSS of interest:
* {
background-color: black;
color: whitesmoke;
}
.redStyle {
background-color: rgb(182, 8, 8);
color: whitesmoke;
}
.pinkStyle {
background-color: rgb(241, 135, 135);
color: black;
}
The test code alternately calls these two functions from Gtk's idle mechanism.
gboolean flashing1(void*)
{
GtkWidget* widget = GTK_WIDGET(gtk_builder_get_object (builder, "labObsession"));
GtkStyleContext *context = gtk_widget_get_style_context(widget);
gtk_style_context_add_class(context,"pinkStyle");
gtk_widget_queue_draw(widget);
return false;
}
gboolean flashing2(void*)
{
GtkWidget* widget = GTK_WIDGET(gtk_builder_get_object (builder, "labObsession"));
GtkStyleContext *context = gtk_widget_get_style_context(widget);
gtk_style_context_remove_class(context,"pinkStyle");
gtk_widget_queue_draw(widget);
return false;
}
Please help. It two two days of googling to get even this far. I know there's a depreciated override function that probably does this but I'm trying to avoid that.
For extra credit, why do I see
** (a.out:26251): WARNING **: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files
Whenever I start?
Here's the full code of the test app:
#include <gtk/gtk.h>
#include <thread>
#include <iostream>
static GtkBuilder *builder;
gboolean flashing1(void*)
{
GtkWidget* widget = GTK_WIDGET(gtk_builder_get_object (builder, "labObsession"));
GtkStyleContext *context = gtk_widget_get_style_context(widget);
gtk_style_context_add_class(context,"pinkStyle");
gtk_widget_queue_draw(widget);
return false;
}
gboolean flashing2(void*)
{
GtkWidget* widget = GTK_WIDGET(gtk_builder_get_object (builder, "labObsession"));
GtkStyleContext *context = gtk_widget_get_style_context(widget);
gtk_style_context_remove_class(context,"pinkStyle");
gtk_widget_queue_draw(widget);
return false;
}
void flashingTh(GtkWidget*) //may need this param someday
{
for (;;)
{
usleep(50 * 1000);
gdk_threads_add_idle (flashing1, nullptr);
usleep(90 * 1000);
gdk_threads_add_idle (flashing2, nullptr);
}
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "randomness/Lachesis.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
gtk_builder_connect_signals(builder, NULL);
// g_object_unref(builder); //keep. needed to find things. Ugh.
//GtkStyleContext *context;
GtkCssProvider *provider = gtk_css_provider_new ();
gtk_css_provider_load_from_path (provider,
"randomness/lachesis.css",
nullptr);
gtk_style_context_add_provider_for_screen (gdk_screen_get_default(),
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
gtk_widget_show(window);
std::thread(flashingTh, window).detach();
gtk_main();
return 0;
}
//not hooked up yet, signals can wait until painting works
// called when window is closed
void on_window_main_destroy()
{
gtk_main_quit();
}
And here's a fragment of the .glade:
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="title" translatable="yes">Lachesis</property>
<property name="window_position">center-always</property>
<property name="hide_titlebar_when_maximized">True</property>
<child>
<object class="GtkGrid" id="topGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="labObsession">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Controller: unknown</property>
<attributes>
<attribute name="background" value="#000000000000"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
It turns out that if you define labels via Glade, and set the Attributes that way, nothing (at least nothing obvious) you can do in your code will change the background or foreground color of the text. Not css, not the depreciated functions, not pango markup. I haven't researched why and I don't care - the bottom line is, don't Edit Attributes in glade if you want subsequent control over those attributes. Once I cleared the attributes, I was able to use markup strings to control the color and background of text from my code.

A QWidget in a QLayout is shifted and cut when window is maximized

There is a simple GUI: main window with a default central widget. A layout is added to it and then a widget of interest is placed to the layout.
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.uic import loadUiType
FormClass, QtBaseClass = loadUiType('main_window.ui')
class MainWindow(FormClass, QtBaseClass):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.fig = Figure(facecolor='yellow', edgecolor='red', linewidth=0.1)
self.canvas = FigureCanvas(self.fig)
hbox_layout = QtWidgets.QHBoxLayout(self.centralwidget)
hbox_layout.addWidget(self.canvas, stretch=2)
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
main_window.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1024</width>
<height>768</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1024</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
When the main window is not maximized, everything seems good:
The whole widget is visible (notice a red border, it was added to monitor the edges of the widget).
But if we maximize the main window, this is what happens:
Looks like the widget is shifted upwards, the top border of the widget disappears, while at the bottom a black line appears under the edge.
I've tested it with HBox/VBox/Grid layouts, the result is always the same. This happens if there is only one widget in a column. If we add one more widget to the column, both widgets will be fully visible.
Why does it happen and how to fix this behavior? Are we not supposed to have a single widget in a column inside a layout?
OS: Windows 10
Qt: 5.6.2
PyQt: 5.6.0
I just checked it by creating a new Qt Widgets Application and the issue is not present. To paint the widget I use Qt Style Sheets as follow:
QWidget {
border: 1px solid red;
background-color: yellow;
}
When the application runs it shows well even maximized (see bellow). Re-evaluate the method you use to paint the widget. You can change Style Sheets by using the Style Sheet property in the designer.
See also: Qt Style Sheets Syntax.

How to use setupUi or uic output to create a free-standing layout without a parent widget?

The output generated by uic from a .ui files always installs the layouts and child widgets on an existing widget. This works great when you intend to add the layout/children directly on a widget:
#include "ui_form.h"
QWidget widget;
Ui::Form ui;
ui.setupUi(&widget);
Alas, sometimes the intervening widget is unnecessary. First of all, layouts on widgets have non-zero margins, so if you intend to insert the contents of Ui::Form into a layout, you'll have to reset the margins:
QWidget top;
QVBoxLayout layout{&top};
QWidget widget;
Ui::Form ui;
ui.setupUi(&widget);
widget.layout()->setContentsMargins(0,0,0,0);
layout.addWidget(&widget);
Furthermore, in this case the intervening widget is completely unnecessary. Suppose we had setupUi that didn't need a top-level widget (as of Qt 5.7, it crashes when passed a nullptr). We could use it as follows:
QWidget top;
QVBoxLayout layout{&top};
Ui::Form ui;
ui.setupUi(nullptr);
layout.addLayout(ui.layout); // assuming `layout` is the top-level layout there
I've inspected uic and it doesn't support emitting code without a top-level widget. It's true that the needed patch would be minuscule.
Yet, is there any way to implement something to the effect of nullptr-accepting setupUi without patching Qt?
Lest someone think this is a made-up problem: This question was prompted in part by this code from YUView. There, the parentWidget passed to setupUi already has a layout, the purpose being to add the form's layout to another layout after setupUi is done. QWidget::setLayout invoked from inside of setupUi refuses to set the new layout, emits a warning, and things just happen to work in spite of it. The code is brittle since it depends on Qt code breaking just the right way to lead to the desired result.
Yes. The key observations that enable us to do so are:
A childLayout can be removed from its parent layout by nulling its parent:
childLayout->setParent(nullptr);
A parentless layout will, upon adding it to a widget or a layout with non-null parentWidget(), reparent its children.
Thus, we need to add an additional top-level wrapper layout to the form, then unparent the target top level layout from it, and delete the wrapper. The form's structure as reported by dumpObjectTree is:
QWidget::Form
QVBoxLayout::wrapper
QVBoxLayout::layout
QHBoxLayout::horizontalLayout
QLabel::label
QLabel::label_2
QLabel::label_3
The test case:
// https://github.com/KubaO/stackoverflown/tree/master/questions/layout-take-40497358
#include <QtWidgets>
#include "ui_form.h"
QLayout * takeLayout(QWidget *);
int main(int argc, char ** argv)
{
QApplication app{argc, argv};
QWidget parent;
QHBoxLayout layout{&parent};
Ui::Form ui;
{
QWidget w;
ui.setupUi(&w);
w.dumpObjectTree();
if (true) {
ui.layout->setParent(nullptr);
delete ui.wrapper;
layout.addLayout(ui.layout);
} else {
layout.addLayout(takeLayout(&w));
}
}
parent.show();
return app.exec();
}
If you wished to factor this functionality out, you'd have a template setupLayout function that you'd use in place of setupUi. The testcase above would become:
QWidget parent;
QHBoxLayout layout{&parent};
Ui::Form ui;
layout.addLayout(setupLayout(&ui));
parent.show();
The setupLayout is:
//*** Interface
QLayout * setupLayout_impl(void * ui, void(*setupUi)(void * ui, QWidget * widget));
// Extracts the top layout from a Ui class generated by uic. The top layout must
// be enclosed in a wrapper layout.
template <typename Ui> QLayout * setupLayout(Ui * ui) {
struct Helper {
static void setupUi(void * ui, QWidget * widget) {
reinterpret_cast<Ui*>(ui)->setupUi(widget);
}
};
return setupLayout_impl(static_cast<void*>(ui), &Helper::setupUi);
}
//*** Implementation
static void unparentWidgets(QLayout * layout) {
const int n = layout->count();
for (int i = 0; i < n; ++i) {
QLayoutItem * item = layout->itemAt(i);
if (item->widget()) item->widget()->setParent(0);
else if (item->layout()) unparentWidgets(item->layout());
}
}
QLayout * setupLayout_impl(void * ui, void(*setupUi)(void * ui, QWidget * widget))
{
QWidget widget;
setupUi(ui, &widget);
QLayout * wrapperLayout = widget.layout();
Q_ASSERT(wrapperLayout);
QObjectList const wrapperChildren = wrapperLayout->children();
Q_ASSERT(wrapperChildren.size() == 1);
QLayout * topLayout = qobject_cast<QLayout*>(wrapperChildren.first());
Q_ASSERT(topLayout);
topLayout->setParent(0);
delete wrapperLayout;
unparentWidgets(topLayout);
Q_ASSERT(widget.findChildren<QObject*>().isEmpty());
return topLayout;
}
What if you can't or are unwilling to alter the form's structure? You can use Qt's internals to implement a takeLayout function that rips out a widget's layout and returns it, unattached to the widget. Note that the private QWidget::takeLayout is insufficient, as it returns a layout with its topLevel flag set: such layouts can only be installed directly on widgets, and will fail an assertion when one attempts to add them to a layout (as a sub-layout). Here's how:
#include <private/qwidget_p.h>
#include <private/qlayout_p.h>
class WidgetHelper : private QWidget {
struct LayoutHelper : private QLayout {
static void resetTopLevel(QLayout * l) {
auto d = static_cast<QLayoutPrivate*>(static_cast<LayoutHelper*>(l)->d_ptr.data());
d->topLevel = false;
}
};
public:
static QLayout * takeLayout(QWidget * w) {
auto d = static_cast<QWidgetPrivate*>(static_cast<WidgetHelper*>(w)->d_ptr.data());
auto l = w->layout();
if (!l) return nullptr;
d->layout = 0;
l->setParent(nullptr);
LayoutHelper::resetTopLevel(l);
return l;
}
};
QLayout * takeLayout(QWidget * w) { return WidgetHelper::takeLayout(w); }
The form.ui looks as follows:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<layout class="QVBoxLayout" name="wrapper">
<item>
<layout class="QVBoxLayout" name="layout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Top</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Left</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Right</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</ui>

How to do QtCreator's steps in compiling qt project manually?

I'm new in Qt and trying to do a text editor example from Qt 5. But, I'm doing that without QtCreator. Of course I have QtCreator installed, I just want to try doing that example without QtCreator. My steps in doing this are:
Write main.cpp, notepad.cpp and notepad.h exactly like in the
example. (Except for include preprocessor, I write the complete
path like:
#include <qt/QtWidgets/QMainWindow>
not just:
#include <QMainWindow>
Create notepad.ui file with QtDesigner.
Generate ui_notepad.h file with uic-qt5 notepad.ui > ui_notepad.h
command.
Generate notepad.pro file with qmake-qt5 -project command.
Add these lines in notepad.pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
Generate Makefile with qmake command.
Do make command.
Those step is what I can understand on how QtCreator doing the task automatically. And then, make complaints about incomplete type and forward declaration. But, If I'm doing this with QtCreator, the project is compiled just fine.
What did I miss there?
These are the error messages that I get:
notepad.cpp: In constructor ‘Notepad::Notepad(QWidget*)’:
notepad.cpp:4:72: error: invalid use of incomplete type ‘class Ui::Notepad’
Notepad::Notepad (QWidget* parent) : QMainWindow (parent), ui (new Ui::Notepad) {
^
In file included from notepad.cpp:1:0:
notepad.h:4:8: error: forward declaration of ‘class Ui::Notepad’
class Notepad;
^
notepad.cpp:5:4: error: invalid use of incomplete type ‘class Ui::Notepad’
ui->setupUi (this);
^
In file included from notepad.cpp:1:0:
notepad.h:4:8: error: forward declaration of ‘class Ui::Notepad’
class Notepad;
^
notepad.cpp: In destructor ‘virtual Notepad::~Notepad()’:
notepad.cpp:9:9: warning: possible problem detected in invocation of delete operator: [-Wdelete-incomplete]
delete ui;
^
notepad.cpp:9:9: warning: invalid use of incomplete type ‘class Ui::Notepad’
In file included from notepad.cpp:1:0:
notepad.h:4:8: warning: forward declaration of ‘class Ui::Notepad’
class Notepad;
^
notepad.cpp:9:9: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined
delete ui;
^
Makefile:660: recipe for target 'notepad.o' failed
make: *** [notepad.o] Error 1
Update
ui_notepad.h file:
/********************************************************************************
** Form generated from reading UI file 'notepad.ui'
**
** Created by: Qt User Interface Compiler version 5.4.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_NOTEPAD_H
#define UI_NOTEPAD_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralwidget;
QVBoxLayout *verticalLayout_2;
QVBoxLayout *verticalLayout;
QTextEdit *textEdit;
QPushButton *quitButton;
QMenuBar *menubar;
QStatusBar *statusbar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QStringLiteral("MainWindow"));
MainWindow->resize(800, 600);
centralwidget = new QWidget(MainWindow);
centralwidget->setObjectName(QStringLiteral("centralwidget"));
verticalLayout_2 = new QVBoxLayout(centralwidget);
verticalLayout_2->setObjectName(QStringLiteral("verticalLayout_2"));
verticalLayout = new QVBoxLayout();
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
textEdit = new QTextEdit(centralwidget);
textEdit->setObjectName(QStringLiteral("textEdit"));
verticalLayout->addWidget(textEdit);
quitButton = new QPushButton(centralwidget);
quitButton->setObjectName(QStringLiteral("quitButton"));
verticalLayout->addWidget(quitButton);
verticalLayout_2->addLayout(verticalLayout);
MainWindow->setCentralWidget(centralwidget);
textEdit->raise();
quitButton->raise();
menubar = new QMenuBar(MainWindow);
menubar->setObjectName(QStringLiteral("menubar"));
menubar->setGeometry(QRect(0, 0, 800, 27));
MainWindow->setMenuBar(menubar);
statusbar = new QStatusBar(MainWindow);
statusbar->setObjectName(QStringLiteral("statusbar"));
MainWindow->setStatusBar(statusbar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
quitButton->setText(QApplication::translate("MainWindow", "Quit", 0));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_NOTEPAD_H
notepad.ui file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="textEdit"/>
</item>
<item>
<widget class="QPushButton" name="quitButton">
<property name="text">
<string>Quit</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<zorder>textEdit</zorder>
<zorder>quitButton</zorder>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
Classes namespaced in Ui:: are automatically generated by the Qt UIC metacompiler after compiling .ui files. Your code expects Ui::Notepad to be generated and automatically linked into the project with qmake/uic.
After looking at the XML of the .ui file that QtDesigner creates, you can see the following line:
<class>MainWindow</class>
That means that the class Ui::MainWindow is generated. If you wanted to generate Ui::Notepad instead, open the .ui form in QtDesigner and rename the top level widget from MainWindow to Notepad. Then Ui::Notepad would appear in your project.
It would cause the XML to look like <class>Notepad</class> which would make Ui::Notepad available in your code

QUiLoader errơr when loading .ui file

I'm trying to load a simple .ui file using QUiLoader and I'm getting the following error:
Designer: An error has occurred while reading the UI file at line 1, column 0: Premature end of document.
I checked that the .ui file exists and printed its contents.
Code:
QApplication a(argc, argv);
MainWindow w;
w.show();
QUiLoader loader;
qDebug()<< QDir::currentPath();
QFile file("customwidget.ui");
qDebug() <<"File open: "<< file.open(QIODevice::ReadOnly| QIODevice::Text );
QWidget *formWidget;
qDebug() << file.readAll();
qDebug() <<"Loader: "<<(formWidget=loader.load(&file,&w));
file.close();
formWidget->show();
return a.exec();
Output:
"/home"
File open: true
"<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>customWidget</class>
<widget class="QWidget" name="customWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>200</width>
<height>200</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>50</x>
<y>60</y>
<width>87</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
"
Designer: An error has occurred while reading the UI file at line 1, column 0: Premature end of document.
Loader: QObject(0x0)
The customwidget.ui file was generated using the QTDesigner and is placed at /home.
Why is this not working?
you already read the entire file, do a file.reset() before the load or just don't read it first:
QUiLoader loader;
qDebug()<< QDir::currentPath();
QFile file("customwidget.ui");
qDebug() <<"File open: "<< file.open(QIODevice::ReadOnly| QIODevice::Text );
QWidget *formWidget;
qDebug() << file.readAll();
file.reset();//or file.seek(0);
qDebug() <<"Loader: "<<(formWidget=loader.load(&file,&w));
file.close();
formWidget->show();

Resources