I have a simple gtkmm program like that:
File main.cpp:
#include "mainwindow.h"
#include <gtkmm/application.h>
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
MainWindow window;
//Shows the window and returns when it is closed.
return app->run(window);
}
File mainwindow.h:
#include <gtkmm/window.h>
#include <gtkmm.h>
class MainWindow : public Gtk::Window {
public:
MainWindow();
virtual ~MainWindow();
protected:
Gtk::Label myLabel;
};
and file mainwindow.cpp:
#include "mainwindow.h"
#include <iostream>
//using namespace gtk;
MainWindow ::MainWindow():myLabel("this is Label")
{
add(myLabel);
show_all_children();
}
MainWindow::~MainWindow() {}
This code run ok. But now I want to declared a Label in file mainwindow.cpp like that:
#include "mainwindow.h"
#include <iostream>
MainWindow ::MainWindow():myLabel("this is Label")
{
Gtk::Label myLabel2("this is label 2");
add(myLabel2);
show_all_children();
}
MainWindow::~MainWindow() {}
The Label don't show when I run this code, can someone tell me what wrong? Thank for your help!
The label doesn't show up, because it's destroyed at the end of the scope (i.e. at the end of the constructor).
To avoid this, you need to allocate Label on the heap. However, to avoid memory leak, you should use Gtk::manage function, so the memory of the label will be managed by the container [1].
Gtk::Label* myLabel2 = Gtk::manage(new Gtk::Label("this is label 2"));
add(myLabel2);
show_all_children();
[1] https://developer.gnome.org/gtkmm-tutorial/stable/sec-memory-widgets.html.en#memory-managed-dynamic
You have two problems here. First myLabel2 goes out of scope have the end of your constructor and is destroyed. The second is Gtk::Window as a single item container and can only hold one widget.
The solution for myLabel2 going out of scope is to allocate it on the heap see #Marcin Kolny answer. Or construct it similar to how you have done with myLabel.
For the second issue a multi-item container needs to be added to your Gtk::Window, then you can add your other widgets to that. This container can be a Gtk::Box, Gtk::Grid, etc... It depends on your needs.
One of many possible solutions is:
mainwindow.h
#include <gtkmm.h>
class MainWindow : public Gtk::Window {
public:
MainWindow();
virtual ~MainWindow();
protected:
Gtk::Box myBox;
Gtk::Label myLabel;
Gtk::Label myLabel2;
};
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow():
myLabel("this is Label"), myLabel2("this is label 2");
{
add myBox;
myBox.pack_start(myLabel);
myBox.pack_start(myLabel2);
show_all_children();
}
MainWindow::~MainWindow() {}
Related
I have a problem that, after closing a QDialog with web content, the QWebEngineProcess.exe process is not closing.
Here is a minimal example:
#include <QApplication>
#include <QWebEngineView>
#include <QWebEngineSettings>
#include <QDialog>
#include <QMainWindow>
#include <QLayout>
#include <QtGui>
#include <QPushButton>
class Dialog : public QDialog
{
public:
Dialog() : QDialog(nullptr)
{
resize(512, 512);
setAttribute(Qt::WA_DeleteOnClose);
auto verticalLayout = new QVBoxLayout(this);
verticalLayout->setSpacing(0);
verticalLayout->setContentsMargins(0, 0, 0, 0);
m_webView = new QWebEngineView(this);
verticalLayout->addWidget(m_webView);
}
void openPage(const QUrl& url)
{
m_webView->setUrl(url);
}
private:
QWebEngineView* m_webView;
};
class MainWindow : public QMainWindow
{
public:
MainWindow() : QMainWindow(nullptr)
{
resize(512, 512);
QPushButton* btn = new QPushButton("open web dialog", this);
connect(btn, &QPushButton::clicked, [this] ()
{
if (m_dialog == nullptr)
{
m_dialog = new Dialog();
m_dialog->openPage(QUrl("https://www.qt.io"));
m_dialog->show();
}
});
}
private:
QPointer<Dialog> m_dialog;
};
int main(int argc, char *argv[])
{
QCoreApplication::setOrganizationName("QtExamples");
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
I'm expecting that, after the dialog is closed, QWebEngineProcess.exe will be closed too, because I'm not using webengine anymore.
P.S. During opening WebPage, I have 2 QWebEngineProcess.exe. One is disappearing, but the second one left.
For any QObject instances (such as QDialog and QWebEngineView), the destructor of a parent object destroys all child objects. This means, for every object you new, it must either have a parent, or you must delete it manually, otherwise you are creating a leak and objects will remain open (not deleted).
You are creating a QWebEngineView object with the correct parent, but the parent (the Dialog) doesn't have a parent (you initialize the parent to nullptr). This means the Dialog would delete the QWebEngineView, except it never is deleted itself.
To fix it, either delete the Dialog (stored in m_dialog) manually in the MainWindow destructor (not recommended), or initialize it correctly with the MainWindow as its parent.
This may also be related to a bug in Qt 5.11 and 5.12. If this is the problem, the recommended solution is to add QCoreApplication::setAttribute(Qt::AA_UseOpenGLES); at the top of your main() function (before declaring the QApplication).
I would like to make some modifications of the main window from another file.
I created another ui file Form1Window (which open when a button is cliked in the MainWindow).
I want to call from the class Form1Window a function named test() of the MainWindow class
I succeed in calling function test() but I can't execute the whole content of the function (I can display a message but can't execute the part where I want to clear an edittext)
MainWindow.h
#include "form1window.h"
public slots:
void nettoyer();
private slots:
void openFrom1();
private:
Ui::MainWindow *ui;
From1Window *uiFrom1;
};
MainWindow.cpp
void MainWindow::openFrom1()
{
uiFrom1 = new From1Window(this);
uiFrom1->show();
}
void MainWindow::nettoyer(){
QMessageBox msgBox;
msgBox.setText("test");
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
ui->auteur->clear();
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
}
form1window.cpp
#include "mainwindow.h"
#include "ui_form1window.h"
void From1Window::on_supprimer_clicked()
{
MainWindow *a=new MainWindow ();
a->test();
close();
}
I've read about the role of the pointer of MainWindow class (C++ /Qt Proper way to access ui from another class in qt //Edited) and I've also tried connect()
Thank for your help
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
this->ui->auteur->clear();
The line will never executed unless you dismiss QMessageBox. This is because you triggered QMessageBox with exec() function. This function has its own event queue and does not return until finishes. You may set QMessageBox as modal and display it with show() method. In that case QMessageBox will not block execution of the the flow.
This problem can also happen with QDialog(s) if you display them with exec().
I provide you a simple two window signal/slot example:
main.cpp
#include "mainwindow.h"
#include "form.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Form f;
f.show();
return a.exec();
}
form.h
#ifndef FORM_H
#define FORM_H
#include <QWidget>
#include <QPushButton>
class Form : public QWidget
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
~Form();
private:
QPushButton *pb;
};
#endif // FORM_H
form.cpp
#include "form.h"
#include "mainwindow.h"
#include <QDebug>
Form::Form(QWidget *parent) : QWidget(parent)
{
MainWindow *mw = new MainWindow();
pb = new QPushButton("clickME", this);
QObject::connect(pb, SIGNAL(clicked()), mw, SLOT(test()));
mw->show();
}
Form::~Form()
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
QLabel *l;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
l = new QLabel("test", this);
}
MainWindow::~MainWindow()
{
}
void MainWindow::test() {
qDebug() << "test called!" << endl;
l->setText("text changed");
}
This works for me.
output
Before taking up the main subject, please mind that i`m a beginner of Qt.
I made a AddIm.cpp, and I want to set an image on QLabel in MainWindow.
here is my source in AddIm.cpp
void AddIm::on_pushButton_clicked()
{
MainWindow mainwindow;
mainwindow.setImage();
}
and here is MainWindow.cpp
void MainWindow::setImage()
{
QPixmap pix("./test.jpg");
ui->label->setPixmap(pix);
}
and MainWindow.h
class MainWindow : public QMainWindow
{
public:
void setImage();
~ some source ~
private:
Ui::MainWindow *ui;
};
it doesn't work at all. so I added a button in MainWindow for testing.
and when it clicked, setImage works. but when I execute setImage in AddIm.
it doesn't work. please let me know why
Your problem has nothing to do with your knowledge with Qt but rather your knowledge of c++.
In AddIm::on_pushButton_clicked(), you create a new MainWindow object on the stack, create the image, and then exit the function.
When a function exits, all local stack objects are destroyed. This means that your image is indeed being loaded but the window is being destroyed before you get a chance to see it. Even if it survived to live longer than the function allowed, you never show the window so it remains hidden.
UPDATE:
Change AddIm.cpp to be the following:
void AddIm::on_pushButton_clicked()
{
MainWindow *mainwindow = new MainWindow;
mainwindow->setAttribute(Qt::WA_DeleteOnClose, true);
mainwindow->setImage();
mainwindow->show();
}
Compare this with with your code to see where you might have gone wrong. I tried as much as possible to code it just like you did. I hardly use the designer, i like to code everything. It works as expected.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QLabel>
#include <QPixmap>
class MainWindow : public QWidget {
Q_OBJECT
public:
void setImage();
private:
QLabel *label;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
void MainWindow::setImage() {
QPixmap pix(":/test.jpg");
label = new QLabel;
label->setPixmap(pix);
label->show();
}
addim.h
#ifndef ADDIM_H
#define ADDIM_H
#include <QMainWindow>
#include <QPushButton>
#include <QHBoxLayout>
#include "mainwindow.h"
class AddIm : public QMainWindow {
Q_OBJECT
public:
AddIm(QWidget *parent = 0);
~AddIm();
private slots:
void on_pushButton_clicked();
private:
QPushButton *button;
};
#endif // ADDIM_H
addim.cpp
#include "addim.h"
AddIm::AddIm(QWidget *parent) : QMainWindow(parent) {
button = new QPushButton("Show Image");
setCentralWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
}
void AddIm::on_pushButton_clicked() {
MainWindow mainwindow;
mainwindow.setImage();
}
AddIm::~AddIm() {
}
main.cpp
#include "addim.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
AddIm window;
window.show();
return a.exec();
}
You did not shown the window.
First, you have to create a C++ Class not a single .cpp file. Then add a pointer to the window in your AddIm.h file:
private:
MainWindow* mainwindow;
Then in your AddIm.cpp file:
mainwindow = new MainWindow(this);
mainwindow->setAttribute(Qt::WA_DeleteOnClose, true); // prevent memory leak when closing window
mainwindow->setImage();
mainwindow->show();
And remember to include MainWIndow in AddIm.h
#include "mainwindow.h"
i just started learning Qt few days ago, and i have a problem that i can't solve.
First there is the files :
main.cpp
#include <QApplication>
#include "test.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
test w;
w.show();
return a.exec();
}
test.h
#ifndef TEST_H
#define TEST_H
#include <QWidget>
#include <QTabWidget>
#include <QTextEdit>
#include <QPushButton>
class test : public QWidget
{
Q_OBJECT
public:
test();
~test();
private slots:
void addT();
private :
QTabWidget *tab;
QPushButton *b,*c;
};
#endif // TEST_H
and test.cpp
#include "test.h"
test::test()
{
QTabWidget *tab = new QTabWidget(this);
QPushButton *b = new QPushButton("Add",this);
tab->addTab(b,"test");
QObject::connect(b,SIGNAL(clicked()),this,SLOT(addT()));
}
test::~test()
{
}
void test::addT()
{
QPushButton *c= new QPushButton("Add",this);
tab->addTab(c,"test");
}
the program starts normally but when i push the button to add a new Tab it crashes
Please Help me!
In your constructor you are not assigning to the QTabWidget and QPushButton instanced declared in your header, but are creating two new instances (with the same name) that will be gone at the end of the scope. The tab instance is still a nullptr and when trying to derefence it in addT, your program will crash. You need to assign to the variables declared in test.h like this:
test::test() : tab(new QTabWidget(this), b(new QPushButton("Add", this) {
...
}
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 :)