can't close app from dialog box (Qt app) - c++

Getting right to it I have a MainWindow and a dialog window which is executed if a condition is met but the problem is I can't get the app to quit if the cancel button from the dialog window is clicked. I've tried putting qApp->quit() in the slot function for the cancel button. I've tried connecting the cancel button slot to the predefined close slot for the MainWindow object via a clickme() signal from the dialog class. (as shown below)
qt application does not quit I read the answer to this question which I think got me close because it made me realize that I can't quit the app before showing the MainWindow but making that change didn't solve the problem. I even tried to explicitly emit the clickme() signal from cancel button slot but that actually caused the OS to throw a signal which threw an error at me saying "the inferior stopped because it received a signal from the operating system signal name: SIGSEGV
signal meaning: segmentation fault"
Here's my code:
Notice warning; // this is the object for the dialog window also all of this code is in main.cpp
warning.setModal(true);
QObject::connect(&warning, SIGNAL(clickme()), &warning, SLOT(on_Cancel_button_clicked()));
QObject::connect(&warning, SIGNAL(clickme()), &w, SLOT(close()));
warning.exec();
Also before that code is
MainWindow w;
w.show();
Also while writing this question I tried this
QObject::connect(&warning, SIGNAL(clickme()), qApp, SLOT(quit()));
But that still didn't work. If you need more info just let me know.
Update: I'm starting to think that the reason I'm having so much trouble with this connect signal/slot function is because it's not designed to connect two windows of two different classes and I should rework my app to do everything from the MainWindow class which is a shame because when I picture a GUI program I picture multiple windows connected to each other regardless of whether or not the object representing each window is from the same class as the others yet I have such a hard time trying do that with the QT framework when it comes to trying to connect objects of different classes.
Update: please forgive me. I assume that the code that I originally thought was the answer would work and took a break from working on the program before actually testing out that code. Going back to it now I discovered that it doesn't work. The code I'm referring to is the following
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
QObject::connect(&msg, &QMessageBox::rejected,
&app, &QApplication::quit); // this line doesn't work for me and I don't know why
QObject::connect(&msg, &QMessageBox::accepted, [&dlg]{
(new QLabel("I'm running")).show();
});

QApp->quit(); should work. Remove warning.setModal(true); The dialog becomes modal when you call exec(). SetModal(true) should be used with show() according to Qt docs. So this may be causing your problem.

I think I've found the problem.
Probably, you're calling exec() twice:
To enter the QApplicationevent loop
To execute the dialog.
Use show() instead of exec() for the dialog. You have an example below where you can check the signal/slot works well. In your application, you need the slot to close the window, but:
With the line of code dialog.exec();, the app keeps running. This is your issue.
With the line of code dialog.show();, the app stops.
By the way, I saw your last question update, but it is not correct. In fact, of course you can connect two different classes.
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QApplication>
#include <QMainWindow>
#include <QAbstractButton>
#include <QDebug>
#include "dialog.h"
class Window : public QMainWindow
{
Q_OBJECT
public:
Window()
{
dialog = new Dialog();
dialog->setText("Continue?");
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
auto onClick = [this]() {
auto role = dialog->buttonRole(dialog->clickedButton());
if (role == QMessageBox::NoRole) {
qDebug() << "QMessageBox::NoRole";
QApplication::quit();
}
if (role == QMessageBox::YesRole) {
qDebug() << "QMessageBox::YesRole";
}
};
QObject::connect(dialog, &QMessageBox::buttonClicked, onClick);
dialog->show(); // this must be show(), not exec()
}
virtual ~Window() { delete dialog; }
private:
Dialog *dialog;
public slots:
void windowSlot() { qDebug() << Q_FUNC_INFO;
close();
}
};
#endif // WINDOW_H
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QMessageBox>
class Dialog : public QMessageBox
{
Q_OBJECT
public:
Dialog() {}
virtual ~Dialog() {}
};
#endif // DIALOG_H
main.cpp
#include <QApplication>
#include <QtGui>
#include "window.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Window window;
window.setWindowTitle("window");
window.show();
return app.exec();
}
Update #1: a very interesting post.

Related

Closing Dialog quits Application if QMainWindow is hidden

