QDialog exec() can not exit process - qt

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog dlg;
dlg.exec();
return a.exec();
}
That's all my code, but when I close the window, The process isn't exit, it seems that drop in the loop a.exec().

Generally speaking, calling any exec is a bad idea, other than QCoreApplication::exec() or QDrag::exec(). The presence of exec() and waitForXxx() methods is an enticing trap for the unwary. Those methods are "easy" to use, but that ease comes at a price of hard to track bugs. Don't use them.
You should simply show the dialog:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMessageBox msg;
msg.setText("Hello");
msg.addButton(QMessageBox::Close);
msg.show();
return a.exec();
}
If you wish to wait for the dialog to be accepted or rejected, you should use the dialog's clickedButton slot. QMessageBox has a long-standing bug that makes the accepted and rejected signals useless :(
// https://github.com/KubaO/stackoverflown/tree/master/questions/messagebox-show-25545652
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
#include <functional>
[...]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
auto onClick = [&msg]() {
auto role = msg.buttonRole(msg.clickedButton());
if (role == QMessageBox::NoRole)
QApplication::quit();
if (role == QMessageBox::YesRole) {
auto label = new QLabel("I'm running");
label->setAttribute(Qt::WA_DeleteOnClose);
label->show();
}
};
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QObject::connect(&msg, &QMessageBox::buttonClicked, onClick);
#else
QObject::connect(&msg, SIGNAL(buttonClicked(QAbstractButton*)),
new FunctorSlot{onClick, &msg}, SLOT(call()));
#endif
msg.show();
return app.exec();
}
#include "main.moc"
For Qt 4, you need the following helper:
// Qt 4 only
struct FunctorSlot : public QObject {
Q_OBJECT
public:
std::function<void()> callable;
template <typename Fun>
FunctorSlot(Fun && fun, QObject * parent = {}) :
QObject{parent}, callable{std::forward<Fun>(fun)} {}
Q_SLOT void call() {
callable();
}
};

Possible solution:
QApplication a(argc, argv);
QDialog dlg;
QTimer::singleShot( &dlg, 0, SLOT(exec()) );
return a.exec();
It will work well. First - application event loop will be started. Then dialog event loop will be executed. After closing of dialog, both dialog and application loop will be finished. Application loop will be terminated automatically (by default), when last window is closed.
But, as noted by #thuga - there are no reason to call exec(). It is enough to call show() method.

Related

How to check if the application has been minimized

Whenever the application window is minimized or maximized i want to link that signal with a function.
This is the code.
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Renderer w(model ); // This is QWidget
w.show();
QObject::connect(&w, &QWindow::windowStateChanged, [&](Qt::WindowState state) {
});
// how will i define the QObject::connect
return application.exec();
}
What would be the parameters for the QObject::connect function ?
You cannot use the connect function to connect to different slots based on the given value. You can however simply call the functions based on the value by checking the value in your lambda.
At least, you could if you had the signal. However, your connect suggests that w is - or inherits - a QWindow. You can obviously only connect to signals your class provides. As your Renderer is a QWidget, you have to check that class.
The documentation of QWidget tells us, that there is no windowStateChanged signal, but it states:
When the window state changes, the widget receives a changeEvent() of type QEvent::WindowStateChange.
So therefor we can create our own signal and connect to that. This can look similar to the following working example:
#ifndef RENDERER_H
#define RENDERER_H
#include <QWidget>
#include <QEvent>
class Renderer : public QWidget {
Q_OBJECT
signals:
void stateChanged(bool isMaximized);
protected:
void changeEvent(QEvent *e)
{
if(e->type() == QEvent::WindowStateChange) {
emit stateChanged(windowState() & ~Qt::WindowMaximized);
}
QWidget::changeEvent(e);
}
};
#endif // RENDERER_H
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Renderer w; // This is QWidget
w.show();
QObject::connect(&w, &Renderer::stateChanged, [&](bool maximized) {
qDebug() << "Maximized?" << maximized;
});
return application.exec();
}
I was able to solve by using QApplication::focusWindow()
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Renderer w; // This is QWidget
w.show();
QObject::connect(QApplication::focusWindow(), &Renderer::stateChanged, [&](bool maximized) {
qDebug() << "Maximized?" << maximized;
});
return application.exec();
}

How to use QMenu signals?

