Track the script execution progress in the progressBar Qt - c++

In my program, I run the execution of a Python script:
void analysis::on_pB_start_clicked()
{
QString file = ui->lE_path->text();
if (file.size() == 0)
{
QMessageBox::warning(this, "warning", "");
return;
}
QProcess analyse;
QString cArg;
cArg="/tmp/pixmap.py -f " + file;
analyse.start("python3 "+cArg);
analyse.waitForFinished();
analyse.close();
}
This process is running in the background and I can't track the execution time of this process.
Please tell me how I can track the execution of this script through the progressBar in Qt on the program form?
I think that in the Python script being run, me need to draw conclusions at some stage of the code, for example, Print ("1"), Print ("2"), and so on, and track these conclusions in your program and pass them to the progressBar, but these are just my assumptions... I could be wrong... please tell me how to act correctly and productively in this case.
And yet, when executing the above code, the program window freezes (waiting) for the duration of the execution of this script.
In the Python script, I use the matplotlib.pyplot library, and it is called there several times, several graphs are created and saved to a directory, which in the next I use these graphs in my Qt program.

Related

How do I keep a command executed by QProcess when the process ends?

I'm trying to find a way to keep the commands executed by QProcess after GUI program is terminated in Linux system. Now, when the process ends, all the commands executed are gone. Is there a way to keep that after QProcess is terminated?
// code which executes command in linux
QProcess *mproc = new Qprocess(this);
QStringList args;
mproc->setWorkingDirectory("/home/test");
args << "-c" << "source tool_def1.env; source tool_def2.env; myProg";
mproc->start("/bin/csh", args);
The tool_def1.env and tool_def2.env file are included some environment variables for executing myProg, like set path = (~~~~).
In GUI Program, this code is well done. And, I want to execute myProg program in terminal which GUI program is run after GUI program is terminated.
But, if GUI Program is terminated, I can't run myProg because the environment variables of tool_def1.env and tool_def2.env file is disappear.
Is it possible to keep the environment variables? Or, is it possible to execute myProg program in other process with environment variables of mproc process as following?
QProcess *mproc2 = new QProcess(this);
mproc2->setWorkingDirectory("/home/test2");
mproc2->start("myProg");
The overload of QProcess::startDetached you are using is a static method, so it will not take into consideration attributes of particular instances, i.e., mproc->setWorkingDirectory("/home/test") doesn't set the working directory for the static method, only for mproc. When you launch the process, as the working directory is not set for the static call, the program cannot be found and it fails.
As you can see in the documentation, the static startDetached also admits the working directory as a parameter, so you can change your code to:
QStringList args;
args << "-c" << "source tool_def1.env; source tool_def2.env; myProg";
QProcess::startDetached("/bin/csh", args, "/home/test");
Another way is using the non-static version, which requires the program to be specified separately:
QProcess mproc(this);
QStringList args;
args << "-c" << "source tool_def1.env; source tool_def2.env; myProg";
mproc.setArguments(args);
mproc.setWorkingDirectory("/home/test");
mproc.setProgram("/bin/csh");
qint64 pid; // to store the process ID (will become invalid if the child process exits)
mproc.startDeatached(&pid);
Regarding your second question, take a look at QProcess::setProcessEnvironment. Just that you'll have to use the non-static way to set the environment of the process. You can get the environment variables of the current process using QProcess::systemEnvironment.
mproc.setProcessEnvironment(QProcess::systemEnvironment());
Update from comments: if you want to always use the environment variables active when the GUI application was running (is it some kind of configurator?) you can just save them to a file (a JSON for example), then load and set them manually from the second process.
To extract them, you can do something like:
const auto env_vars = QProcess::systemEnvironment().toStringList();
Now env_vars will be a list of strings with format NAME_OF_ENVAR=VALUE_OF_ENVAR. You can save such list to the file (you will need to prepend an export at the beginning of each line to be usable with source).
I've tested the static version in Windows (VS 15.8.2 and Qt 5.10.0) and it worked as expected. Code used:
#include <qprocess.h>
int main(int argc, char* argv[])
{
QProcess::startDetached("cmd", QStringList() << "/c" << "test.exe", "../test/");
return 0;
}
where test.exe's code is basically a never ending process.
Note: An interesting fact, and as a note for developer using VS. For the same program and build, if it is executed from the command line it works correctly: application ends and the second process keeps running in the background, but if executed from the VS IDE then the console window keeps alive, and if I close it, the the second process is killed too. When debugged, the debugger ends but the console is still shown. I suppose it is because VS somehow tracks all created processes when launched from the IDE.