I have the following Problem:
I have a Qt MainWindow which starts several Dialogs. Through an external source, I can hide and show the MainWindow. If a dialog is open, only the MainWindow is hidden, but the dialog is still visible. This is not nice but not my main problem. The main problem is, if i close the dialog while the MainWindow is hidden, the whole Application terminates. I do not want that, because I can make my main window visible again by external source.
I know it has something to do with QApplication quitOnLastWindowClosed. But if i set it true, my Application doesn't terminate if i normaly press "X".
Here is an example:
// MainApp.h
#include <QMainWindow>
#include "ui_MainWindow.h"
class MainApp : public QObject {
Q_OBJECT
public:
MainApp(QObject *parent = nullptr);
private slots:
void slotOpenDialog();
private:
QMainWindow mMainWindow;
Ui::MainWindow mUi;
};
// MainApp.cpp
#include "MainApp.h"
#include <QTimer>
#include <QMessageBox>
MainApp::MainApp(QObject *parent) {
mUi.setupUi(&mMainWindow);
mMainWindow.show();
connect(mUi.pushButton, &QPushButton::clicked, this, &MainApp::slotOpenDialog);
// simulate external hide and show mechanism
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout,
[=] {
if(mMainWindow.isHidden()) mMainWindow.show();
else mMainWindow.hide();
});
timer->start(3000);
}
void MainApp::slotOpenDialog() {
QMessageBox::information(nullptr, "Info", "text");
}
// main.cpp
#include <QApplication>
#include "MainApp.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainApp* mApp = new MainApp;
// if set true, I can't exit the application with "X"
//a.setQuitOnLastWindowClosed(false);
int error = a.exec();
delete mApp;
return error;
}
How can I prevent the program from quitting when it is hidden and a still visible dialog has been closed and how can I make it exit normally when the window is visible?
QApplication emits a signal "lastWindowClosed" and it has a quit() slot. As mentioned in the comments, the problem can be solved by connecting your own slot onLastWindowClosed() to that signal and quitting only when you want to.

My qt desktop app keeps crashing after I close out of my starting child dialog and go into my parent dialog

So I am quite new to qt, and am trying to open a desktop app with a child dialog, and when I click a button it points to the parent dialog. I managed to do that, but whenever I run it and click 'go' it points me to my parent window and then crashes! I got the code from this link. the first answer was what got it to work, and the second one didn't work at all. my MainWindow (parent) dialog is survey and my child dialog is global. (I know I named them weird. Still learning).
my main.cpp
#include "survey.h"
#include <QApplication>
#include "global.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget survey;
survey.show();
global popup(&survey);
popup.show();
/*
survey w;
w.show();
*/
return a.exec();
}
my global.cpp
#include "global.h"
#include "ui_global.h"
#include "survey.h"
global::global(QWidget *parent) :
QDialog(parent),
ui(new Ui::global)
{
ui->setupUi(this);
}
global::~global()
{
delete ui;
}
void global::on_Go_clicked()
{
//survey *nWin;
auto win = new survey();
win->setAttribute(Qt::WA_DeleteOnClose);
win->show();
deleteLater();
}
What do I need to change so my desktop app doesn't crash when I run it??
You're calling deleteLater on a global instance, which you did not instantiated with new, it's in your main:
global popup(&survey);
When delete is called, your application crashes.
No need to call deleteLater in your slot.

Create QMainWindow from different thread

