I am unable to get QProcess to read any output from my VBScript. The script executes both on its own and when called from QProcess, and outputs to QCreator's Application Output, so I know my VBS is executing. To troubleshoot I've cut my VBS down to:
WScript.StdOut.WriteLine("Hi")
Qt-side I've tried:
Connecting QProcess's finished, readyReadStandardOutput,
readyReadStandardError signals
I have also tried setProcessChannelMode to QProcess::MergedChannels
In the MainWindow constructor:
connect(Process,SIGNAL(readyReadStandardOutput()),this,SLOT(processDone()));
Slots:
void MainWindow::processDone()
{
qDebug()<<"Out";
/*QString str;
str.append(Process->readAllStandardOutput());
qDebug()<<str;*/
}
void MainWindow::runProcess()
{
QString script = "cscript";
QStringList args;
args<<QString(QDir::currentPath()+ "/myVBs.vbs")<<"//NoLogo";
Process->execute(script,args);
}
QProcess::execute is a static method, so Process->execute(script, args) is equivalent to QProcess::execute(script, args), i.e. your instance Process isn't used at all. Use
Process->start( script, args );
Related
I'm working on a QT project. I was wondering if is possible to create a connection using two signals to execute a method.
I have three classes: A, B and C. Class A emit a signal when a button is pressed (connected in Class C), also in Class C a QProcess is created (from an instance of class B).
In class C I have a connect to get the output of the QProcess. Also, I have another connect to execute a method when a button is pressed (signal emitted in Class A).
So, I need to modify the current behavior, the doSomething() method should be executed when the QProcess output is ready, similar to an if statement:
if(signalA && signal B){
do something...
}
This is the current code:
//This signal will get the output of a Qprocess
connect(objectC,&QProcess::readyReadStandardOutput, [=] (){
QString out = objectB->readAllStandardOutput();
qDebug() << out;
});
//When a button in Class A is pressed doSomething() is executed
//but now I must wait until the above signal generates an output.
connect(objectA, ClassA::buttonPressed, [=] (){
doSomething();
});
objectC -> run(args); // This line execute an external process
any Ideas on how to achieve this?
I found on stackoverflow that in QT we can have two signals in a single connect, like this:
connect(this,SIGNAL(someSignal()),this,SIGNAL(anotherSignal()));
but I don't know how to adapt this to my problem.
The flow of my QT application is the following:
A QProcess is created to launch an external .exe file
The QProcess return a QString
At any moment the user can press a button that will execute a specific method (doSomething()) but needs the output of the QProcess.
The big issue is that sometimes the user press the button before the QProcess ends, so I cannot execute the doSomething() correctly.
The desired behavior is: if the user press the button to execute doSomething(), first I must wait until the output of the QProcess is ready. So if I press the button and if the QProcess takes e.g 10s to finish, the doSomething() should be executed after this 10s.
You can store the state of both events and check them both whenever one of them changes.
// These should probably be defined in the header of your class.
bool processFinished = false;
bool buttonClicked = false;
void checkState() {
if (buttonClicked && processFinished) {
doSomething();
}
}
connect(objectC,&QProcess::readyReadStandardOutput, [=] (){
...
processFinished = true;
checkState();
});
connect(objectA, ClassA::buttonPressed, [=] (){
...
buttonClicked = true;
checkState();
});
Structure Of Application:
MainWindow -> ProcessingThread(QThread) - > QProcess for Python Script
In the Run/Exec loop of Processing Thread I would like to interact with the process.
How do I go about it?
Current Problem:
I know both ProcessingThread(QThread) and its Run loop run inside different threads. Hence if I initialize the QProcess in QThread constructor I am unable to interact with the process because of following error:
QSocketNotifier: Socket Notifiers cannot be enabled or disabled from
another thread
and if I try to initialize the process in the Run Loop I get the following error:
QObject: Cannot create children for a parent that is in a different
thread
(Parent is ProcessingThread(0x984b2a0), parent's thread is QThread(0x940e180)),
current thread is ProcessingThread(0x984b2a0)
If I initialize the QProcess in ProcessingThread constructor, I am able to interact with the script perfectly.
Any suggestions?
Update: Also The reason for using QThread is because I am performing image processing, the Processing Threads keeps fetching images from camera. Some of these images need to be further processed by the Python script running in QProcess.
Update 2: CODE
void MainWindow::MainWindow(QWidget *parent)
{
...
debugProcessingThread = new DebugProcessingThread();
}
class DebugProcessingThread : public QThread
{
Q_OBJECT
...
private:
qProcess *myprocess;
}
DebugProcessingThread::DebugProcessingThread()
{
...
myProcess = new QProcess(this);
myProcess->start("python abc.py");
connect(myProcess, SIGNAL(started()), this, SLOT(processStarted()));
connect(myProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
myProcess->waitForStarted();
}
void DebugProcessingThread::processError()
{
qDebug("PROCESS ERROR");
qDebug() << myProcess->errorString();
}
void DebugProcessingThread::readStandardOutput()
{
qDebug("READ DATA");
qDebug(myProcess->readAll().toStdString().c_str());
myProcess->write("out.txt\n");
}
void DebugProcessingThread::processStarted()
{
qDebug("Process has started");
}
The above code works perfectly.
But I want to send and receive data from function:
void DebugProcessingThread::run()
{
myProcess->write("out.txt\n");
// This Throws socket Error
}
Keep long story short, you shouldn't instantiate anything you going to use in your new thread in the constructor, as every object instantiated there will get an affinity of the thread where your QThread object is created, common practice is either not to subclass QThread at all, just use QObject and moveToThread, and then connect some slot like init() to QThread started() signal, so you can do all initialisation inside the init() which will run inside a new thread, or if for whatever reasons you need QThread subclassing instantiate everything in run().
Also pay attention that QThread itself is nothing more nothing less then a wrapper of your real thread and stays as an object in a thread where you created it.
I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.
I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum
I'm trying to get Qt to launch another Qt program when a button is clicked.
Here is my code.
void Widget::launchModule(){
QString program = "C:\A2Q1-build-desktop\debug\A2Q1.exe";
QStringList arguments;
QProcess *myProcess = new QProcess(this);
myProcess->start(program, arguments);
myProcess->waitForFinished();
QString strOut = myProcess->readAllStandardOutput();
}
So it is supposed to save into the QString strOut. First of all I am having an error with the QString program line I don't understand how to point this to the program as all examples of QProcess I have looked at use / and this doesn't make sense to me. Also with the syntax of the program string correct, will this work?
Thanks
In a C/C++ string literal, you must escape all backward slashes.
It's really bad to use the waitForX() functions in Qt. They block your GUI and make your application unresponsive. From a user experience point of view, it truly sucks. Don't do it.
You should code in asynchronous style, with signals and slots.
My other answer provides a rather complete example how asynchronous process communications might work. It uses QProcess to launch itself.
Your original code could be modified as follows:
class Window : ... {
Q_OBJECT
Q_SLOT void launch() {
const QString program = "C:\\A2Q1-build-desktop\\debug\\A2Q1.exe";
QProcess *process = new QProcess(this);
connect(process, SIGNAL(finished(int)), SLOT(finished()));
connect(process, SIGNAL(error(QProcess::ProcessError)), SLOT(finished()));
process->start(program);
}
Q_SLOT void finished() {
QScopedPointer<Process> process = qobject_cast<QProcess*>(sender());
QString out = process->readAllStandardOutput();
// The string will be empty if the process failed to start
... /* process the process's output here */
// The scoped pointer will delete the process at the end
// of the current scope - right here.
}
...
}
I have a code that uses QProcess like this.
int main(int argc, char *argv[])
{
int status=0;
QProcess pingProcess;
QString ba;
QString exec = "snmpget";
QStringList params;
params << "-v" << "2c" << "-c" << "public" << "10.18.32.52" << ".1.3.6.1.4.1.30966.1.2.1.1.1.5.10";
status=pingProcess.execute(exec, params);
pingProcess.close();
}
This outputs the following.
SNMPv2-SMI::enterprises.30966.1.2.1.1.1.5.10 = STRING: "0.1"
I want to take(read) this output as string. I searched for this and I cant find the solution. Thanks in advance.
Did you try QByteArray QProcess::readAllStandardOutput() docs - here
QString can be instantiated from QByteArray:
QString output(pingProcess.readAllStandardOutput());
As others mentioned, and I join to them, you should not use execute method and replace it with:
pingProcess.start(exec, params);
pingProcess.waitForFinished(); // sets current thread to sleep and waits for pingProcess end
QString output(pingProcess.readAllStandardOutput());
In a more Qt way you can try to use readyReadStandardOutput signal:
connect(&pingProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readData()));
and in corresponding slot readData to the string
QString output = pingProcess.readAllStandardOutput();
#Shf is right in that you should be using readAllStandardOutput. However, you're using the function execute() which is a static method. You should be calling start( ) from an instance of a QProcess.
It may also be a good idea to then either wait for the data with waitForReadyRead, or just wait for the process to finish with waitForFinished( ).
Also, there's an overloaded start function, which allows you to pass the whole command in, which may make your code easier to read: -
QProcess pingProcess;
QString exe = "snmpget -v 2c -c public 10.18.32.52 .1.3.6.1.4.1.30966.1.2.1.1.1.5.10";
pingProcess.start(exe);
pingProcess.waitForFinished();
QString output(pingProcess.readAllOutput());
Note that calling waitForFinished will hang the current process, so if you're going to do something that will take a while, you would then want to dynamically create the QProcess and connect to the finished() signal in order for a connected slot to then read the data.
You shouldn't use QProcess::execute method, it's static and doesn't alter your pingProcess variable. You have no access to a process started using this method. You need to use start() method instead. Note that this method is asynchronous. You need to use waitForFinished and then read the data.
pingProcess.start(exec, params);
pingProcess.waitForFinished();
QByteArray output = pingProcess.readAllStandardOutput();