Handling multiple ui files in Qt - c++

I am new to the Qt framework and am trying to load another UI file when SubmitClicked. The file's name is Form.ui
//MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "form.h"
#include <QtCore/QCoreApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow:: SubmitClicked()
{
Form* f= new Form(this);
f->show();
f->raise();
f->activateWindow();
}
//Form.cpp
#include "form.h"
#include "ui_form.h"
Form::Form(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form)
{
ui->setupUi(this);
}
Form::~Form()
{
delete ui;
}
This didn't work out! Can you tell me what's wrong?

The .ui file is simply where the code for GUI elements gets stored. This code is generated by the QtDesigner in most cases. It's similar to Visual Studio's .rc file and wizard generated GUI in function and form. This file will either be loaded at compile time which is the default or at runtime via the QUiLoader. If you want dynamically generated UI at runtime the latter is the option you need to look into starting with QtUiTools
On a side note the class Form does not exist in Qt so this is either a class you made or a typo. If you simply want to declare and show a window or dialog then derive from the appropriate base class and call show() or the appropriate method.
For example something simple like this where MainWindow is your own user defined class derived from QMainWindow:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(application);
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
return app.exec();
}
Edit:
Ah so Form is a QWidget class. Are you missing the Q_OBJECT macro in your Form class? You also generally only call setupUi once for the main window of the application to load your resources and such where as user defined subclasses it's often easier to define gui objects for the class programmatically.
//Form.h
class Form : public QWidget
{
Q_OBJECT // this is needed for the MOC aka qmake
public:
Form(QWidget *parent);
virtual ~Form();
private:
QTextEdit m_text;
};
//Form.cpp
#include "form.h"
Form::Form(QWidget *parent) : QWidget(parent)
{
setCentralWidget(&m_text);
}
Form::~Form()
{
}
It sounds almost like you're confusing your class object with your ui namespace files.

Related

Recursive Constructor Invocation when creating a Widget with form in QT?

