Open external application and close current application - c++

In my gui project, I need to start another application that updates the application that called the initial update.. if that makes sense.
The only way the secondary program can update the main program is if the main program is closed.
This is what I did:
QDesktopServices::openUrl(QUrl("file:update.exe"));
qApp->quit();
In the update program I also added a 2 second sleep timer before the update begins just in case. The problem is the main program never closes.
I have replaced qApp->quit() with qApp->exit, QApplication::quit(), QCoreApplication::exit() etc and nothing is closing the main program.
Any suggestions?

Try this one:
#include <QApplication>
#include <QProcess>
qApp->quit();
QProcess::startDetached("update.exe");

You can try to do the following (hopefully idea is clear from the source code):
// Launches another application after 5 seconds.
class Launcher : public QObject
{
Q_OBJECT
public:
Launcher()
{
QTimer::singleShot(5000, this, SLOT(launch()));
}
private slots:
void launch()
{
QProcess::startDetached("notepad");
qApp->quit();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Launcher launcher;
[..]
return app.exec();
}
#include "main.moc"

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.

Is there any way to make really sure QSplashScreen has been repainted on the screen?

I have a problem that on Linux with Xorg (Ubuntu 14.04) and Qt 5.5.1 QSplashScreen isn't painted until I get to the event loop. Even if I call QApplication::processEvents() multiple times, it still isn't painted, even after 1000 calls, although the window is already on the screen, retaining the original pixels which were there before the app launched, thus being effectively invisible*. From this answer I got an idea of using a timed loop of calling QApplication::processEvents(), like here:
#include <QThread>
#include <QApplication>
#include <QSplashScreen>
int main(int argc, char** argv)
{
QApplication a(argc,argv);
QSplashScreen splash;
splash.show();
splash.showMessage("Loading...");
// The hack to try to ensure that splash screen is repainted
for(int i=0;i<30;++i)
{
QThread::usleep(1e3);
a.processEvents();
}
QThread::usleep(5e6); // simulate slow loading process
splash.showMessage("Finished");
return a.exec();
}
The above code actively sleeps for 30 ms in an attempt to make QSplashScreen repaint. This works for me, but I'm not sure that it'll always work e.g. on a busy/slow CPU or in whatever other conditions (the magic value of 30 iterations was found empirically).
Another, quite intrusive in general, way would be to do all the necessary loading in another thread, only to make sure that QSplashScreen in the main thread does have an active message queue. Due to the need to considerably redo the main program, this looks not too good of a solution.
So, is there any way to make sure that QSplashScreen has been repainted, so that its window doesn't contain garbage, and only then to proceed with long blocking loading process?
* I discovered this when I moved a window behind the splash screen
One way to avoid the unknowable a priori magic timeout is to wait for an exact event: the paint event. On X11 it appears to come with a delay. To do this waiting we'll have to subclass QSplashScreen and override QSplashScreen::paintEvent(), like here:
#include <QThread>
#include <QApplication>
#include <QSplashScreen>
class MySplashScreen : public QSplashScreen
{
bool painted=false;
void paintEvent(QPaintEvent* e) override
{
QSplashScreen::paintEvent(e);
painted=true;
}
public:
void ensureFirstPaint() const
{
while(!painted)
{
QThread::usleep(1e3);
qApp->processEvents();
}
}
};
int main(int argc, char** argv)
{
QApplication a(argc,argv);
MySplashScreen splash;
splash.show();
splash.showMessage("Loading...");
splash.ensureFirstPaint();
QThread::usleep(5e6); // simulate slow loading process
splash.showMessage("Finished");
return a.exec();
}
The solution is rather simple: keep the event loop running until the window is repainted. This should be done without any spinning, i.e. you shouldn't be using any explicit timeouts.
#include <QtWidgets>
class EventSignaler : public QObject {
Q_OBJECT
QEvent::Type m_type;
protected:
bool eventFilter(QObject *src, QEvent *ev) override {
if (ev->type() == m_type)
emit hasEvent(src);
return false;
}
public:
EventSignaler(QEvent::Type type, QObject *object) :
QObject(object), m_type(type) {
object->installEventFilter(this);
}
Q_SIGNAL void hasEvent(QObject *);
};
int execUntilPainted(QWidget *widget) {
EventSignaler painted{QEvent::paint, widget};
QObject::connect(&painted, &EventSignaler::hasEvent, qApp, &QCoreApplication::quit);
return qApp->exec();
}
int main(int argc, char **argv) {
QApplication app{argc, argv};
MySplashScreen splash;
EventSignaler painted{QEvent::Paint, &splash};
splash.show();
splash.showMessage("Loading...");
execUntilPainted(&splash);
QThread::sleep(5); // simulate slow loading process
splash.showMessage("Finished");
return app.exec();
}
#include "main.moc"

How some objects are created before main event loop?

While debugging, I came up with strange for me thing. In the main function, I commented out creation of window as follows:
#include <QApplication>
#include <QMetaType>
#include <QDebug>
//#include "mainwindow.h"
int main(int argc, char *argv[])
{
qDebug() << "Creating QApplication";
QApplication a(argc, argv);
qDebug() << "QAplication has been created successfully";
qDebug() << "Creating application window";
// MainWindow w;
qDebug() << "Displaying application window";
// w.show();
qDebug() << "Application window has been displayed successfully";
return a.exec();
}
I thought I am just creating an event loop and lunching it. But output surprised me:
"17:28:32.793" ButtonControl: contructor.
"17:28:32.807" GestureControl: contructor
Creating QApplication
QAplication has been created successfully
Creating application window
Displaying application window
Application window has been displayed successfully
I have ButtonControl and GestureControl classes and first 2 lines of output are from their constructors. I create their objects inside of other class, which I use in MainWindow class. The strange thing for me is they are created before/without MainWindow and event loop. Their messages are printed even if I don't create QApplication object and call its exec() method. I tried cleaning and running qmake, and rebuilding, but no success. What's going on here? What is wrong with ButtonControl and GestureControl classes?
Env: win7, Qt 5.10, MSVC 2015.
Edit
Here is my Control class:
class Control : public QObject
{
Q_OBJECT
public:
explicit Control(QObject *parent = nullptr);
static ButtonControl *getButtonController() {
return &buttonController;
}
static GestureControl *getGestureController() {
return &gestureController;
}
private:
static ButtonControl buttonController;
static GestureControl gestureController;
};
I call this class inside my MainWindow. (As I understand from comments this code snippet is enough)
Following comments, I did a small research and found this answer:
Static members are initialized before main(), and they are destroyed in reverse order of creation after the return in main().
Static members are statically allocated, and their lifetime begins and ends with the program.
Thank you everyone who commented out.

can't close app from dialog box (Qt app)

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.

QApplication In Non-Main Thread

I need to exec() a QApplication in a thread that is not main (my GUIs must be plugins that can be dynamically loaded and unloaded at runtime, so I have no access to the main thread). Does anyone know of a (relatively) painless way to hack around Qt's restriction against starting QApplication outside of main?
I'm developing in Linux with Qt4 in C++ using gcc4.3.4.
You can start a QApplication in a PThread as below
//main.cpp
#include <iostream>
#include "appthread.h"
int main(int argc, char *argv[]) {
InputArgs args = {argc, argv};
StartAppThread(args);
sleep(10);
return 0;
}
//appthread.h
struct InputArgs{
int argc;
char **argv;
};
void StartAppThread(InputArgs &);
//appthread.cpp
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include "appthread.h"
#include <pthread.h>
void *StartQAppThread(void *threadArg) {
InputArgs *args = (struct InputArgs*) threadArg;
QApplication app(args->argc, args->argv);
QMainWindow w;
w.show();
w.setCentralWidget(new QPushButton("NewButton"));
app.exec();
pthread_exit(NULL);
}
void StartAppThread(InputArgs &args) {
pthread_t thread1;
int rc = pthread_create(&thread1, NULL, StartQAppThread, (void*)&args);
}
If you are using QThread then you already have normal Qt event loop and can just run exec() inside QThread::run() function. While you can't work with GUI objects outside of the main thread you still can interact with them through queued signal/slot connections. Maybe you can try to store pointer to the main thread QThread object and call QObject::moveToThread() to move your GUI objects to the main thread instead of moving QApplication into another thread.
I think it's not really good idea to try to go against toolkit with different kind of hacks and kluges.
Ok, I got something that works! It's not pretty, but it definitely does the job.
Create a QMainWindow derivative with all of your actual GUI code in it and overload the event() function of this class to call this->show()
Create a class (let's call it Runner) which will hold a pointer to your QMainWindow derivative, and give it a run function.
In the Runner::Runner(), start up a thread which will call Runner::run()
In Runner::run() (which is now running in it's own thread) construct a QApplication, and an instantiation of your QMainWindow derivative. Call the exec() function of the QApplication.
Now, when you want to start up your GUI, just post any event to your QMainWindow derivative, and it will show itself!
This solution seems to work very well in Linux, although it really seems to be exploiting some loophole in Qt and may not work on other platforms. Definitely easier than patching Qt though.
Patch Qt, I guess and remove the main thread check, and test if that works for you.
According to
http://bugreports.qt-project.org/browse/QTBUG-7393
that won't work on OS X/Cocoa though, as Cocoa assumes the first thread spawned to be the main/UI thread.
Adding my 2 cents with a fancy lambda and C++ threads:
#include "mainwindow.h"
#include <QApplication>
#include <thread>
int main(int argc, char *argv[])
{
std::thread t1
(
[&]
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
);
t1.join();
}
Here Mainwindow can be your QMainWindow.
A good solution is found in: git#github.com:midjji/convenient_multithreaded_qt_gui.git
then its just e.g.
run_in_gui_thread(new RunEventImpl([](){
QMainWindow* window=new QMainWindow();
window->show();
}));
or whatever code you wish to run in the gui thread.
callable from any thread, at any time, while taking care of setting things up for you in the bg.