Start both applications and scripts using QProcess - qt

I have written this function to run scripts or applications:
void TerminalRun (QString command)
{
QProcess process;
process.start("sh",QStringList() << "-c" << command);
process.waitForFinished(-1); // will wait forever until finished
}
It works just fine if I use it for applications like:
TerminalRun("geany &")
However, it can't execute scripts like:
TerminalRun("/path/to/script.sh &")
I don't get any error, but it just does not execute the script.
What is the issue and how can I fix it?
The script executes just fine directly in terminal.
I am using Qt 4.8 in Ubuntu 16.04.

I suggest you to not use "waitForFinished" but "start" and then the signals:
connect(&Process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));
connect(&Process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
connect(&Process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));

Related

catch that new QApplication failed and try something else

I have two programs. One call SelectScreen and another called RadioPanel.
SelectScreen sends a message to RadioPanel telling it what screen its supposed to display the gui on.
RadioPanel uses setenv("DISPLAY", myHostslist[hostId].c_str(),true); to set the DISPLAY environment variable. Then a mQtApplication = new QApplication(mArgc, mArgv); to start the gui.
This works as long as the host info is correct. However if it is not correct QApplication causes the program to end. What I want to do is catch the fact that QApplication failed and try to run the gui on ":0"
I tried using a try catch block but it will not catch. My guess is that QApplication just ends the process and does not throw an exception in this case.
Does anyone know if there is a way to determine if QApplication is going to fail or respond to that failure.
The message I get from QApplication when it fails is:
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, xcb.```
I found a solution. If you use XOpenDisplay you can check the return to confirm that the X Server display is working before you attempt to create the QApplication.
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
void myUiApplication::qtGuiThread()
{
Display *dis;
dis=XOpenDisplay((char *)0);
if(dis!=nullptr)
{
XCloseDisplay(dis);
mQtApplication = new QApplication(mArgc, mArgv);
} else
{
CCS_ERR("Failed to display on host:" << cds::toString(mCdsId) << " "
<< mCdsHosts[mCdsId].c_str() << ".\nPlease edit the "
<< getConfigFileName() << " file. Attempting to run GUI on local X Server.");
setenv("DISPLAY",":0",true);
mQtApplication = new QApplication(mArgc, mArgv);
}
}

Qprocess and avrdude

i'm trying to create a simple QT program that allows me to launch avrdude without using command line operations.
I saw that with Qprocess it's easy to launch any kind of program and I tried succesfully with simple programs like Explorer Word and Others.
The problem is that when i try to open cmd.exe nothing happens, even if i try to pass a batch file containing all the information to launch correctly avrdude.
Here's the code
QProcess *process = new QProcess(this);
process->startDetached("cmd.exe",QStringList()<<"C:/avrdude/avr.bat");
I wrote a minimal sample application which shows how to start cmd with a command using QProcess::startDetached() (on button click):
// standard C++ header:
#include <iostream>
// Qt header:
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QProcess>
int main(int argc, char **argv)
{
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
QMainWindow qWin;
QPushButton qBtn(QString::fromLatin1("Start cmd"));
QObject::connect(&qBtn, &QPushButton::clicked,
[](bool) {
bool ret = QProcess::startDetached(
#if 1 // let Windows search for cmd.exe in %PATH%
QString::fromLatin1("cmd.exe"),
#else // define exact path of cmd.exe
QString::fromLatin1("C:\\Windows\\system32\\cmd.exe"),
#endif // 1
QStringList()
<< QString::fromLatin1("/K")
<< QString::fromLatin1("echo Hello"));
std::cout << "QProcess::startDetached():"
<< (ret ? "OK." : "Failed!") << std::endl;
});
qWin.setCentralWidget(&qBtn);
qWin.show();
return qApp.exec();
}
The Qt project file is left as exercise. (Sorry, I used CMake for this.)
Please, note the #if 1. If 1 is replaced by 0 the alternative code with full path is used. (During chat session we examined special problems with starting the cmd.exe.) On my system, both alternatives did as well.
(My system: Windows 10, VS2013, Qt 5.7)
I too have been working on a Qt program where there are a couple calls to AVRDUDE. This is what worked for me. Here's the code I made for a read of the AVR device through AVRDUDE, followed by a couple of comments.
void MainWindow::call_AVRDUDE_read() //AVR READ
{
QProcess CommandPrompt;
QStringList Arguments;
QString COMPortUsed = (ui->COM_Port_Used->text()); // get the COM port from the user off UI
Arguments << "/C avrdude -c arduino -P "+ COMPortUsed +" -b 115200 -p ATmega328P -e -U eeprom:r:fromEEPROM.bin:r";
CommandPrompt.start("cmd",Arguments);
CommandPrompt.waitForFinished();
}
Here's something else which may well influence things in your application. In my case, I am reading the AVR's EEPROM. There is another routine that writes the EEPROM, but it is essentially the same as above, but a different script is sent.
In BOTH these cases, the AVRDUDE operation takes a few seconds to perform its task. When you use the QProcess::startDetached(), it has the disadvantage that control will return IMMEDIATELY after the AVRDUDE script is called through the QProcess. This can cause problems, if for instance you wanted to (as in my case) read the contents of the EEPROM and try to do so before the read actually completes.
An alternative to startDetached() you might consider trying is shown below. This will retain control until the process is finished, which may be pretty important to you. Use these two lines to replace the startDetached() call you are currently using.
CommandPrompt.start("cmd",Arguments);
CommandPrompt.waitForFinished();
This will wait for the AVRDUDE process to finish before control is returned.
The take away here though is that QProces::startDetached() may return prematurely in your application. Just beware of that.

QProcess with GUI not freezing

I would like to launch mysql from GUI using QProcess. I've tried the following:
QStringList arguments;
arguments << QString("-u%1").arg("myaccount")<< QString("-p%2").arg("password");
QProcess *mysql = new QProcess;
mysql->setReadChannelMode(QProcess::ForwardedChannels);
mysql->execute("mysql", arguments);
if(mysql->waitForReadyRead(-1))
qDebug(mysql->readAllStandardOutput());
But, there is big problem as it's mentioned in Qt Documentation, it's gonna freeze.
How can I solve this? Many advised to use QThread but I don't have any idea how to do that?
Thanks beforehand!
The problem is that you call the QProcess::execute() function and it waits until the process is finished. If you need to avoid freezing you can use readyReadStandardOutput() signal and do the following:
[..]
connect(mysql, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
mysql->start("mysql", arguments);
if (!mysql->waitForStarted()) {
// report error
}
This link may help you:
QProcess fails to execute external executable
Calling MySQL :
c:\mysql\mysql.exe -u MYUSERNAME -pMYPassword
There is no space between -p and password.
Set MySQL Path.

Need to quit a process from inside Qt GUI, just as it is started

I am trying to run C++ executables placed inside SBC6845 [inside /ftest as shown ]. Now these executables are running with
while(1){
// around 250-300 lines of code here
}
infinite loop. Now when I run only the codes from terminal, I can kill them whenever I want to. But I am unable to kill them while running from inside the gui. I execute these codes with Qprocess like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow){
ui->setupUi(this);
connect(ui->pushButton, SIGNAL(pressed()), SLOT(vcm_test()));
connect(ui->pushButton_2, SIGNAL(pressed()), SLOT(offloader_test()));
connect(ui->pushButton_3, SIGNAL(pressed()), SLOT(quit_vcm()));
connect(ui->pushButton_4, SIGNAL(pressed()), SLOT(quit_offloader()));}
void MainWindow::vcm_test(){
QProcess::execute("/ftest/vcm_test_2 \r\n");
}
void MainWindow::offloader_test(){
QProcess::execute("/ftest/off_test_2 \r\n");
}
void MainWindow::quit_vcm(){
QProcess::execute("\x001a \r\n");
}
void MainWindow::quit_offloader(){
QProcess::execute("\x001a \r\n");
}
Now the problem is when the pushbutton or pushbutton_2 i.e. vcm_test() or offloader_test() is invoked the gui becomes unresponsive. Since the gui keeps waiting for the code in /ftest to finish quit option does not work and I have to quit it from the terminal again. Also quitting from terminal closes both the code and the gui.
I have tried searching solutions and used threads too. But I get segmentation error while starting a thread from pushbutton.
I need to be able to quit the process while it is being executed (modification of this code or any new idea is very much appreciated). I am a newbie so please ignore my poor coding skills. Thanks.
QProcess::execute(..) waits for the process to finish, that is why your GUI is freezing. Use QProcess::start(..) instead. To quit the process use the QProcess::close() function
Try this:
QProcess *myProcess = new QProcess(this);
myProcess->start("/ftest/vcm_test_2");
And when you want to close the process:
myProcess->close();
You can also connect your pushbutton's clicked signal to the process' kill slot:
connect(ui->pushButton_3, SIGNAL(clicked()), myProcess, SLOT(kill());
You can make a QProcess object and call start() on it. That way the code doesn't get blocked when you execute the process untill it is finished.
QProcess* myprocess=new QProcess();
myprocess->start("/ftest/vcm_test_2");
You can if you want get a signal from myprocess to know if the process is finished. Which is in your case not usefull.
You can also close the process by invoking
myprocess->close();
Hope that helpes.

Run a program from Qt

I am working with Qt in Linux. I need to run the "evince" pdf reader from Qt.
I have been searching and as I understand I can use Qprocess to make it work. Something like this:
QStringList args;
args.append("/home/user/presentacion0.pdf");
QProcess p(this);
p.start("/usr/bin/evince", args, QIODevice::ReadWrite);
p.waitForFinished();
QString p_stdout = p.readAllStandardOutput();
QString p_stderr = p.readAllStandardError();
But I always get the following error:
No protocol specified
Cannot parse arguments: Cannot open display:
So I tried the system(char *cmd) from stdlib.h and does not work
system("/usr/bin/evince /home/user/presentacion0.pdf");
I think system() does not work because "evince" is a graphical application. However I can run "ls", "mkdir", etc. commands with system() without problems.
Please I need help with this topic.
I Really appreciate your help in advance.
Thank you.
You're running your Qt app from an application (most likely shell) that doesn't have DISPLAY environment variable set properly (it's usually :0). QProcess uses environment of the calling process.
If you're not really interested in grabbing evince's stdout and stderr, and you don't need to wait for its finish, then I would go with QProcess::startDetached().

Resources