Cleanly closing a qt Gui application application programatically - qt

Hello I've been using PyQt 4.8 on windows to create a simple gui application. The gui(main window) has one button, and one QLineEdit widget. Pressing the button simply calls a function to process the contents of the QLineEdit widget.
So far it works well. My main looks like this
class StartQt4App(QtGui.QMainWindow):
def process_stuff(self,param):
#Do stuff here
if __name__="__main__":
app=QtGui.QApplications(sys.argv)
myapplication=StartQt4App()
myapplication.show()
sys.exit(app.exec_())
Using py2exe I can create an windows executable e.g mygui_app.exe
However I want to adapt it so that it can be run from the windows command line. i.e if the user types
Run mygui_app.exe "c:\text_file.txt"
The application launches, this time without the GUI and automatically processes the parameter that was entered when the application was called.
So far this is what I have come up with
class StartQt4App(QtGui.QMainWindow):
def process_stuff(self,param):
#Do stuff here
def process_stuff_again(self,param):
#Do stuff here
return
if __name__="__main__":
if len(sys.argv)==1:
app=QtGui.QApplications(sys.argv)
myapplication=StartQt4App()
myapplication.show()
sys.exit(app.exec_())
else:
app=QtGui.QApplications(sys.argv)
myapplication=StartQt4App()
myapplication.process_stuff_again(param)
sys.exit(app.exec_())
Essentially if the application has been called with parameters I don't want/need to show the gui, simply call the processing function. Once processing is done exit cleanly
Currently it works, at least as far as processing the file goes. However it does not exit, once the processing is complete. Instead the program remains active (I can see it using the Windows Task Manager).
My question is how do I programatically quit the application? so that once done it cleanly shuts itself down.
I have experimented with
app.quit()
app.exit()
myapplication.exit()
myapplication.quit()
None work, essentially the application is still alive and kicking. In desperation I removed the
sys.exit(app.exec_())
from the else portion of the code and now it just crashes, as it it processes the file and then promptly crashes. Very consistently crashes.
Any suggestion as to how to cleanly get the application to close nicely when its called from the command line?