I'm trying to understand the automatically code generated why QT when creating a QWidget with a Form.
This is the code generated by QT:
**********************************************************************
* widget.h
**********************************************************************
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#endif // WIDGET_H
**********************************************************************
* widget.cpp
**********************************************************************
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
**********************************************************************
* main.cpp
**********************************************************************
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
My question is with this statement in the constructor:
ui(new Ui::Widget)
This is creating a new Widget when the constructor of class Widget is called.
It's like recurssion isn't it? Why doesn`t it break?
It is not recursive it s the instance of your ui_Widget.h Class since you need only one instance of your GUI at a time
The advantage of this approach is that the user interface object can be forward-declared, which means that we do not have to include the generated ui_Widget.h file in the header. The form can then be changed without recompiling the dependent source files. This is particularly important if the class is subject to binary compatibility restrictions.because as you can see the " #include "ui_widget.h"
is inside the cpp a not in the headers file
NO. Because of namespaces there are two different classes with the same name:
Ui::Widget
and
Widget
Ui::Widget is the class for the form object.

Memory Leak in QWebEngineView

I am trying to make a window with a QWebEngineView, and delete the QWebEngineView after the window closes. However, the QWebEngineView never seems to get deleted, and keeps running any QUrl I have loaded (e.g. a YouTube video). In my program, I have a QMainWindow with a Line Edit and a Push Button, that creates a window that loads the URL entered by the user. Here is my code:
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "subwindow.h"
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
void init();
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
SubWindow *sub;
};
#endif // MAINWINDOW_H
SubWindow.h
#ifndef SUBWINDOW_H
#define SUBWINDOW_H
#include <QMainWindow>
#include <QtWebEngineWidgets/qwebengineview.h>
#include <QTimer>
namespace Ui
{
class SubWindow;
}
class SubWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SubWindow(QWidget *parent = 0);
void doWeb(QString link);
~SubWindow();
private:
Ui::SubWindow *ui;
QWebEngineView *web;
private slots:
void on_pushButton_clicked();
};
#endif // SUBWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::init()
{
this->showMaximized();
sub = new SubWindow(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
sub->doWeb(ui->lineEdit->text());
}
SubWindow.cpp
#include "subwindow.h"
#include "ui_subwindow.h"
SubWindow::SubWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::SubWindow)
{
ui->setupUi(this);
}
void SubWindow::doWeb(QString link)
{
this->show();
web = new QWebEngineView(this);
ui->verticalLayout->addWidget(web);
web->load(QUrl(link, QUrl::TolerantMode));
web->show();
}
SubWindow::~SubWindow()
{
delete web; //Doesn't seem to work, since memory is still allocated in task manager
delete ui;
}
void SubWindow::on_pushButton_clicked()
{
this->close(); //Artifact for testing purposes.
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.init();
return a.exec();
}
I have also tried using "web->close();" (which I put on the line where I have the testing artifact) in conjunction with
"web->setAttribute(Qt::WA_DeleteOnClose);" (which I put after "web = new QWebEngineView(this);"), but that didn't solve my issue either. Anyone know what I am doing wrong?
You are creating QWebEngineView with parent "this" (owner) so you don't have to delete it yourself, it will be automatically deleted when it parent will. See Qt documentation about memory management :
http://doc.qt.io/qt-5/objecttrees.html
it is also dangerous doing that, because if you don't create the QWebEngineView object using doWeb(QString link), you will try to delete something that doesn't exist and therefore it can lead you to undefined behavior.
remove delete web from your destructor and see if you always have the problem.
Edit :
The reason why it is not destroyed : you aren't destroying SubWindow Object (the owner of QWebEngineView Object). You can Verify it yourself by printing something in the destructor.
If you were destroying SubWindow object, the second time you push the button in MainWindow, your application will crashes. Since you aren't creating the SubWindow object inside your function on_push_button, but inside MainWindow::init. Your SubWindow Object is only hidden and not destroyed. It is destroyed only when you close the MainWindow. You are also Creating an instance of QWebEngineview each time you show sub (SubWindow Object), so if you show sub 3 times you will have 3 QWebEngineView inside your Subwindow.
the changes i would do to the code :
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.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "subwindow.h"
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
SubWindow* sub;
};
#endif
mainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow), sub(new SubWindow(this))
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
sub->show();
sub->doWeb(ui->lineEdit->text());
}
subWindow.h
#ifndef SUBWINDOW_H
#define SUBWINDOW_H
#include <QMainWindow>
#include <QtWebEngineWidgets/qwebengineview.h>
#include <QTimer>
namespace Ui
{
class SubWindow;
}
class SubWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SubWindow(QWidget *parent = 0);
void doWeb(QString link);
~SubWindow();
private:
Ui::SubWindow *ui;
QWebEngineView *web;
private slots:
void on_pushButton_clicked();
};
#endif // SUBWINDOW_H
subWindow.cpp
#include "subwindow.h"
#include "ui_subwindow.h"
SubWindow::SubWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::SubWindow),
web(new QWebEngineView(this))
{
ui->setupUi(this);
ui->verticalLayout->addWidget(web);
}
void SubWindow::doWeb(QString link)
{
web->load(QUrl(link, QUrl::TolerantMode));
}
SubWindow::~SubWindow()
{
delete ui;
}
void SubWindow::on_pushButton_clicked()
{
this->close(); //Artifact for testing purposes.
}
Note that i am also not destroying subWindow object, but i m not creating QWebView each time i call the method SubWindow::doWeb(String).
If it was up to me i would use a Subclassed Dialog that is not a member of MainWindow, the object would be created inside MainWindow::on_pushButton_clicked() and destroyed when i finish using it.
OK, apparently I needed to call "web->deleteLater();" before calling
"this->close();". The "delete web;" was uneeded. Still, I'd like to know why delete doesn't work in this case...
Looks like something was not closed correctly.
I was using Qt 5.15 using the kit MSVC2019 32bit compiler. But Visual Studio 2017 (and not 2019) was installed on my computer. Thus, the compiler detected in Qt creator -> project -> manage kit -> compiler was the one of MSVC2017 i.e : Microsoft visual C++ compiler 15.8 (x86).
The solution is to install visual Studio 2019 and then replace Qt creator by the correct compiler (2019) i.e: Microsoft visual c++ compiler 16.7 (X86).
Then I could compile without any leak of memory anymore.

QPushButton - How to append strings of text in a Line Edit box via PushButton

I'm starting to learn Qt and coding. I have a basic project in mind, for practice purposes.
Here is a pic of my small UI:
Bear with me please because I am just starting in cpp.
I would like the QPushButton to append this string -> "text" inside the text box after I click it.
Clicking twice would result in having "texttext" and so on.
I have seen this question answered:
QT creating push buttons that add text to a text edit box
The solution mentioned there seems to be what I need, I just don't understand how to integrate it to my project.
Is there anyone that would be able to help out ?
I have these files so far:
test.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
mainwindow.h :
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void addTextTolable();
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();
}
and mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(this- >addTextToLabel()));
}
void MainWindow::addTextTolable()
{
ui->textEdit->appendPlainText("test");
}
MainWindow::~MainWindow()
{
delete ui;
}
This is the last error I have
mainwindow.cpp:-1: In member function 'void MainWindow::addTextTolable()':
mainwindow.cpp:14: error: 'class QTextEdit' has no member named 'appendPlainText'
ui->textEdit->appendPlainText("test");
^
Welcome to C++ and Qt coding! It's a lot of fun, but there are a lot of things going on. I'll try my best to modify your existing stuff to explain. Classes inherited from QObject send signals to each other through Qt's signal/slot architecture. So, this is what you'll do.
1.) Declare a slot function in the mainwindow header file. This is just a normal function declaration, except placed under a slots: tab.
2.) Connect the signal from the QPushButton's "clicked(bool)" to the mainwindow slot, usually in the MainWindow constructor
So here's the modified code.
mainwindow.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
/*IMPORTANT NOTE: Q_OBJECT must appear in the beginning of the header of any object you want to use signals/slots for*/
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
/*Declare the function to be called when the QPushButton is clicked*/
private slots:
void addTextToLabel();
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();
}
and mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*It's very important to note that doing anything with the ui object must be done AFTER ui->setupUi(this) is called. The program will segfault otherwise*/
/*General connect syntax:
connect(object that will emit signal, SIGNAL(signal emitted), object that will receive the signal, SLOT(slot function));
/*the pushButton is owned by the ui object*/
connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(addTextToLabel());
}
/*Now define the slot function*/
void MainWindow::addTextToLabel()
{
/*I actually can't tell from the UI whether the text box is a plainTextEdit or textEdit, so substitute the name of the text box (found in the QDesigner window)*/
ui->textEdit->appendText("test");
}
MainWindow::~MainWindow()
{
delete ui;
}
Give that a shot and let me know if anything goes awry or you have any more questions.

Why does this code create two objects while one is needed?

This is a tutorial code for Qt:
Header file:
#include <QMainWindow>
namespace Ui {
class Notepad;
}
class Notepad : public QMainWindow
{
Q_OBJECT
public:
explicit Notepad(QWidget *parent = 0);
~Notepad();
private:
Ui::Notepad *ui;
};
Source file:
#include "notepad.h"
#include "ui_notepad.h"
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
}
Notepad::~Notepad()
{
delete ui;
}
And in main,
#include "notepad.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Notepad w;
w.show();
return a.exec();
}
So when we do Notepad w, an object is already created on the stack, and why does the code still create another object on the heap using new and assign to a member?
The one on the stack is of type Notepad, and it's the application's main window. The dynamic one is of type Ui::Notepad. That's a class automatically generated by Qt's uic tool; it contains the widgets created in UI creator as data members.
In a way, you could say that Notepad is concerned with the logic and uses an instance of Ui::Notepad to provide the GUI for it.

How can I put this qt program into one source code file

I want to have this code in one file, but can't figure out how to. I know it might not be good practice to do so but I am trying to learn qt, and would find it easier to understand the information if it were in one file.
This is the main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.showMaximized();
return app.exec();
}
This is the mainwindow.cpp
#include "mainwindow.h"
#include <QCoreApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// Create the button, make "this" the parent
m_button = new QPushButton("My Button", this);
// set size and location of the button
m_button->setGeometry(QRect(QPoint(100, 100),
QSize(200, 50)));
// Connect button signal to appropriate slot
connect(m_button, SIGNAL(released()), this, SLOT(handleButton()));
}
void MainWindow::handleButton()
{
// change the text
m_button->setText("Example");
// resize button
m_button->resize(100,100);
}
this is the mainwindow.h
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private slots:
void handleButton();
private:
QPushButton *m_button;
};
By just copying everything in one file.
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private slots:
void handleButton();
private:
QPushButton *m_button;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// Create the button, make "this" the parent
m_button = new QPushButton("My Button", this);
// set size and location of the button
m_button->setGeometry(QRect(QPoint(100, 100),
QSize(200, 50)));
// Connect button signal to appropriate slot
connect(m_button, SIGNAL(released()), this, SLOT(handleButton()));
}
void MainWindow::handleButton()
{
// change the text
m_button->setText("Example");
// resize button
m_button->resize(100,100);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.showMaximized();
return app.exec();
}
It is usually not a good idea to define new classes in same file as your main. Generally you want new classes each in their own file or you would want to put several related classes together in a seperate file. There are a tonne of resources you can google related to best practices for this. I'd suggest you spend some time reading.
But since you asked... below is how you would do it for your example. If you do not define your class above the main, the compiler will complain because it won't know what a "MainWindow" is.
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private slots:
void handleButton();
private:
QPushButton *m_button;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.showMaximized();
return app.exec();
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// Create the button, make "this" the parent
m_button = new QPushButton("My Button", this);
// set size and location of the button
m_button->setGeometry(QRect(QPoint(100, 100),
QSize(200, 50)));
// Connect button signal to appropriate slot
connect(m_button, SIGNAL(released()), this, SLOT(handleButton()));
}
void MainWindow::handleButton()
{
// change the text
m_button->setText("Example");
// resize button
m_button->resize(100,100);
}
#include essentially takes the contents of whatever file you choose and copy/pastes it at that location. The compiler then starts at the top of the file and works its way down to the bottom.
Knowing that, you should be able to just copy-paste the contents of the files in the order they are included.
mainwindow.h
mainwindow.cpp
main.cpp
The short answer is don't do this, you should define a class in its own header file and #include it to the main when you want to run it in the main. This allows you to reuse the class as you see fit throughout the program, its one of the tenets of Object Oriented programming, reusable code. For example
class A
{
public:
A();
~A();
void somePublicMethod();
private:
void somePrivateMethod();
};
If you include that class in your main when you compile that class to object code(assuming you know about implementing that class in a .cpp file) then when all the object files are linked to create the program the linker basically makes one big file with all the object code included in file to be fully compiled. I suggest you read up more on compiling and linking, essentially it boils down to three phases, preprocessing, compiling and linking. Learn more about Object Oriented programming and read up why it's a bad idea to just shove them all into one file. Every class should be in its own self contained .h file(unless its a tightly coupled class) so you can include them as you see fit. Hope this helps, have fun with Qt :)