I try to create something like a window pool. You can use these windows everywhere in your program to display graphics and plot diagrams etc. The widgets working well but the main problem at the moment is the frustrated tries, to create the pool. One non QObject-Object should represent a QMainWindow to cut the bindings to Qt.
I cannot create a widget -> I tried invokeMethode, connect and QTimer but nothing works. Sometimes the methods donĀ“t get called or I am not in the gui thread... Any idea?
Edit 2 - new version:
header:
#pragma once
#include <QMainWindow>
#include <QTimer>
class MyWindow : QObject
{
Q_OBJECT
public:
MyWindow();
};
class QWindowPool : public QObject
{
Q_OBJECT
public:
QWindowPool();
public slots:
void createWindow();
};
class QWindow : public QMainWindow
{
Q_OBJECT
};
cpp:
#include
#include <QApplication>
#include <QTimer>
#include <QtConcurrent/qtconcurrentrun.h>
#include <iostream>
#include <future>
static QWindowPool *pool = new QWindowPool();
QWindowPool::QWindowPool() {
// check if app is running
if (!QApplication::instance()) {
bool appOnline = false;
QtConcurrent::run([&appOnline](){
int c = 0;
new QApplication(c, NULL);
appOnline = true;
qApp->exec();
});
while (!appOnline) {}
}
moveToThread(QApplication::instance()->thread());
}
void QWindowPool::createWindow() {
printf("window created\n");
new QWindow();
}
MyWindow::MyWindow() {
QTimer::singleShot(0, pool, SLOT(createWindow()));
}
int main()
{
MyWindow mw;
std::thread t1([](){
MyWindow mw;
std::thread t2([](){
MyWindow mw;
});
t2.join();
});
t1.join();
std::cin.ignore();
return 0;
}
Now the code do what is should. I can create widgets in different threads. But there are two scenarios, where I would stack at:
Someone (anyone who would like to use this library) creates before me QApplication and never calls qApp->exec
Someone want to create an own UI with Widget but does not work in my qt::concurrent gui thread. He would probably not get along with this.
What I want is in the final application:
The user should get the possibility to write anywhere in his code and in any thread:
MyWindow mw(dataToDisplay)
and the window should be created and showed to him.
Qt will only let you create widgets from the main GUI thread, this is explicitly mentioned in the docs (emphasis mine):
As mentioned, each program has one thread when it is started. This
thread is called the "main thread" (also known as the "GUI thread" in
Qt applications). The Qt GUI must run in this thread. All widgets and
several related classes, for example QPixmap, don't work in secondary
threads. A secondary thread is commonly referred to as a "worker
thread" because it is used to offload processing work from the main
thread.

Hide console window when gui program sends commands to a cli program?