Not really familiar with PyQt, probably you're doing something wrong in your processing function which leads your app crashed.
Also, in case you processing something synchronously, your
app.quit()
called before
app.exec_()
and doesn't have any effect because event loop (that started with app.exec_()) not started yet.
If you still need to have event loop started before your processing function called (i.e. you're using event loop in your processing function), you can do a quirk like this (it's C++, I'm not familiar with PyQt):
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
class MyApp : public QObject
{
Q_OBJECT
public slots:
void process()
{
qDebug() << "Processing...";
qDebug() << "Quit application...";
qApp->quit();;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyApp myapp;
QTimer::singleShot(0, &myapp, SLOT(process()));
int rc = a.exec();
qDebug() << "app finished with" << rc << "code";
}
#include "main.moc"
Also, QMainWindow class doesn't have quit/exit methods (at least in C++).

If you don't need to show the GUI, do you even need to run the QApplication event loop at all? You could just make process_stuff_again a staticmethod
class StartQt4App(...):
#staticmethod
def process_stuff_again(param):
...
app = QtGui.QApplication(sys.argv)
StartQt4App.process_stuff_again(param)
If you're not using any of the Qt classes in process_stuff_again, you don't even need to create the QApplication.
Or if you really need to create an instance of the main window and you absolutely need the event loop, just make sure to call .close on the window at the end of the method. By default, the QApplication should exit when no windows are left open.
def process_stuff_again(self, param):
...
self.close()

Related

Convert a Qt GUI-based application into a console or batch application

I have a Qt GUI-based full application but now I need to use this application in a sort of pipeline in batch mode (console). I've tried several approaches but none of them worked as expected. Here is what I have now:
QApplication a(argc, argv);
MyMainWindow *w = new MyMainWindow();
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
a.exec();
Here is what I need:
QApplication a(argc, argv);
QString project_path = argv[1];
MyMainWindow *w = new MyMainWindow();
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
w->loadPrjFile(project_path);
w->analyze();
w->exportResults();
a.exec();
So, basically what I need is to allow the application to get the project_path through command line (not file dialogs) and execute the methods that a user would usually follow using the GUI. The problem is that these methods should block, in the sense that one should wait for the previous one to finish.
The application itself should block, in the sense that, when executed in the shell, it should wait for the whole execution to finish before quitting. As it should work as a console application the interface should also be hidden.
If you know a way to do that, I would really appreciate a code sample of how this can be done.
The problem you have is that you're trying to develop a console app, but still using Gui widgets, such as QMainWindow. You need to start by separating the Gui classes from everything else in your main project.
I recommend you create a class, derived from QObject, which handles the processing of what you need; loadPrjFile, analyze and exportResults.
Then use an instance of this new class in your MainWindow for the GUI project and use it directly for the console project.
class Worker : public QObject
{
Q_OBJECT
public:
void loadPrjFile(const QString& path);
void analyze();
void exportResults();
};
class MyMainWindow : QMainWindow
{
private:
Worker m_pWorkerObject;
};
If you're developing a console project that doesn't need a Gui, you can use QCoreApplication, instead of QApplication.
Be aware that calling app.exec() starts Qt processing messages, so you only need that if you need a message loop to process events, which may not be the case for a console application, depending on what your app does.
This answer shows the solution that I came up with after a while. I'll put it here because it can be useful to others. The code looks like this:
QApplication a(argc, argv);
QString project_file = argv[1];
MyMainWindow *w = new MyMainWindow();
w->setVisible(false);
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
w->setBatchMode(true);
QObject::connect(w,SIGNAL(loadingFinished()),w,SLOT(analyze()));
QObject::connect(w,SIGNAL(analysisFinished()),w,SLOT(exportResults()));
QObject::connect(w,SIGNAL(exportingFinished()),w,SLOT(close()));
w->loadPrjFile(project_file);
a.exec();
The main considerations are:
w->setVisible(false) was used to hide the MainWindow as also pointed out by #Dissident penguin.
w->setBatchMode(true) was used to set a class variable that is used to supress all the other dialogs throughout the code as also pointed out by #Dissident penguin. Inside the functions I just wrapped the dialog code with an if statement like:
if (!_batchMode) { //show dialog }
Meeting the requirement of sequencial execution was not that easy. I had to create two signals: loadingFinished(), analysisFinished() and exportingFinished(). Then I emit them in the end of loadPrjFile(), analyze() and exportResults() functions respectively. This way I garantee that they are executed in order and that one waits for the other. This is needed because slots are executed asynchronously in Qt.
Finally, I could not take out the method a.exec() because if I do that the program doesn't run properly. I think this is because I'm still using the GUI, it's just hidden. This way, a.exec() is still needed.
To read arguments from the command line in an app with a GUI, you can use the global pointer qApp anywhere in your code. This is particularly useful if you want, for example, to be able to associate your GUI application with a file type, since the file name will be pipleined by the OS to your app (at least it works in Windows).
You can see a detailed answer I gave to the same question in this thread, together with the links to the appropriate documentation, which for some reason is not in the latest versions of Qt.
The second part is not that easy.
You can use w->setVisible(false) before calling a.exec(); to hide your main window, but you will have, to the best of my knowledge, to modify every method that has a dialogue to either react to the command line argument if detected, and disable the dialogue, or use the normal dialogues if no related arguments are detected.
If you only need to call methods of the main window that have no interaction with the user, then it won't be that much work, and you might get away with not calling a.exec (if and only if no part of your code is using signals and slots in batch mode), which in reality starts the main loop of the GUI and won't be needed in that case.
Something like this might work:
QApplication a(argc, argv);
MyMainWindow *w = new MyMainWindow();
if(1 < qApp->arguments().count()) //Command line arguments detected
{
QString project_path = qApp->arguments().at(1);
w->loadPrjFile(project_path);
w->analyze();
w->exportResults();
}
else //No command line arguments detected
{
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
a.exec();
}
If, on the other hand, the functions loadPrjFile(), analyze(); and exportResults() are slots and not, as your code suggests, methods of your main window, they will not be called sequentially and you will have no choice but using signals and slots so each function can notify the next one that it finished its job, and therefore will have to call a.exec

Qt application remains in memory after closing all windows

I'm a beginner in using Qt and OpenCV, and I have a small problem.
My application works fine, but after closing it seems that opencv.exe (application name) is still in memory.
Here is my code:
int main(int argc, char* argv[]) {
QCoreApplication a(argc, argv);
cv::Mat img = cv::imread("img.jpg");
cv::namedWindow("Image");
cv::imshow("Image",img);
return a.exec();
}
How to kill task with closing application window?
I don't sure that I work correct with exec() function.
QCoreApplication::exec() starts an event loop.
Often times this is tied to the presence of a terminal window.
With QApplication::exec() it also starts an event loop, but it usually is tied to the presence of a QMainWindow or the last QWidget that was opened.
The easiest way right now for you to close it, is to go to Projects > Run > Run in Terminal, and check it.
You may also need to go to your .pro file and add CONFIG += console.
When you start using Qt signals and slots, the event loop will be extremely useful.
Also for any of Qt's GUIs to function properly you need the exec() event loop running.
Another way that you can kill your task when running it in Qt Creator is to go to the Application Output tab at the bottom and click the red square stop button.
Hope that helps.
You could try to call qApp->quit() in the close event of your non-qt window (I don't know OpenCV though).
qApp is equivalent to QCoreApplication::instance() if you started a non-gui application (in Qt terms of course), or a QApplication if you started a gui application.
To gracefully come out of event loop started by QCoreApplication::exec() QCoreApplication::quit () must be called.
Somehow when you are done with your OpenCV stuff it should call QCoreApplication::quit (). As it is a static slot you can connect a signal to it or call it explicitly.

QT application app.exec() in main() code is not reached until the main window is closed

I have created a QT application using QT Creator 2.4.0.
and created a main.cpp file that includes main() function as below:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Q_INIT_RESOURCE(MainResources);
MainWindow mainWindow;
mainWindow.show();
cout << "1\n";
int retVal = app.exec();
cout << "2\n";
return retVal;
}
When I execute this function the couts "1" and "2" are not shown at all.
I was expecting to see at least "1" in the console output.
they are printed only after I close the main window.
thus it seems as if app.exec() is not executed until the main window is closed...
1 - can anyone explain this?
When I try to execute this application from command line (the app is built statically)
the call returns immediately after I run the application.exe file, and doesn't wait for the main window to be closed.
2 - is there a way to make the application wait until the main window is closed?
Thanks
app.exec() is a blocking function (it launches Qt event loop) and doesn't return until the last window of the app is closed.
You indeed probably doesn't see "1" because of buffering issues. use qDebug() << "1" instead.
It's highly likely that the standard output is buffered, and thus the "1" may actually be printed but isn't flushed. You'd have to flush the standard output to get it to appear at the right time. Or you can print to cerr instead, which is likely unbuffered.
You indicate that the program runs normally in the first case (from QtCreator?) but without the console output you expect and in the second case, running from the console directly, the program exits without showing a window? I would say that you are running two different executables.

Correct way to quit a Qt program?

How should I quit a Qt Program, e.g when loading a data file, and discovered file corruption, and user need to quit this app or re-initiate data file?
Should I:
call exit(EXIT_FAILURE)
call QApplication::quit()
call QCoreApplication::quit()
And difference between (2) and (3)?
QApplication is derived from QCoreApplication and thereby inherits quit() which is a public slot of QCoreApplication, so there is no difference between QApplication::quit() and QCoreApplication::quit().
As we can read in the documentation of QCoreApplication::quit() it "tells the application to exit with return code 0 (success).". If you want to exit because you discovered file corruption then you may not want to exit with return code zero which means success, so you should call QCoreApplication::exit() because you can provide a non-zero returnCode which, by convention, indicates an error.
It is important to note that "if the event loop is not running, this function (QCoreApplication::exit()) does nothing", so in that case you should call exit(EXIT_FAILURE).
You can call qApp->exit();. I always use that and never had a problem with it.
If you application is a command line application, you might indeed want to return an exit code. It's completely up to you what the code is.
While searching this very question I discovered this example in the documentation.
QPushButton *quitButton = new QPushButton("Quit");
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection);
Mutatis mutandis for your particular action of course.
Along with this note.
It's good practice to always connect signals to this slot using a
QueuedConnection. If a signal connected (non-queued) to this slot is
emitted before control enters the main event loop (such as before "int
main" calls exec()), the slot has no effect and the application never
exits. Using a queued connection ensures that the slot will not be
invoked until after control enters the main event loop.
It's common to connect the QGuiApplication::lastWindowClosed() signal
to quit()
If you're using Qt Jambi, this should work:
QApplication.closeAllWindows();
if you need to close your application from main() you can use this code
int main(int argc, char *argv[]){
QApplication app(argc, argv);
...
if(!QSslSocket::supportsSsl()) return app.exit(0);
...
return app.exec();
}
The program will terminated if OpenSSL is not installed
//How to Run App
bool ok = QProcess::startDetached("C:\\TTEC\\CozxyLogger\\CozxyLogger.exe");
qDebug() << "Run = " << ok;
//How to Kill App
system("taskkill /im CozxyLogger.exe /f");
qDebug() << "Close";
example

Ways to create a QDialog outside the main thread

I am trying to create a client application in QT which requires both threads for processing and a variable amount of window instances. But I am having a hard time trying to figure out how to create a new window inside one of the processing thread. I understand that all ui elements must be created in the same thread as the QApplication class, but I need to be able to instantiate, or at least have a reference to a QDialog in another thread.
Communicating between the thread and QDialog can be done using signals, I am not worried about this, but actually creating the window is another matter. I could use signals to tell the main thread to create an instance to the window, and then retrieve the pointer to it somehow, but to me that seems a bit to complicated and ugly. Is there a better way to accomplish such a task? To create a QDialog outside the main thread were the QApplication class exists?
Edit : I have tried the Q_INVOKABLE method but it does not work across threads. I have created a view factory class which can create a QDialog of a type I specify and returns a pointer to it. This class has been instantiated in the main GUI thread and a reference to this class is sent to any worker threads. The problem is that, when a thread invokes the create method from the factory using Qt::BlockingQueuedConnection, the invoke method fails. If I change it to Qt::DirectConnection, the invoke method calls the right create method but in the current thread as the worker thread.
My main function looks like this :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ViewFactory vFactory;
vFactory.registerCreator(Util::W_CONNECT, new ConnectWindow::ConnectCreator());
ClientApp app;
if(!app.Initialize(&vFactory))
return 0;
app.start();
a.exec();
.............................
}
And my run function from the ClientApp thread looks something like this :
void ClientApp::run()
{
QDialog * tmp = NULL;
QMetaObject::invokeMethod(this->_vFactory, "create", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QDialog*, tmp), Q_ARG(int, 0));
}
Like I said, the invokeMothod will not fail if I change the connection type to Qt::DirectConnection, so the params are not the problem, but rather calling the method across a separate worker thread.
You can only do Gui stuff in the gui thread. The obvious solution is for the worker thread to send a message to the gui thread = a signal in Qt terms.
If a worker thread needs to ask a question it should send a message to the gui thread and then block until it gets a signal back.
AFAIK, signals (or just a dynamically callable method, using Q_INVOKABLE) or an event is the way to go.
Note that, using QMetaObject::invokeMethod() (with Qt::BlockedConnection), you can call a function safely across threads and get a return value back without too much coding.
It seems like QObject::moveToThread can solve this problem. This function moves event processing loop to another thread.
Example from Qt documentation:
myObject->moveToThread(QApplication::instance()->thread());

Resources