How to close a Qt qml application programmatically without errors? - c++

I want to programmatically close a qml qt application.
I tried the method described here How to quit the C++ application in Qt QML
Qt.callLater(Qt.quit)
via qml and using
QObject::connect(&engine, &QQmlApplicationEngine::quit, &QGuiApplication::quit);
I also tried to close the application from c++ using QCoreApplication::quit(). And the method described in the qt documentation via signals and slots by calling the slot QGuiApplication::quit.
The problem is that the application closes with an error:
“The program has unexpectedly finished.”
“The process was ended forcefully.”
If I close the application with a standard cross, then the problem does not arise.
I suspect that the problem is in QQmlApplicationEngine. Because if I remove the line engine.load(url); then the application closes correctly.
I use QT 5.13.0 minGW and QT 5.13.0 MSVC2017 (32 and 64).
If I run in the debug, the application gives an error, but the error is absolutely not informative.
here is my application code c++:
#include <QGuiApplication>
#include <QTimer>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
engine.load(url);
QTimer* timer=new QTimer();
QObject::connect(timer, &QTimer::timeout, &app, &QGuiApplication::quit, Qt::QueuedConnection);
timer->start(2000);
return app.exec();
}
and code qml file:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
}
UPDATE:
I tried to compile Qt5.9.9 Qt5.13.0 QT5.15 and this problem occurs everywhere. But when I compiled with the Qt6.4 version, the problem disappeared and the application terminated correctly. Anyway, I'll leave the question open.

As JarMan pointed out QTimer::singleShot() can be used to close your application. In fact, this is the example provided straight from the documentation https://doc.qt.io/qt-6/qtimer.html#singleShot :
#include <QApplication>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTimer::singleShot(600000, &app, SLOT(quit()));
...
return app.exec();
}

Related

QT Program segfaults when trying to instantiate QWidget

I have a simple QT project that looks like the following:
#include <QtWidgets/qwidget.h>
TempClass::TempClass() {
QWidget* tempWidget = new QWidget();
}
Everything compiles fine, but when I try to run the program it segfaults on the line that instantiates a new QWidget. FYI I am using QT 5.7.1.
The issue here was that I was instantiating my application as a QGuiApplication vs. a QApplication. Once I changed the code to the following, my QWidget instantiates properly:
QApplication app(argc, argv);

Create separate QML window from C++ code

In my application I want to create another window with QML UI from C++ code.
I know it's possible to create another window using QML Window type, but I need the same thing from C++ code.
So far I managed to load my additional qml file into QQmlComponent:
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(QUrl(QStringLiteral("qrc:/testqml.qml")));
if ( component.isReady() )
component.create();
else
qWarning() << component.errorString();
How do I display it in a separate window?
You can achieve that using a single QQmlEngine. Following your code, you could do something like this:
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(QUrl(QStringLiteral("qrc:/main.qml")));
if ( component.isReady() )
component.create();
else
qWarning() << component.errorString();
component.loadUrl(QUrl(QStringLiteral("qrc:/main2.qml")));
if ( component.isReady() )
component.create();
else
qWarning() << component.errorString();
I prefer QQmlApplicationEngine though. This class combines a QQmlEngine and QQmlComponent to provide a convenient way to load a single QML file. So you would have fewer lines of codes if you have the opportunity of using QQmlApplicationEngine.
Example:
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
engine.load(QUrl(QStringLiteral("qrc:/main2.qml")));
return app.exec();
We could also use QQuickView. QQuickView only supports loading of root objects that derive from QQuickItem so in this case our qml files couldn't start with the QML types ApplicationWindow or Window like in the examples above. So in this case, our main could be something like this:
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();
QQuickView view2;
view2.setSource(QUrl("qrc:/main2.qml"));
view2.show();
return app.exec();
You can try to create new QQmlEngine
For anyone curious, I ended up solving the problem with slightly different approach.
My root QML document now looks like this:
import QtQuick 2.4
Item {
MyMainWindow {
visible: true
}
MyAuxiliaryWindow {
visible: true
}
}
Where MainWindow is a QML component with root element ApplicationWindow and AuxiliaryWindow is a component with root element Window.
Works just fine and you don't have to worry about loading two separate QML files.

Qt5 QuickView cannot create window: no screens are available

I receive this error (title, below) whenever I try to run the following code:
#include <QCoreApplication>
#include <QQuickView>
int main(int argc, char *argv[]){
QCoreApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl::fromLocalFile("app.qml"));
QObject *object = (QObject*)view.rootObject();
view.show();
delete object;
return app.exec();
}
Cannot create window: no screens available
The program has unexpectedly finished.
All I can find online for that error are bug reports arising from specific conditions significantly more involved than the above.
app.qml is a file that runs fine alone, i.e. without the above C++ and in a separate project configured as a 'Qt Quick UI'. Giving it's qrc:// path, or deliberately specifying a file which does not exist has no effect.
Note the QObject* cast - this was not present in the docs, but without it:
/main.cpp:11: error: cannot initialize a variable of type 'QObject *' with an rvalue of type 'QQuickItem *'
How should this be done?
The QCoreApplication can be used with console application, not with GUI ones, i.e. you have to use a QGuiApplication object. It seems to me that you created a console application instead of a graphical one.
You can create a proper application via the Qt Quick Application, add your "app.qml" as a resource to that project and call such a file instead of the default "main.qml", provided by the project template.
If you want to quick fix your current project, just check that the .pro file is set to import GUI libraries:
QT += gui qml quick
Set your qml file as a resource:
Create a new resource file via file -> new File or Project... -> Qt -> Qt Resource File
Right click the newly created .qrc file and click add existing file to add your "app.qml" file
Finally, rewrite your main like this:
#include <QQuickView>
#include <QGuiApplication>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv); // GUI APPLICATION!!!
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:///app.qml")));
view.show();
return a.exec();
}
However, going for the Qt Quick Application project would be the wiser choice.

Problems Receiving QSerialPort Signals

I'm trying to write a simple program to test out the serial port, but am having trouble getting QSerialPort to work. I never receive signals from the QSerialPort object. I get 3 runtime warnings/errors that I think probably have something to do with it.
The errors are:
QApplication::qAppName: Please instantiate the Qapplication object first
QSocketNotifier: Can only be used with threads started with QThread
QSocketNotifier: Can only be used with threads started with QThread
The code snippet below is the smallest sample I can give to recreate the errors, it doesn't show me connecting signals but I think these errors are why I don't see them. If I don't call the open function none of the errors occur.
#include <QtGui/QApplication>
#include <QSerialPort>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
PowerBoardGUI w;
w.show();
QSerialPort* serial = new QSerialPort();
serial->setPortName("/dev/ttyS1");
serial->setBaudRate(QSerialPort::Baud9600);
bool isOpen = serial->open(QIODevice::ReadWrite);
serial->close();
delete serial;
return a.exec();
}
The test system is Redhat 5.6. A static version of QT 4.7.4. And the latest version of QSerialPort (built from GIT today).

Simplest Qt Dialog

I have a C++ function that checks if Bluetooth is activated. I want to display a simple dialog telling the user to activate his Bluetooth and try again. As I have a QML interface this can be done through C++ or QML.
You can use the built-in information message box:
#include <QApplication>
#include <QDebug>
#include <QMessageBox>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QMessageBox::information(0, "Try Again", "Please try to activate your Bluetooth again.");
}
Qt Components have some dialogs out of box:
http://doc.qt.nokia.com/qt-components-symbian-1.0/qml-querydialog.html