It is very straightforward to connect to QMenu::triggered or QMenu::hovered signals by calling QObject::connect and pass the appropriate QAction.
However, I do not know how to use QMenu::aboutToHide signal, as there is no action passed to that signal.
How to use QMenu::aboutToHide and QMenu::aboutToShow signals or those are just virtual functions that can be overridden?
The signals in the world of Qt are not functions, never invoke them. The signals notify that something has happened with the QObject and send information if necessary.
In the case of triggered and hovered it is necessary to send the QAction because several QActions in a QMenu, then the developer thought that it is necessary to know with which QAction was interacting. On the other hand with aboutToShow and aboutToHide the signal does not send anything because it wants to notify is that if the QMenu was shown or hidden, respectively. Is there any need to know that QMenu was shown or hidden if he did it ? no, because the sender did it, I do not use other properties that we do not have at hand.
Example of use:
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QMenu *foo_menu = w.menuBar()->addMenu("Foo Menu");
for(const QString & name: {"action1", "action2", "action3"}){
foo_menu->addAction(name);
}
QObject::connect(foo_menu, &QMenu::aboutToShow, [](){
qDebug()<<"aboutToShow";
});
QObject::connect(foo_menu, &QMenu::aboutToHide, [](){
qDebug()<<"aboutToHide";
});
QObject::connect(foo_menu, &QMenu::triggered, [](QAction *action){
qDebug()<< "triggered: " <<action->text();
});
QObject::connect(foo_menu, &QMenu::hovered, [](QAction *action){
qDebug()<< "hovered: " <<action->text();
});
w.show();
return a.exec();
}
And what happens if you have several QMenu that connect to the same slot? How do I know QMenu was shown or hidden?
The solution is to use sender() which is a method that belongs to the QObject class that returns the object that emitted the signal, in this case the QMenu.
Example:
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QDebug>
class MainWindow: public QMainWindow{
public:
MainWindow(QWidget *parent=nullptr):
QMainWindow(parent)
{
for(const QString & name_of_menubar: {"bar1", "bar2", "bar3"}){
QMenu *menu = menuBar()->addMenu(name_of_menubar);
connect(menu, &QMenu::aboutToShow, this, &MainWindow::on_aboutToShow);
connect(menu, &QMenu::aboutToHide, this, &MainWindow::on_aboutToHide);
for(const QString & name: {"action1", "action2", "action3"}){
menu->addAction(name);
}
}
}
private slots:
void on_aboutToShow(){
if(QMenu *menu = qobject_cast<QMenu *>(sender()))
qDebug()<<"aboutToShow" << menu->title();
}
void on_aboutToHide(){
if(QMenu *menu = qobject_cast<QMenu *>(sender()))
qDebug()<<"aboutToHide" << menu->title();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

SIGABRT in simple message box Qt program

Got an error running the following problem:
#include <QMessageBox>
#include <QApplication>
int main() {
QApplication app();
QMessageBox msgBox(QMessageBox::Critical,
QObject::tr("text1"),
QObject::tr("text2"),
QMessageBox::Ok);
msgBox.exec();
return 0;
}
The error is:
The program breaks at QMessageBox msgBox(...);
The call stack is:
EDIT: Even after i have added QApplication instance in XTerm window named qtcreator_process_stub i see the following:
QWidget: Must construct QApplication before a QWidget
The line
QApplication app();
doesn't create a QApplication object - it actually declares a function taking no arguments and returning a QApplication! This is sometimes known as the "most vexing parse".
To actually construct the application object, you need to provide the program's arguments:
QApplication app(argc, argv);
The full program is then
#include <QMessageBox>
#include <QApplication>
int main(int argc, char **argv) {
QApplication app(argc, argv);
QMessageBox msgBox(QMessageBox::Critical,
QObject::tr("text1"),
QObject::tr("text2"),
QMessageBox::Ok);
msgBox.exec();
return 0;
}

Qt connect - object emits signal before connect is issued

I have following main.cpp:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "database/uepeoplemodel.h"
#include "core/uestatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now, inside main.cpp I create two objects from classes:
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
and I connect signal from UePeopleModel to slot in ueApplicationStatus:
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
The problem is when uePeopleModel is created, the signal is emmited inside constructor:
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent),
QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
} // if
this->ueDatabase().setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
this->ueDatabase().setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
this->ueDatabase().setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
this->ueDatabase().setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
/*
if(this->lastError().isValid())
qDebug() << this->lastError();
*/
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
// qDebug() << this->ueDatabase().lastError();
}
// qDebug() << this->ueDatabase().connectionNames();
} // default constructor
before connect is issued and therfore ueApplicationStatus object does not catch is with slot. Does anyone has idea how to get rid of this situation?
You shouldn't use the constructor to open the connection with the database.
Use the constructor only to instantiate other classes, initialize variables, allocate memory and so on.
In your case, your constructor should be used to initialize the database, but you could create another method with:
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
}
This method would be called after the connect you have in your main.cpp.
I've solved the problem by adding method void ueConnectToDatabase() and moved the content of constructor into it and redefined main.cpp as:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
uePeopleModel->ueConnectToDatabase();
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now the object is created, signal and slot connected and AFTER this the connection to database occurs.

Qt Login Dialog Box before Main Window

How do I have the user first login before getting to the main window in my QT app? I'm new to QT and have looked through the documentation and have not found anything very helpful. Thank you.
I would make this in the following way. Let's assume, that my login dialog is a QDialog:
class Login : public QDialog
{
[..]
};
In my application, I create an instance of my Login dialog and if it is accepted, i.e. closed with OK button, I open my main window:
int main(int argc, char *argv[])
{
[..]
QMainWindow mw;
Login login;
if (login.exec() == QDialog::Accepted) {
mw.show();
}
[..]
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
LoginWindow l; // create login-widget
connect(&l, SIGNAL(loggedIn), &w, SLOT(show()); // connect to mainwindow show()
l.show(); // show login-window instead of
// mainwindow at start
return a.exec();
}
You might want to :
1 - exec the loop only if the dialog is accepted, otherwise you application continues to run
2 - create the mainwindow only if accepted, cause it might be a heavy interface, which takes time to initialize
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog_Login dialog;
if(dialog.exec() == QDialog::Accepted){
MainWindow w;
w.setUser(dialog.GetUser());
w.show();
return a.exec();
}
else return 0;
}
You need to create the QApplication instance in parrallel with the login dialog.

Resources