Qt console application quit is problematic, stack variables is not being destructed - qt

When you close console application in Windows 10, in the following code, Boo object is not being destructed even it is a local variable. I tried to catch interrupts but it didnt worked. I tried to connect to aboutToQuit signal , it didn't worked as well. Is there any way to destruct an object just before quit?
class Boo {
public:
~Boo() {
std::cout << "i'm dying" << std::endl;
}
};
void handle_quit() {
std::cout << "I quit" << std::endl;
}
int main(int argc, char *argv[])
{
Boo test;
QCoreApplication app(argc, argv);
QTimer::singleShot(0, &app, [&]() {
std::cout << "hello world qt";
});
QObject::connect(&app, &QCoreApplication::aboutToQuit, [&]() {
handle_quit();
});
return app.exec();
}

Here is the answer:
If you close the concole application by closing cmd window, the application gets SIGBREAK interrupt. In that case, you need to destruct everthing in 5 seconds. After 5 second application is being terminated forcefully by the system. Since my stack is not being destructed in that case, I moved it to heap and destructed it as soon as I got SIGBREAK.
class Boo {
~Boo () {
//do destruction job..
}
}
std::shared_ptr<Boo> test;
void SigInt_Handler(int) {
//destruct in 5 second...
test.reset();
}
int main(int argc, char *argv[])
{
test = make_shared<Boo>();
signal(SIGBREAK , &SigInt_Handler);
QCoreApplication app(argc, argv);
QTimer::singleShot(0, &app, [&]() {
std::cout << "hello world qt";
});
return app.exec();
}

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 continually run QProcess while running my QML program?

The problem I have in my code is, once the QML engine uplouded the QProcess stop!! Is it possible to let QProcess run while the QMLis already in operation!
the idea is: I want the user to be able to interact with only one specific mouse and one keyboard and to continually check this condition!
Can some one check what is the problem here?
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
bool scanForDevices=0;
USBdeviceID *usbdeviceid =new USBdeviceID();
engine.rootContext()->setContextProperty("USBdeviceID", usbdeviceid);
QProcess OProcess;
QString Command; //Contains the command to be execute
Command = "lsusb";
while (1)
{
OProcess.start(Command,QIODevice::ReadOnly); //Starts execution of command
OProcess.waitForFinished(); //Waits for execution to complete
QString StdOut = OProcess.readAllStandardOutput(); //Reads standard output
QString StdError = OProcess.readAllStandardError(); //Reads standard error
cout<<"\n Printing the standard output..........\n";
cout<<endl<<StdOut.toStdString();
bool mouse1 = StdOut.contains("ID 046d:c03e");
bool keyBoard1 = StdOut.contains("ID 413c:1003");
if (mouse1 ==1 && keyBoard1==1)
{
// start main program
// revoke A signal to tell QML the correct devices are connected
usbdeviceid->setMouse1Detected(1);
usbdeviceid->setkeyBoard1Detected(1);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
}
}
}
It is not necessary to create infinite loops in Qt, instead the most elegant thing is to use the signals.
#include <QGuiApplication>
#include <QProcess>
#include <QQmlApplicationEngine>
class LSUSB: public QObject
{
Q_OBJECT
public:
LSUSB(const QStringList & ids, QObject *parent=nullptr): QObject(parent), status(false), ids(ids)
{
QString command = "lsusb";
connect(&process, &QProcess::readyReadStandardOutput, this, &LSUSB::onReadyReadStandardOutput);
connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &LSUSB::onFinished);
process.setProgram(command);
process.start();
}
Q_SIGNALS:
void isLoaded();
private Q_SLOTS:
void onReadyReadStandardOutput(){
QString stdout = process.readAllStandardOutput();
status = true;
for(const QString & id: ids){
status &= stdout.contains(id);
}
if(status){
process.kill();
Q_EMIT isLoaded();
}
}
void onFinished(){
if(!status)
process.start();
}
private:
QProcess process;
bool status;
QStringList ids;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
LSUSB lsusb({"ID 046d:c03e", "ID 413c:1003"});
USBdeviceID usbdeviceid;
QObject::connect(&lsusb, &LSUSB::isLoaded, [&engine, &usbdeviceid](){
usbdeviceid.setMouse1Detected(1);
usbdeviceid.setkeyBoard1Detected(1);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
QCoreApplication::exit(-1);
});
return app.exec();
}
#include "main.moc"

How to redirect text output to command line in Qt?

If I have a QApplication, how can I redirect output (from qDebug) to the command line console that first started the executable?
Note that I don't want to create a new console.
You can use qInstallMessageHandler to redirect qDebug() to your own function.
void qDebugRedirect(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
switch (type) {
case QtDebugMsg:
std::cout << msg.toStdString() << " from line: " << context.line;
break;
default:
break;
}
}
You want to install the message handler as early as possible:
int main(int argc, char *argv[])
{
qInstallMessageHandler(qDebugRedirect); // Install the handler
QCoreApplication a(argc, argv);
qDebug() << "Hello from qDebug";
return a.exec();
}

QRemoteObjectNode::remoteObjectAdded signal does not fire