How to avoid waitForStarted with QProcess to stop GUI from freezing?

I am running wscript with QProcess to run a VB Script that converts Excel files to tab delimited text files. The script runs fine and everything, but the GUI freezes and the user is unable to interact with it for a significant amount of time. Here is the code:
/* Create txt files and store paths */
for (int i = 0; i < excelFilepaths.size(); ++i) {
wscript->start("wscript.exe", QStringList() << vbs.fileName() << excelFilepaths.at(i) << newDir.absolutePath() + "/" + QString::number(i + 1));
wscript->waitForFinished();
payloadPaths.push_back(newDir.absolutePath() + "/" + QString::number(i + 1));
}
So whats going on is that I have multiple excel file paths and a QProcess allocated on the heap. This QProcess runs the VB Script that converts the excel files into text files and then stores the path of the new text file. This takes a long time (about 20 seconds for 4 excel files). During this time the GUI is frozen. I would like the user to be able to use parts of the GUI that don't interfere with the process.
Now I suspect that the cause of this issue is
QProcess::waitForFinished()
And I've read online about connecting the finished() and error() signals of QProcess to remove this problem. However I've been having difficulty doing so. I'm running this code as a method of a class that inherits from QObject and containst the Q_OBJECT macro, so everything should be set. I just need some help putting the rest of the pieces together. How can I make it so my GUI does not freeze while QProcess is running? Please help.
To quote the documentation at the section called Synchronous Process API:
waitForStarted() blocks until the process has started.
waitForReadyRead() blocks until new data is available for reading on the current read channel.
waitForBytesWritten() blocks until one payload of data has been written to the process.
waitForFinished() blocks until the process has finished.
Calling these functions from the main thread (the thread that calls QApplication::exec()) may cause your user interface to freeze.
Keep that in mind. However you may overcome this issue using something like that:
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus){ /* ... */ });
Note that there are some more signals which may suite any desired purpose.
I had the same problem but with QSerialPort. However, i think the solution is the same. I couldn't find a way to have "serial->waitForReadyRead()" not freezing the GUI, so, I implemented my own function.
void Research::WaitSerial(int MilliSecondsToWait)
{
QTime DieTime = QTime::currentTime().addMSecs(MilliSecondsToWait);
flag = 0;
while(QTime::currentTime() < DieTime && !flag)
{
QCoreApplication::processEvents(QEventLoop::AllEvents,100);
if(BufferSerial != "")
{
flag++;
}
}
}
Of course, your problem is similar but not the same. Just change the ifto have your "stopping condition". Hope this helps.
EDIT: This was not originally my ideia. I found it on a forum somewhere. So I don't take the credits.

Qt program freezes every time

I'm making a C++ GUI program in Qt using qtcreator its not complete yet but when ever I build and run to test the program it runs then if i click buttons that open a file or write something in a file, the button does that and then the program freezes. Why this happens, What I'm doing wrong or what's the issue.
It mainly freezes in theses two functions:
void MainWindow::on_kmpOpenButton_clicked()
{
QString kmplayerloc = "\"F:\\Program Files\\The KMPlayer\\KMPlayer.exe\"";
QProcess::execute(kmplayerloc);
}
void MainWindow::on_nbopenbutton_clicked()
{
// Remember tha if you have to insert " in a string \"....location of file or anything u want to put.......\"
QString netbeansloc = "\"F:\\Program Files\\NetBeans 7.4\\bin\\netbeans.exe\"";
QProcess::execute(netbeansloc);
}
From the documentation
Starts the program program [..] in a new
process, waits for it to finish, and then returns the exit code of the
process.
The calling thread freezes until the external process is finished. If you don't want this, use the method start or startDetached.