In my project, I have made a GUI program that will occasionally send commands to a cli program. I do it like this:
system("folder\\program.exe -d folder\\inputFile.dat folder\\outputPath");
Obviously without those names but you get the idea. This works fine, except when my GUI program sends these commands, a command prompt window opens and does whatever the cli program is supposed to do. It looks very bad and unclean.
Is there any way I could "hide" the cli program window but still have it silently do what it needs to do?
Thanks for your time :)
EDIT: I tried olive's technique which was to use QDesktopServices and QUrl to call the program:
QDesktopServices::openUrl(QUrl("folder\\program.exe -d folder\\inputFile.dat folder\\outputPath"));
The console window isn't showing up, however, the program wasn't called at all. Are there any changes that need to be made to the path when using olive's technique rather than my original system() command?
I cannot determine whether you need a cross platform solution or not. On windows execution using start generally hides the command window.
system("start program.exe -d inputFile.dat outputPath");
I solved this problem like so:
QProcess::execute("start program.exe -d inputFile.dat outputPath");
The problem is, I can only do this once. Everytime I try to call it again, it will not work. The thing that makes this hidden is "start." Taking it out allows the console to be seen, it's just blank.
It seems like I need a way to "end" the program or whatever before running it again. (I say or whatever because I have no clue what/why adding "start" to the path does)
QDesktopServices::openUrl() is usually used if you wish to open a document (eg PDF document, web page) in a viewing or editing program and you're not sure which programs have been installed. This function lets the operating system choose for you from the list of default programs with respect to the file types.
Although you can also use the function to open executable files (eg console programs), an alternative to that would be using QProcess. If you don't need to communicate with the console program or wait for it to complete, you can just launch it in a fire-and-forget fashion using one of the two QProcess::startDetached() static functions
QProcess::startDetached
Sorry for misleading with QDesktopService::URL, later i understood that it wont accept parameter.
So implemented by improving error handling, if process not started/exited badly or waitfor the process to finish the task..I think this is useful
In QProcess, execute is blocking thread, but start is resuming the thread.
Current code is using start() API, but more or less featurewise like execute..
Code is copied from SO and modified little for the current requirements.
> Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QShortcut>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
cameraControl = new QProcess(this);
}
MainWindow::~MainWindow()
{
delete ui;
cameraControl->close();
delete cameraControl;
}
void MainWindow::on_pushButton_clicked()
{
// connect the camera control finished signal to the slot that will read the exit code and
// place the std output string from the process into a label on the form
connect(cameraControl, SIGNAL(finished(int , QProcess::ExitStatus )),
this, SLOT(on_cameraControlExit(int , QProcess::ExitStatus )));
// Disable the ui button do we don't get double presses
ui->pushButton->setDisabled(true);
// setup the gphoto2 arguments list
QStringList args;
args.append("d:\\text.txt");
// start the camera control
cameraControl->start("notepad",args);
// // wait for the process to finish or 30 seconds whichever comes first
cameraControl->waitForFinished(30000);
}
void MainWindow::on_cameraControlExit(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << cameraControl->errorString();
qDebug() << cameraControl->readAllStandardError();
qDebug() << cameraControl->readAllStandardOutput();
ui->pushButton->setEnabled(true);
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QProcess>
#include <QObject>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void reply2();
private slots:
void on_pushButton_clicked();
void on_cameraControlExit(int exitCode, QProcess::ExitStatus exitStatus);
private:
Ui::MainWindow *ui;
QProcess* cameraControl;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
in your Qt program,there is a .pro file.You can add this line into the file:
config+=console

Simple multithreading with Qt: am I doing this right?

I'm new to StackOverflow and wondering if I'm doing this right:
I'm writing a simple Qt application to test multi-threading (something I am also completely new to). I made a MainWindow that contains widgets, and a class MyThread that subclasses QThread and overrides the run() method.
The application simply displays two buttons, "Start Counter" and "Stop Counter", and a text field. When "start counter" is pressed, a worker thread is created and runs in the background, continuously incrementing a counter in a while loop and signaling the main thread (where the GUI is) with the updated value. When "Stop Counter" is pressed, a signal is sent to the main thread that stops the while loop, and the counter is stopped until "Start Counter" is pressed again.
This works perfectly fine ... but is it the best way? I'm new at this, and read a lot of people saying "don't subclass QThread" and other people saying "subclass QThread", and it's a little bit confusing. If this isn't the best way to implement this sort of thing (run a computationally-intensive loop in a background thread with "start" and "stop" buttons), what is? If I'm doing it wrong, how do I do it right? I don't want to learn the wrong way.
Thank you! And here's the code:
MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public slots:
void stopRunning();
protected:
virtual void run();
signals:
void signalValueUpdated(QString);
private:
bool isRunning;
};
MyThread.cpp
#include "MyThread.h"
#include <QString>
void MyThread::run()
{
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
static int value=0; //If this is not static, then it is reset to 0 every time this function is called.
isRunning = 1;
while(isRunning == 1)
{
QString string = QString("value: %1").arg(value++);
sleep(1/1000); //If this isn't here, the counter increments way too fast and dies, or something; the app freezes, anyway.
emit signalValueUpdated(string);
}
}
void MyThread::stopRunning()
{
isRunning = 0;
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include "MyThread.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
//Widgets
QHBoxLayout * boxLayout;
QPushButton * startButton;
QPushButton * stopButton;
QLineEdit * lineEdit;
MyThread thread;
};
#endif
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
boxLayout = new QHBoxLayout(this);
startButton = new QPushButton("Start Counter", this);
stopButton = new QPushButton("Stop Counter", this);
lineEdit = new QLineEdit(this);
boxLayout->addWidget(startButton);
boxLayout->addWidget(stopButton);
boxLayout->addWidget(lineEdit);
qDebug("Thread id %d",(int)QThread::currentThreadId());
//When the start button is pressed, invoke the start() method in the counter thread
QObject::connect(startButton,SIGNAL(clicked()),&thread,SLOT(start()), Qt::QueuedConnection);
//When the stop button is pressed, invoke the stop() method in the counter thread
QObject::connect(stopButton,SIGNAL(clicked()),&thread,SLOT(stopRunning()), Qt::QueuedConnection);
//When the counter thread emits a signal saying its value has been updated, reflect that change in the lineEdit field.
QObject::connect(&thread,SIGNAL(signalValueUpdated(const QString&)),lineEdit,SLOT(setText(const QString&)), Qt::QueuedConnection);
}
Most of the time QThread sub-classing is a wrong way to do threading in Qt. I suggest you to read an article about threads, event loops and other which could give you an idea how to use threads in Qt in a better way. But do not listen to anyone who arguing that there is the only one right way to use QThread. There are 2 ways and while subclassing is not needed in general it could be useful sometimes. You just need to use non-subclassing way until you really need to subclass. In your particular case you don't need subclassing.
Replace sleep(1/1000); with msleep(100); Things will be just fine :)