While learning how to use QtRO tech preview module, I tried a simple 3 node network ( A registry node, a source object remoting node, and a client node).
registry node main.cpp:
#include <QCoreApplication>
#include <QRemoteObjectRegistryHost>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QRemoteObjectRegistryHost host(QUrl("tcp://127.0.0.1:5557"));
return a.exec();
}
source node main.cpp:
#include <QCoreApplication>
#include <QRemoteObjectHost>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTimer timer;
timer.start(10000);
QRemoteObjectHost host;
if(!host.setHostUrl(QUrl("tcp://127.0.0.1:5556"))) qDebug() << "Host url " << host.lastError();
if(!host.setRegistryUrl(QUrl("tcp://127.0.0.1:5557"))) qDebug() << "Reg url " << host.lastError();
if(!host.enableRemoting(&timer, "HostTimer")) qDebug() << "Remoting error " << host.lastError();
return a.exec();
}
client node main.cpp:
#include <QCoreApplication>
#include <QRemoteObjectNode>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QRemoteObjectNode node(QUrl("tcp://127.0.0.1:5557"));
QObject::connect(&node, &QRemoteObjectNode::remoteObjectAdded,
[](const QRemoteObjectSourceLocation& info){
qDebug() << "New source added : " << info;
});
qDebug() << "Waiting for registry ";
node.waitForRegistry(10000);
qDebug() << "Already here sources : " << node.registry()->sourceLocations();
QTimer timer;
timer.start(5000);
QObject::connect(&timer, &QTimer::timeout,
[&](){
qDebug() << "New sources list : " << node.registry()->sourceLocations();
});
return a.exec();
}
I begin by starting the registry node, then the client node and finally the source node, with this launch sequence I expect to get the remoteObjectAdded fired up, but It didn't.
Your help will be highly appreciated.
I answer my question.
I used the wrong signal source in the connect method call.
the client node will be as :
#include <QCoreApplication>
#include <QRemoteObjectNode>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QRemoteObjectNode node(QUrl("tcp://127.0.0.1:5557"));
QObject::connect(node.registry(), &QRemoteObjectRegistry::remoteObjectAdded,
[](const QRemoteObjectSourceLocation& info){
qDebug() << "New source added : " << info;
});
qDebug() << "Waiting for registry ";
node.waitForRegistry(10000);
qDebug() << "Already here sources : " << node.registry()->sourceLocations();
QTimer timer;
timer.start(5000);
QObject::connect(&timer, &QTimer::timeout,
[&](){
qDebug() << "New sources list : " << node.registry()->sourceLocations();
});
return a.exec();
}
It is the registry who fire the signal not the node, It sound logic after all the source nodes are connected to the registry, so it fire the remoteObjectAdded signal.

Display and get the result of a QMessageBox from outside of a QObject

I am trying to display and get the result a message box from outside of a QObject class. I seem to be able to generate the dialog like this:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class DialogHandler : public QObject
{
Q_OBJECT
signals:
void MySignal();
public:
DialogHandler()
{
connect( this, SIGNAL( MySignal() ), this, SLOT(MySlot()) );
}
void EmitSignal()
{
emit MySignal();
}
public slots:
void MySlot()
{
QMessageBox* dialog = new QMessageBox;
dialog->setText("Test Text");
dialog->exec();
int result = dialog->result();
if(result)
{
std::cout << "ok" << std::endl;
}
else
{
std::cout << "invalid" << std::endl;
}
}
};
#include "main.moc" // For CMake's automoc
void MyFunction(DialogHandler* dialogHandler)
{
dialogHandler->EmitSignal();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
DialogHandler* dialogHandler = new DialogHandler;
MyFunction(dialogHandler);
return app.exec();
}
To get the result back in MyFunction, it seems to work to do simply pass an object to fill with the result like this:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class DialogHandler : public QObject
{
Q_OBJECT
signals:
void MySignal(int* returnValue);
public:
DialogHandler()
{
connect( this, SIGNAL( MySignal(int*) ), this, SLOT(MySlot(int*)), Qt::BlockingQueuedConnection );
}
void EmitSignal(int* returnValue)
{
emit MySignal(returnValue);
}
public slots:
void MySlot(int* returnValue)
{
std::cout << "input: " << *returnValue << std::endl;
QMessageBox* dialog = new QMessageBox;
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
dialog->setText("Test Text");
dialog->exec();
int result = dialog->result();
if(result == QMessageBox::Yes)
{
*returnValue = 1;
}
else
{
*returnValue = 0;
}
}
};
#include "main.moc" // For CMake's automoc
void MyFunction(DialogHandler* dialogHandler)
{
int returnValue = -1;
dialogHandler->EmitSignal(&returnValue);
std::cout << "returnValue: " << returnValue << std::endl;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
DialogHandler* dialogHandler = new DialogHandler;
QtConcurrent::run(MyFunction, dialogHandler);
std::cout << "End" << std::endl;
return app.exec();
}
Does that seem reasonable? Is there a better way to do it?
This isn't possible quite like you have it, but with a bit of work it could be done. One option, of course, would be to convert your class to a QObject, at which point you could send signals. It doesn't help for the delay during exec, however. If that is necessary, you could have a messaging class that lives in the main UI thread, but can be called from other threads. The function called from other threads would need to lock, make a semaphore, and send an event to itself with the semaphore and message to be displayed. Then, in customEvent (which would be in the UI thread), you would create the message box, exec it, and trigger the semaphore after the message box is cleared.
Of course, things get a bit more complicated if you need to send information back the other way as well. Then you'll need a complete subsystem for your program, instead of just one basic class like I describe here.

Resources