How to stop a process running in a shell in a different system?

Ok, so I am executing a program ./led.sh present in my SBC6845, from my host system using a qt-C++ program. This program basically connects my SBC to my host system. It is the equivalent of "hyperterminal" or "Minicom". I obtained this program (the example code) "uartassistant" inside "qextserialport-1.2rc.zip" from http://code.google.com/p/qextserialport/ .
I came across this link: Running shell command in QT c++ in ubuntu , while searching how to execute a shell command from inside the qt program. I tried and succeeded in executing ./led.sh. Thanks to the link.
I declared
void someaction(); // in the dialog.h
then in dialog.cpp I add this
connect(ui->pushButton, SIGNAL(clicked()), SLOT(someaction()));
and this
void Dialog::someaction()
{
QString command = "sh ./led.sh\r\n"; const char* command2;
command2 = command.toLocal8Bit().data();
port->write(command2);
I was able to do the ledflash in my SBC.
But the problem occurs when I try to stop ./led.sh, I am unable to do so in the uartassistant (bugs, need modification, still working).
But for the time being I am trying to make another pushbutton_1 and put something like "Ctrl+Z" inside and ask ./led.sh to stop.
I came across some other links which I am unable to put due to low reputation points.
I have no idea how to use SIGTERM / kill option[from other links] inside qt app and execute on pushbutton click.
Say if I used kill how would I determine the pidof of multiple such pushbutton actions and assign whom to kill.
Also I would like to add that my SBC has ash [Almquist shell]. So it being low memory clone of Bourne shell, I don't know if it would support normal commands for exiting led.sh.
I have no idea how to use SIGTERM / kill option[from other links]
inside qt app and execute on pushbutton click.
As with so much, Qt gives you an intuitive abstraction that allows you to not have to worry about any of this, namely QProcess. In your case you'd want something like this:
QProcess proc;
proc.start("led.sh");
...
//handle Ctrl-Z event
proc.close();
The first answer here has several other techniques for executing more complicated shell commands.
I have found a temporary solution for my problem. I am yet to try the qprocess action.
In dialog.h I added another function:
void someotheraction();
then in dialog.cpp I did this:
connect(ui->pushButton_2,SIGNAL(clicked()), SLOT(someotheraction()));
and this:
void Dialog::someotheraction()
{
QString command = "\x001a \r\n"; const char* command2; // Ctrl-Z = \x001a
command2 = command.toLocal8Bit().data();
port->write(command2);}
The fifth reply here gave me the idea. I don't know how, but it did the job maybe some one can explain it better.

program stops after execvp( command.argv[0], command.argv)

I am writing a small shell program that takes a command and executes it. If the user enters a not valid command the if statement returns a -1. If the command is correct it executes the command, however once it executes the command the program ends. What am I doing wrong that is does not execute the lines of code after it? I have tested execvp( command.argv[0], command.argv) with ls and cat commands so I am pretty sure it works. Here is my code.
int shell(char *cmd_str ){
int commandLength=0;
cmd_t command;
commandLength=make_cmd(cmd_str, command);
cout<< commandLength<<endl;
cout << command.argv[0]<< endl;
if( execvp( command.argv[0], command.argv)==-1)
//if the command it executed nothing runs after this line
{
commandLength=-1;
}else
{
cout<<"work"<<endl;
}
cout<< commandLength<<endl;
return commandLength;
}
From man page of execvp(3)
The exec() family of functions replaces the current process image with
a new process image
So your current process image is overwritten with the image of your command! Hence you need to use a fork+exec combination always so that your command executes in the child process and your current process continues safely as a parent!
On a lighter note I want to illustrate the problem with a picture as a picture speaks a thousand words. No offence intended :) :)
From the documentation on exec
The exec() family of functions replaces the current process image with a new process image. The functions described in this manual page are front-ends for execve(2). (See the manual page for > execve(2) for further details about the replacement of the current process image.)
If you want your process to continue, this is not the function you want to use.
#Pavan - Just for nit-pickers like myself, technically the statement "current process is gone" is not true. It's still the same process, with the same pid, just overwritten with a different image (code, data etc).