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

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

Related

How to Fix QStatusBar that stops to work if placed it in Layout?

I succeeded to moved the QStatusBar to a specific location (repositioning), but when I hover I don't see the tips anymore. I tried QStatusBar.show() or .setVisible(True) but doesn't still work. How would you approach this. Thanks
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<widget name="__qt_fake_top_level">
<widget class="QPushButton" name="greetBTN">
<property name="geometry">
<rect>
<x>70</x>
<y>10</y>
<width>75</width>
<height>24</height>
</rect>
</property>
<property name="statusTip">
<string>Greeting people,...</string>
</property>
<property name="text">
<string>greet</string>
</property>
</widget>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>30</x>
<y>40</y>
<width>241</width>
<height>80</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_status"/>
</widget>
<widget class="QPushButton" name="closeBTN">
<property name="geometry">
<rect>
<x>160</x>
<y>10</y>
<width>75</width>
<height>24</height>
</rect>
</property>
<property name="statusTip">
<string>About to close</string>
</property>
<property name="text">
<string>close</string>
</property>
</widget>
</widget>
<resources/>
</ui>
converted to Python
# -*- coding: utf-8 -*-
from PySide5.QtCore import *
from PySide5.QtGui import *
from PySide5.QtWidgets import *
class Ui_AppMainWindow(object):
def setupUi(self, AppMainWindow):
if not AppMainWindow.objectName():
AppMainWindow.setObjectName(u"AppMainWindow")
AppMainWindow.resize(303, 190)
self.centralwidget = QWidget(AppMainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.greetBTN = QPushButton(self.centralwidget)
self.greetBTN.setObjectName(u"greetBTN")
self.greetBTN.setGeometry(QRect(70, 10, 75, 24))
self.closeBTN = QPushButton(self.centralwidget)
self.closeBTN.setObjectName(u"closeBTN")
self.closeBTN.setGeometry(QRect(160, 10, 75, 24))
self.gridLayoutWidget = QWidget(self.centralwidget)
self.gridLayoutWidget.setObjectName(u"gridLayoutWidget")
self.gridLayoutWidget.setGeometry(QRect(30, 40, 241, 80))
self.gridLayout_status = QGridLayout(self.gridLayoutWidget)
self.gridLayout_status.setObjectName(u"gridLayout_status")
self.gridLayout_status.setContentsMargins(0, 0, 0, 0)
AppMainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(AppMainWindow)
self.statusbar.setObjectName(u"statusbar")
AppMainWindow.setStatusBar(self.statusbar)
self.retranslateUi(AppMainWindow)
QMetaObject.connectSlotsByName(AppMainWindow)
# setupUi
def retranslateUi(self, AppMainWindow):
AppMainWindow.setWindowTitle(QCoreApplication.translate("AppMainWindow", u"MainWindow", None))
#if QT_CONFIG(statustip)
self.greetBTN.setStatusTip(QCoreApplication.translate("AppMainWindow", u"Greeting people,...", None))
#endif // QT_CONFIG(statustip)
self.greetBTN.setText(QCoreApplication.translate("AppMainWindow", u"greet", None))
#if QT_CONFIG(statustip)
self.closeBTN.setStatusTip(QCoreApplication.translate("AppMainWindow", u"About to close", None))
#endif // QT_CONFIG(statustip)
self.closeBTN.setText(QCoreApplication.translate("AppMainWindow", u"close", None))
# retranslateUi
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import *
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('Xuntitled.ui', self)
self.statusbar.setVisible(True)
self.statusbar.setStyleSheet('Background:red;')
self.statusbar.setParent(self)
#self.statusbar.showMessage('sqddsfdsfd') # works but if I hover, nothing !
self.statusbar.move(50, 25)
self.gridLayout_status.addWidget(self.statusbar, 1, 1)
self.show()
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
The expected behavior of a status bar is to be shown on the bottom margin of the window, allowing temporary messages and also providing an internal layout for "extra widgets" displayed in it.
If you want to show the status tip somewhere else, then you probably don't need a QStatusBar at all, and a basic QLabel will suffice.
The only requirement is to override the event() function of the window and check for StatusTip events.
In the following example I assumed that you don't really need the default status bar (so you should remove it from Designer and update the generated uic file accordingly if you use that approach).
class Ui(QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('Xuntitled.ui', self)
self.fakeStatusBar = QLabel()
self.gridLayout_status.addWidget(self.fakeStatusBar)
def event(self, event):
if event.type() == event.StatusTip:
self.fakeStatusBar.setText(event.tip())
return True
return super().event(event)

Problem with Tristate QCheckBox not repainting itself when set programmatically

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.

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>

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