How to continually run QProcess while running my QML program? - qt

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"

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();
}

In Qt, how to cancel QtConcurrentRun if it is not finished by the time the application quits?

I have an application that does a presumably long operation on disk, that I want to start in the background as soon as the application opens. However, if the task is not done by the time the last window is closed, I need to cancel this operation.
Class doing long work in setRootPath:
class Scanner : public QObject
{
Q_OBJECT
Q_PROPERTY(QString currentPath READ currentPath NOTIFY currentPathChanged)
Q_PROPERTY(bool done READ done NOTIFY doneChanged)
public:
Scanner(QObject * parent = 0);
QString currentPath() const;
bool done() const;
void setRootPath(QString root);
signals:
void currentPathChanged(QString newPath);
void doneChanged(bool newDone);
private:
QString m_path;
bool m_done;
};
Main:
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false);
Scanner scanner{};
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("scanner", &scanner);
QFuture<void> f = QtConcurrent::run(&scanner, &Scanner::setRootPath, QString("path/to/Pictures"));
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
f.waitForFinished(); // of course, this hangs the gui... how do I get around that?
return app.exec();
}
I have read on the Qt forums that I need to connect to lastWindowChanged signal, but I can't figure out how to use QObject::connect here... what's my recipient?

Qt connect - object emits signal before connect is issued

I have following main.cpp:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "database/uepeoplemodel.h"
#include "core/uestatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now, inside main.cpp I create two objects from classes:
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
and I connect signal from UePeopleModel to slot in ueApplicationStatus:
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
The problem is when uePeopleModel is created, the signal is emmited inside constructor:
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent),
QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
} // if
this->ueDatabase().setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
this->ueDatabase().setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
this->ueDatabase().setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
this->ueDatabase().setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
/*
if(this->lastError().isValid())
qDebug() << this->lastError();
*/
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
// qDebug() << this->ueDatabase().lastError();
}
// qDebug() << this->ueDatabase().connectionNames();
} // default constructor
before connect is issued and therfore ueApplicationStatus object does not catch is with slot. Does anyone has idea how to get rid of this situation?
You shouldn't use the constructor to open the connection with the database.
Use the constructor only to instantiate other classes, initialize variables, allocate memory and so on.
In your case, your constructor should be used to initialize the database, but you could create another method with:
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
}
This method would be called after the connect you have in your main.cpp.
I've solved the problem by adding method void ueConnectToDatabase() and moved the content of constructor into it and redefined main.cpp as:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
uePeopleModel->ueConnectToDatabase();
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now the object is created, signal and slot connected and AFTER this the connection to database occurs.

QDialog exec() can not exit process

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog dlg;
dlg.exec();
return a.exec();
}
That's all my code, but when I close the window, The process isn't exit, it seems that drop in the loop a.exec().
Generally speaking, calling any exec is a bad idea, other than QCoreApplication::exec() or QDrag::exec(). The presence of exec() and waitForXxx() methods is an enticing trap for the unwary. Those methods are "easy" to use, but that ease comes at a price of hard to track bugs. Don't use them.
You should simply show the dialog:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMessageBox msg;
msg.setText("Hello");
msg.addButton(QMessageBox::Close);
msg.show();
return a.exec();
}
If you wish to wait for the dialog to be accepted or rejected, you should use the dialog's clickedButton slot. QMessageBox has a long-standing bug that makes the accepted and rejected signals useless :(
// https://github.com/KubaO/stackoverflown/tree/master/questions/messagebox-show-25545652
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
#include <functional>
[...]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
auto onClick = [&msg]() {
auto role = msg.buttonRole(msg.clickedButton());
if (role == QMessageBox::NoRole)
QApplication::quit();
if (role == QMessageBox::YesRole) {
auto label = new QLabel("I'm running");
label->setAttribute(Qt::WA_DeleteOnClose);
label->show();
}
};
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QObject::connect(&msg, &QMessageBox::buttonClicked, onClick);
#else
QObject::connect(&msg, SIGNAL(buttonClicked(QAbstractButton*)),
new FunctorSlot{onClick, &msg}, SLOT(call()));
#endif
msg.show();
return app.exec();
}
#include "main.moc"
For Qt 4, you need the following helper:
// Qt 4 only
struct FunctorSlot : public QObject {
Q_OBJECT
public:
std::function<void()> callable;
template <typename Fun>
FunctorSlot(Fun && fun, QObject * parent = {}) :
QObject{parent}, callable{std::forward<Fun>(fun)} {}
Q_SLOT void call() {
callable();
}
};
Possible solution:
QApplication a(argc, argv);
QDialog dlg;
QTimer::singleShot( &dlg, 0, SLOT(exec()) );
return a.exec();
It will work well. First - application event loop will be started. Then dialog event loop will be executed. After closing of dialog, both dialog and application loop will be finished. Application loop will be terminated automatically (by default), when last window is closed.
But, as noted by #thuga - there are no reason to call exec(). It is enough to call show() method.

QProcess disable stdout redirection

I want to start a process from a QT app and catch its termination event. Its done with the method QProcess::start(). But unlike in startDetached(), the standard output of the process is redirected to a buffer. I don't want that.
I can't find how to disable it. An ugly workaround is to call setStandardOutputFile("/dev/stdout")
test.h
#ifndef MY_TEST_H
#define MY_TEST_H
#include <QCoreApplication>
class MyApp : public QCoreApplication {
Q_OBJECT
private Q_SLOTS:
void subprocessStarted();
void subprocessFinished(int);
public:
MyApp( int & argc, char ** argv );
};
#endif
test.cpp
#include "test.h"
#include <QProcess>
#include <QCoreApplication>
#include <stdio.h>
#define ENTRY printf("%s\n", __PRETTY_FUNCTION__)
MyApp::MyApp( int & argc, char ** argv ) : QCoreApplication(argc, argv) {
ENTRY;
QProcess *process = new QProcess();
//process->setStandardOutputFile("/dev/stdout");
process->start("/bin/echo aaa");
bool b;
b = connect(process, SIGNAL(started()), SLOT(subprocessStarted()));
printf("connect started %d\n", b);
b = connect(process, SIGNAL(finished(int)), SLOT(subprocessFinished(int)));
printf("connect finished %d\n", b);
}
void MyApp::subprocessStarted() {
ENTRY;
}
void MyApp::subprocessFinished(int ret) {
ENTRY;
printf("%d\n", ret);
}
int main(int argc, char *argv[]) {
ENTRY;
MyApp a(argc, argv);
return a.exec();
}
Does QProcess::closeReadChannel(ProcessChannel channel) work for you?
Closes the read channel channel. After calling this function, QProcess
will no longer receive data on the channel. Any data that has already
been received is still available for reading. Call this function to
save memory, if you are not interested in the output of the process.
Like this-
QProcess *process = new QProcess();
process->start("/bin/echo aaa");
process->closeReadChannel(QProcess::StandardOutput);
process->closeReadChannel(QProcess::StandardError);

Resources