launching a program inside another program - c++

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.
}
...
}

Related

Copying Files in Threads to prevent a freezed application

I wrote a C++/QT Application with "Installer" features. Everything workes fine, but when I click outside the window while my programm is in a "copy process", it somehow loses focus and freezes until the copy process is over, then everything is displayed normaly with a QProgressBar value of 100%.
Im copying like this:
void Installer_C::copy(QString aSrcPath, QString aDstPath)
{
//handles
hSrc = CreateFileW(..); //source file
hDst = CreateFileW(..); //destination
//copy
ReadFile(...);
LockFile(...);
WriteFile(...); //->returnes bytesWritten
UnlockFile(...);
updateQProgressBar(bytesWritten); //updates progressbar in my application
CloseHandle(...);
}
This function is called in a foreach loop iterating through a QStringList with files (located in my launchInstall() function).
Due to my problems, I thought about creating Threads for this copy process. Is it more efficient to create a new thread for each Installer_C::copy() call, or to just create one Thread to call the launchInstall() function (I think it wouldn't help much).Or a better Question: Would it even solve my problem that the application freezes? And how shall I do it so that the ProgressBar still will be updated from this thread?
I think, the best way to solve your problem is to create one addition thread to copy process. You can use QThread (Qt documentation: QThread) class to create a thread, which will copy files. The main thread will execute your GUI and it will be available during files copying.
Small example for copying thread:
class CopyThread : public QThread
{
Q_OBJECT
private:
QStringList oldfiles_;
QStringList newfiles_;
public:
CopyThread(const QStringList& oldfiles,
const QStringList& newfiles,
QObject * parent = 0)
: QThread(parent)
, oldfiles_(oldfiles)
, newfiles_(newfiles)
{}
void run() Q_DECL_OVERRIDE
{
int min = qMin(oldfiles_.count(), newFiles.count());
for(int i=0; i<min; ++i)
{
copyFile(oldfiles_.at(i), newFiles_.at(i));
emit signalCopyFile(oldfiles_.at(i), newFiles_.at(i));
}
}
signals:
void signalCopyFile(const QString&, const QString&);
private:
void copyFile(QString aSrcPath, QString aDstPath)
{
QFile::copy(aSrcPath, aDstPath);
}
};
Of course, you must implement slot on your widget for signalCopyFile(const QString&, const QString&) and make connection. Small piece of code (for example) to start copy thread and make connection:
QStringList oldFiles;
oldfiles.append("C:/1.txt");
QStringList newFiles;
newFiles.append("C:/2.txt");
yourProgressBar.setMaximum(oldFiles.count());
yourProgressBar.setMinimum(0);
yourProgressBar.setValue(0);
CopyThread *copyThread = new CopyThread(oldFiles, newFiles, this);
connect(copyThread, &CopyThread::finished, copyThread, &QObject::deleteLater);
connect(copyThread, &CopyThread::signalCopyFile, youWidget, &YouWidget::yourSlot);
copyThread->start();
In yourSlot you can update value of your QProgressBar:
void yourSlot(const QString& oldFile, const QString& newFile)
{
// your actions when one file was copied
yourProgressBar->setValue(yourProgressBar.value() + 1);
}
Everything will be all right without freezes!
As I know there are two possible ways to solve this problem in Qt:
Using QCoreApplication::processEvents(). As docs said it's not a bad solution and suitable for handling long operations. I think it could be usefull for you. For example, you could call it after copying each file (or couple of files).
Using multithreading. It's a great approach to devide GUI threads and logical threads. You could adapt Kirill's solution for your goals.
So my suggestion is: if you need easy and quick working solution, the first way is for you.
If you want to make well-designed and more complex application and you are ready to code little bit more, use the second approach.

How to use OpenMP with Qt so the application would be still clickable

Let's say I have a Qt application with GUI. And I have a button on it. When I click on the button the program computes something in a loop (with OpenMP) and then shows the result with some GUI element(textbox/label/e.t.c).
Is it possible to make the application clickable during these computations (avoid crushing)?
Use QThread (Qt documentation: http://doc.qt.io/qt-5/qthread.html) class to create a thread, which will do your computations. The main thread will execute your GUI application and it will be clickable during computations.
You can find a simple example in documentation for creating your thread:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
You may also try QCoreApplication::processEvents
You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).

Cross-thread signal slot, how to send char *

I've created a simple Qt GUI App and I've created a simple thread in it using worker and worker thread (see below codes, it is a simple code which will be used in a large program).
In this program when I push the push button, the thread is created and started and then I send to the thread a char * containing a file name to be read. But when I send for example the string "salam", it shows me extra characters and file cannot be opened( in console):
"filename=salam▬»
ìax↔↑♂"
Why does this occur?
MainWindow.cpp:
void MainWindow::on_pushButton_clicked()
{
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread,SIGNAL(finished()),
worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate(char *,int)),
worker, SLOT(doWork(char *,int)));
workerThread.start();
char *name=new char[5];
name[0]='s';name[1]='a';name[2]='l';name[3]='a';name[4]='m';
emit operate(name,5);
//vec=new QVector<double>();
}
worker.cpp:
void Worker::doWork(char *fileName,int size){
cout<<"filename="<<fileName<<endl;
}
worker.h:
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
public :
Worker();
public slots:
void doWork(char *fileName,int size) ;
};
#endif // WORKER_H
(Don't forget to add CONFIG+= console in .pro file if you want to test it.)
The problem you have is completely unrelated to Qt, signals or multiple threads.
The char* you're creating isn't null-terminated, so you cannot use it with functions (or operators) that expect char*s to be C strings - they rely on the null terminator. What you're seeing on your console is the result of that - the operator<< overload for char* will print out characters until a zero is encountered. You're printing whatever garbage values are stored in memory after your 5 characters (this is undefined behavior btw).
If you want to stick with char* for whatever reason, and expect to use it with functions that require C-style strings, you must zero-terminate it. (And take care of freeing it, that's not going to happen automatically.)

Launching a while-loop freezes program even if using another thread

In my (Qt-)program I need a continuous request of a value which I get from an external source. But I did not want that this request freezes the whole program, so I created a separate thread for this function. But even if it is running in a separate thread, the GUI freezes, too. Why?
Code for the request function:
void DPC::run()
{
int counts = 0, old_counts = 0;
while(1)
{
usleep(50000);
counts = Read_DPC();
if(counts != old_counts)
{
emit currentCount(counts);
old_counts = counts;
}
}
}
Read_DPC() returns an int value I want to sent to a lineEdit in my GUI.
The main class looks like
class DPC: public QThread
{
Q_OBJECT
public:
void run();
signals:
void currentCount(int);
};
This code is called in the main function as:
DPC *newDPC = new DPC;
connect(newDPC, SIGNAL(currentCount(int)), SLOT(oncurrentCount(int)));
connect(newDPC, SIGNAL(finished()), newDPC, SLOT(deleteLater()));
newDPC->run();
How can I prevent this code from freezing my GUI? What am I doing wrong?
Thanks!
It seems that you code run in GUI thread because you use run() method to start thread, so try to call start() as documentation and many examples said.
Try:
DPC *newDPC = new DPC;
connect(newDPC, SIGNAL(currentCount(int)), SLOT(oncurrentCount(int)));
connect(newDPC, SIGNAL(finished()), newDPC, SLOT(deleteLater()));
newDPC->start();//not run
Anyways you can call thread() method or currentThread() to see in which thread some objects live.

read QProcess output to string

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