I just started learning QT and what i wanted to accomplish is to get popup message on buttons click.
Here is how my file looks like:
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QDialog>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow *mainWindow = new MainWindow();
QLabel *text = new QLabel("Some text");
QPushButton *btn = new QPushButton("Click");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(btn);
layout->addWidget(text);
QObject::connect(btn, SIGNAL(clicked()), &app, SLOT(popup()));
mainWindow->setLayout(layout);
mainWindow->show();
return app.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::popUp()
{
QMessageBox::information(this, "New Box", "Message");
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMessageBox>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void popUp();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Can you please explain what i've done wrong or maybe there is something missing in my code.
I recommend that the graphical part implement it inside the class MainWindow since the member ui that is private handles the design.
#include <QMessageBox>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QLabel *text = new QLabel("Some text");
QPushButton *btn = new QPushButton("Click");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(btn);
layout->addWidget(text);
ui->centralWidget->setLayout(layout);
connect(btn, &QPushButton::clicked, this, &MainWindow::popUp);
}
Do not make any changes to main.cpp, the code should look like this:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Wrong connection. You should connect the clicked() signal to the mainWindow's slot popUp(), because it is a member of the MainWindow class. And don't forget about case sensitivity of c++ (popUp, not popup):
QObject::connect(btn, SIGNAL(clicked()), mainWindow, SLOT(popUp()));
You're connecting to a private slot from outside mainwindow.
The application output probably shows you a warning like this:
QObject::connect: No such slot QApplication::popup()
Usually what you'd want to do is put stuff used inside mainwindow, inside mainwindow class.
Eg: Create the layout inside the constructor.
You can use the parent argument when creating the objects to get them destroyed when you're done with mainwindow.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QLabel *text = new QLabel("Some text", this);
QPushButton *btn = new QPushButton("Click", this);
QHBoxLayout *layout = new QHBoxLayout;
QObject::connect(btn, SIGNAL(clicked()), this, SLOT(popUp()));
ui->centralWidget->setLayout(layout);
this->show();
}
You have to use ui->centralWidget, because that's how mainwindow works. The application output should have given you a warning for that as well.
Like this:
QWidget::setLayout: Attempting to set QLayout "" on MainWindow "MainWindow", which already has a layout
Ok, you have to work on the file mainwindow.cpp. You have already create the slot, so connect it adding this code in MainWindow's constructor (if you don't know witch is the mw constructor it is the function where is written ui->setupUi(this);)
connect(ui->btn, SIGNAL(clicked()), SLOT(popUp()));
now in the slot MainWindow::popUp(); put this code:
QMessageBox msgBox;
msgBox.setText("text to write");
msgBox.exec();
remember to include QMessageBox in mainwindow.cpp, you shouldn't write code on main.cpp, it must be this:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Related
Basically, when second window is opened from a push button in the main window, the main window will be closed. When the second window is closed, the main window will reappear.
QWidget *wdg = new QWidget;
wdg->show();
hide();
I put this under the class of mainwindow.cpp
I tried using this..but it doesn't seem to do anything?
this are the code I have so far. Everything is working but I just don't know how to hide the window when the second window is opened and also when the second window is closed the main window will reappear.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
public:
void show();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
secwindow.h
#ifndef SECWINDOW_H
#define SECWINDOW_H
#include <QDialog>
namespace Ui {
class SecWindow;
}
class SecWindow : public QDialog
{
Q_OBJECT
public:
explicit SecWindow(QWidget *parent = nullptr);
~SecWindow();
private:
Ui::SecWindow *ui;
};
#endif // SECWINDOW_H
source 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.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QPixmap>
#include "secwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPixmap pix("C:/Users/Charlene/Downloads/Charlene Back-up/MAPUA/2nd Term/Object Oriented Programming/GOW-Gui/GOW-GUI/intro pic/intro.png");
ui->label->setPixmap(pix.scaled(230,250,Qt::KeepAspectRatio));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked() // Modal approach..mainwindow cannot be moved when secwindow is displayed.
{
SecWindow secwindow;
secwindow.setModal(true); //it'll set the secwindow
secwindow.exec(); //shows secwindow when button is pressed
}
secwindow.cpp
#include "secwindow.h"
#include "ui_secwindow.h"
SecWindow::SecWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::SecWindow)
{
ui->setupUi(this);
}
SecWindow::~SecWindow()
{
delete ui;
}
EDIT:
#Serhiy Kulish
What I added so far:
secWindow.h
class Dialog : public QDialog
{
Dialog();
};
mainwindow.cpp
#include <QDialog>
void MainWindow::show()
{
Dialog *dialog = new Dialog(this); //Error:no matching constructor for initialization of 'Diaolog'
connect(dialog, SIGNAL(accepted()), this, SLOT(show()));
connect(dialog, SIGNAL(rejected()), this, SLOT(show()));
dialog->show();
hide();
}
These are the errors I'm having so far.
Add your own class derived from QDialog. Then connect signals accepted and rejected with MainWindow::show().
Dialog *dialog = new Dialog(this);
connect(dialog, SIGNAL(accepted()), this, SLOT(show()));
connect(dialog, SIGNAL(rejected()), this, SLOT(show()));
dialog->show();
hide();
It works fine on Windows 10.
Also, depends your OS you maybe need
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
in main.cpp to prevent app closing. But in this case you have to quit from your app manually
I have issue with SIGNAL not being emitted. Here is minimal example of this issue:
main.cpp - standard main
#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 <QVBoxLayout>
#include "combobox.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QWidget *mainWidget = new QWidget;
setCentralWidget(mainWidget);
QVBoxLayout *mainLayout = new QVBoxLayout;
combobox combo_box;
mainLayout->addWidget(combo_box.box);
mainWidget->setLayout(mainLayout);
}
MainWindow::~MainWindow()
{
}
combobox.h
#ifndef COMBOBOX_H
#define COMBOBOX_H
#include <QComboBox>
#include <QDebug>
class combobox : public QWidget
{
Q_OBJECT
public:
combobox();
~combobox();
QComboBox *box = new QComboBox;
public slots:
void selection_changed();
};
#endif // COMBOBOX_H
combobox.cpp
#include "combobox.h"
combobox::combobox()
{
QString string = "test 1";
box->addItem(string);
string = "test 2";
box->addItem(string);
box->setCurrentIndex(0);
connect(box, SIGNAL(currentIndexChanged(int)), this, SLOT(selection_changed()));
}
combobox::~combobox()
{
}
void combobox::selection_changed()
{
qDebug() << "Selection changed";
box->setCurrentIndex(-1);
}
You need to run qmake before compiling.
When I run this program and change combobox index selection_changed is not executed. Why?
SIGNAL and SLOT connection definitely works, because if I add box->setCurrentIndex(1); at the end of combobox constructor, selection_changed will be executed once.
I am using QT 5.4 with QT Creator
Thanks in advance!
This problem because of you create your ComboBox class object at stack. So if you write some debug information at destructor of this class you can see object destroyed immediately after MainWindow constructor out of scope:
ComboBox::~ComboBox()
{
qDebug() << Q_FUNC_INFO;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
QWidget *mainWidget = new QWidget;
setCentralWidget(mainWidget);
QVBoxLayout *mainLayout = new QVBoxLayout;
ComboBox combo_box;
mainLayout->addWidget(combo_box.box);
mainWidget->setLayout(mainLayout);
qDebug() << Q_FUNC_INFO;
}
And qDebug() got the following result:
MainWindow::MainWindow(QWidget*)
virtual ComboBox::~ComboBox()
Thats why signal don't emitted. So you need create object on the heap or make something tricks.
Also, you have dynamically allocated object *box at your ComboBox class and don't specify parent of this object, so it seems memory leak is possible. Specify parent or delete object at destructor of ComboBox class.
I'm trying to write a simple app with singleton design in Qt. Below is the header file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
static MainWindow *getInstance();
~MainWindow();
private:
explicit MainWindow(QWidget *parent = 0);
static MainWindow *uniqueInstance;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
And here is implementation file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow* MainWindow::uniqueInstance = new MainWindow();
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow* MainWindow::getInstance()
{
return uniqueInstance;
}
Finally here is the main function:
#include <QApplication>
#include "mainwindow.h"
#include "QThread"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w = MainWindow::getInstance();
w->show();
return a.exec();
}
Building of my program is OK. But I receive a run-time error "QWidget: Must construct a QApplication before a QWidget". What should I do for solving this problem? I want to use this form of singleton to have a thread-safe program.
Thanks in advance for your helps.
Reza
The Qt-idiomatic way of holding a global object instance thread-safely is through Q_GLOBAL_STATIC. The instance is created on the first use. This way, your singleton instance will be created when needed, after QApplication instance exists.
Instead of MainWindow* MainWindow::uniqueInstance = new MainWindow(), you'd write:
Q_GLOBAL_STATIC(MainWindow, uniqueInstance);
Based on previous answers and also http://doc.qt.io/qt-5/qglobalstatic.html#Q_GLOBAL_STATIC, the answer is like below:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
friend class myClass;
public:
static MainWindow *getInstance();
~MainWindow();
private:
explicit MainWindow(QWidget *parent = 0);
Ui::MainWindow *ui;
};
class myClass : public MainWindow
{
};
#endif // MAINWINDOW_H
.cpp file is like below:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGlobalStatic>
Q_GLOBAL_STATIC(myClass,uniqueInstance)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow* MainWindow::getInstance()
{
return uniqueInstance;
}
finally main file is like below:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w = MainWindow::getInstance();
w->show();
return a.exec();
}
And that works and is thread-safe.
MainWindow* MainWindow::uniqueInstance = new MainWindow();
this is global instance, it happens before the main function, so this constructor is earlier than the main function, which is not allowed. Qt needs to construct QApplication first, then the widget. so you need to move this after constructor the QApplication in main, or just remove it.
MainWindow* MainWindow::uniqueInstance = 0;
then constructor the object after QApplication.
As I said, you should NOT constructor the uniqueInstance before main, modified some code basing on your POST, it should work.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow* MainWindow::uniqueInstance = 0;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow* MainWindow::getInstance()
{
if (0 == MainWindow::uniqueInstance){
MainWindow::uniqueInstance = new MainWindow();
}
return MainWindow::uniqueInstance;
}
Basing on Kuba's POST, there is introduced a new global MACRO for creating this kind of SINGLETON (Q_GLOBAL_STATIC http://qt-project.org/forums/viewthread/13977), it is more elegant, however, this macro only exists in Qt5, not Qt4, and also has some usage limit you should notice. Basically it is also a macro for wrapping code to create singleton at runtime.
So this is the code of the main.cpp:
#include <QApplication>
#include <QtGui>
#include <mainwidget.h>
int main(int argc, char **argv)
{
QPushButton button ("Hello world!");
button.show();
mainWidget widget;
widget.show();
return app.exec();
}
I want a button from the "widget" to close the "Hello world!" window. I have already added that button in "widget" and made a function for it in mainwidget.h (which also shows a message box) and connected them. I just want to know how can that same button close the Hello World window. I guess I have to add something to the function in mainwidget.h but I don't know what it is. The instructor says we should use the QWidget close() function.
I will answer to your question but before I'll explain you how a basic Qt application looks like.
In Qt, a basic main is like :
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Here as you can see a QApplication is created then a MainWindow.
So What's the MainWindow class ?
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
};
#endif // MAINWINDOW_H
It's the MainWindow.h. As you can see MainWindow inherit to the QMainWindow class. It's the main window class to create a graphic user interface.
the Q_OBJECT define is for qmake. Indeed qmake I'll create a moc_mainwindow.cpp for this class to manage the Qt signals.
Now you get an empty window if you create an Empty constructor and destructor like:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
}
MainWindow::~MainWindow()
{
}
then after you wish to write "Hello world !" in the window so in Qt to write a text you can use a QLabel. So to write "Hello World !" you get:
#include "mainwindow.h"
#include <QLabel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget *widget = new QLabel("Hello world !", this);
}
MainWindow::~MainWindow()
{
}
then after to create a button as you made you ll use the QPushButton class.
so you get:
#include "mainwindow.h"
#include <QLabel>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget *widget = new QLabel("Hello world !", this);
setCentralWidget(widget);
QPushButton *button = new QPushButton("close", this);
}
MainWindow::~MainWindow()
{
}
(I Choose to set the QLabel to the central Widget to don't get the label behind the button but after and in real Qt application a QMainWindow's central widget is mostly usualy a QWidget I'll explain you why after)
now you have a button. But when you click on it nothing append.
Why ? Because nothing link the Button and the Window. to link it in Qt we use the connect function. [http://qt-project.org/doc/qt-4.8/qobject.html][1]
so with connect to close the window when you click on the button you get:
#include "mainwindow.h"
#include <QLabel>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget *widget = new QLabel("Hello world !", this);
setCentralWidget(widget);
QPushButton *button = new QPushButton("close", this);
connect(button, SIGNAL(clicked()), this, SLOT(close()));
}
MainWindow::~MainWindow()
{
}
As you can see with connect. In first parameter, we put the object which ll send the signal here the button. in second parameter, we put the signal to link here it's clicked() to do this we write SIGNAL(clicked()). In third, the object which will receive the signal, here the window to close. In fourth parameter the function to launch when the signal is received. We write this SLOT(close()).
Why SIGNAL and SLOT ? because in Qt to create a signal we use signal: in the .hh and to create a slot et use (public or protected or private) slots:
example:
Class Object
{
Q_OBJECT
...
signals:
void aSignal();
public slots:
void aSlot();
...
};
NOTE: the signal and the slot must have same return and parameters.
after to organize your objects you ll use the labels in the QWidget in the centralWidget so you have:
#include "mainwindow.h"
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget* centralWid = new QWidget(this);
setCentralWidget(centralWid);
QVBoxLayout *layout = new QVBoxLayout(centralWid);
QWidget *widget = new QLabel("Hello world !", this);
QPushButton *button = new QPushButton("close", this);
layout->addWidget(widget);
layout->addWidget(button);
centralWid->setLayout(layout);
connect(button, SIGNAL(clicked()), this, SLOT(close()));
}
MainWindow::~MainWindow()
{
}
I am writing a simple editor i Qt and C++. I want to have tabs, so after creating a new document, I want to open this in a new tab. My code:
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("emacs");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionExit_triggered()
{
qApp->exit(0);
}
void MainWindow::on_actionNew_triggered()
{
// what to write here?
}
// main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
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>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_actionExit_triggered();
void on_actionNew_triggered();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
I have successfully managed to create an action to exit the program. But when I try something like this: tabWidget->addTab(new QWidget(),"new tab"); is complaints that tabWidget was not declared in the scope. Anybody? Thanks!
tabWidget is not a member of your MainWindow class, I'm guessing its an object you defined in your ui file, so try:
ui->tabWidget->addTab(...);