reading and writing to QProcess in Qt Console Application - c++

Noted: this appears to be a specific issue question but hopefully it can be edited for all to related to
I need to interact with a QProcess object.
The Problem:
I am not getting any output from QProcess after calling QProcess:write(input)
More Info:
Going through the doc pages led me to create an example below:
I have a script requesting user input, and finally displaying and appropriate message based on the user input.
Testing:
After adding a "log" feature to my script for testing, the following occurs:
script executes
script requests user input (confirmed by the 'first' qDebug() << p->readAll())
script accepts input from QProcess (confirmed by script 'log output')
After this, no output is received. The following 2 debug statements both fire (i.e. wait 30s each)
if (!p->waitForReadyRead()) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished()) {
qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
Followed by:
QString s = QString(p->readAll() + p->readAllStandardOutput());
where s is an empty string.
The issue is s should contain either "success" or "failed"
Calling Code:
QString cmd = QString("sh -c \"/path/to/bashscript.sh\"");
QString input = QString("Name");
QString result = runCommand(cmd, input)
Process Code:
//takes 2 parameters,
// cmd which is the code to be executed by the shell
// input which acts as the user input
QString runCommand(QString cmd, QString input){
QProcess *p = new QProcess(new QObject());
p->setProcessChannelMode(QProcess::MergedChannels); //no actual reason to do this
p->start(cmd);
if (p->waitForStarted()) {
if (!p->waitForReadyRead()) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished()) {
//reads current stdout, this will show the input request from the bash script
//e.g. please enter your name:
qDebug() << p->readAll();
//here I write the input (the name) to the process, which is received by the script
p->write(ps.toLatin1());
//the script should then display a message i.e. ("success" o "failed")
if (!p->waitForReadyRead()) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished()) {
qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
}
QString s = QString(p->readAll() + p->readAllStandardOutput());
return s;
}
else{
qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
p->waitForFinished();
p->kill();
return QString();
}
script.sh (-rwxrwxr-x)
#!/bin/bash
#returns
# "success" on non empty $n value
# "failed: on empty $n value
#
echo "enter your name:"
read n
if [[ ! -z $n ]];
then
echo "success"
exit 0;
else
echo "failed"
exit 1;
fi
UPDATE
#KevinKrammer I modified the run command as you said, also using the QStringList with the args.
Still does not get output, infact the waitForReadyRead() and waitForFinished() returns false instantly.
Called with:
QString r = runCommand(QString("text"));
Process Code:
QString runCommand(QString input){
QProcess *p = new QProcess(new QObject());
p->setProcessChannelMode(QProcess::MergedChannels);
//script is the same script refered to earlier, and the `cd /home/dev` IS required
p->start("sh", QStringList() << "-c" << "cd /home/dev" << "./script");
;
if (p->waitForStarted()) {
if (!p->waitForReadyRead(5000)) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
qDebug() << p->readAll();
p->write(input.toLatin1());
if(!p->waitForFinished(5000)){
qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
QString s = QString(p->readAll() + p->readAllStandardOutput());
return s;
}
else{
qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
p->waitForFinished();
p->kill();
return QString();
}
Terminal Output of the Process:
started
readChannelFinished
exit code = "0"
waitForReadyRead() [false] : CODE: "5" | ERROR STRING: "Unknown error"
""
waitForFinished() [false] : CODE: "5" | ERROR STRING: "Unknown error"
Press <RETURN> to close this window...
Thoughts on this?
UPDATE 2
#Tarod Thank you for taking the time to make a solution.
It works, however not completely is expected.
I copied over your code, exactly.
Made a few changes in the mReadyReadStandardOutput()
See additional info below.
The problem:
After running the application (and script), I get a result -> AWESOME
Everytime it is the incorrect result i.e. "failed". -> NOT AWESOME
Terminal Output:
void MyProcess::myReadyRead()
void MyProcess::myReadyReadStandardOutput()
"enter your name:\n"
""
void MyProcess::myReadyRead()
void MyProcess::myReadyReadStandardOutput()
"failed\n"
Press <RETURN> to close this window...
script contents:
#!/bin/bash
echo "enter your name:"
read n
echo $n > "/tmp/log_test.txt"
if [[ ! -z "$n" ]];
then
echo "success"
exit 0;
else
echo "failed"
exit 1;
fi
/tmp/log_test.txt output
myname
running this manually from console:
dev#dev-W55xEU:~$ ls -la script
-rwxrwxr-x 1 dev dev 155 Jan 25 14:53 script*
dev#dev-W55xEU:~$ ./script
enter your name:
TEST_NAME
success
dev#dev-W55xEU:~$ cat /tmp/log_test.txt
TEST_NAME
Full code:
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
class MyProcess : public QProcess
{
Q_OBJECT
public:
MyProcess(QObject *parent = 0);
~MyProcess() {}
public slots:
void myReadyRead();
void myReadyReadStandardOutput();
};
MyProcess::MyProcess(QObject *parent)
{
connect(this,SIGNAL(readyRead()),
this,SLOT(myReadyRead()));
connect(this,SIGNAL(readyReadStandardOutput()),
this,SLOT(myReadyReadStandardOutput()));
}
void MyProcess::myReadyRead() {
qDebug() << Q_FUNC_INFO;
}
void MyProcess::myReadyReadStandardOutput() {
qDebug() << Q_FUNC_INFO;
// Note we need to add \n (it's like pressing enter key)
QString s = this->readAllStandardOutput();
qDebug() << s;
if (s.contains("enter your name")) {
this->write(QString("myname" + QString("\n")).toLatin1());
qDebug() << this->readAllStandardOutput();
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyProcess *myProcess = new MyProcess();
QString program = "/home/dev/script";
myProcess->start("/bin/sh", QStringList() << program);
a.exec();
}
#include "main.moc"
script issue? QProcess issue?

Unfortunately I don't have all your code, so I made an example. I hope it helps you.
If I compare my code to yours, I think the problem could be you are not calling readAllStandardOutput() after writing or maybe you are not calling exec() in your main.cpp.
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
class MyProcess : public QProcess
{
Q_OBJECT
public:
MyProcess(QObject *parent = 0);
~MyProcess() {}
public slots:
void myReadyRead();
void myReadyReadStandardOutput();
};
MyProcess::MyProcess(QObject *parent)
{
connect(this,SIGNAL(readyRead()),
this,SLOT(myReadyRead()));
connect(this,SIGNAL(readyReadStandardOutput()),
this,SLOT(myReadyReadStandardOutput()));
}
void MyProcess::myReadyRead() {
qDebug() << Q_FUNC_INFO;
}
void MyProcess::myReadyReadStandardOutput() {
qDebug() << Q_FUNC_INFO;
// Note we need to add \n (it's like pressing enter key)
this->write(QString("myname" + QString("\n")).toLatin1());
// Next line no required
// qDebug() << this->readAll();
qDebug() << this->readAllStandardOutput();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyProcess *myProcess = new MyProcess();
QString program = "/home/fran/code/myscript.sh";
myProcess->start("/bin/sh", QStringList() << program);
a.exec();
}
#include "main.moc"
Script to test the application:
echo "enter your name:"
read n
if [ ! -z "$n" ];
then
echo "success"
exit 0;
else
echo "failed"
exit 1;
fi

Related

Execute CMD Command with QProcess and Save it in QString

I wanted to execute the cmd command "wmic share get name" with QProcess and then save the result of the command in the QString variable. In further, I wanted to show it in QMessageBox or ... How can I do that?
You can use QProcess for this. Let's say I want to execute g++. Example:
QProcess p;
p.setProgram("g++");
p.setArguments({"-O3", "filename.cpp"});
p.start();
// wait for the process to finish executing
// returns true on success
if (!p.waitForFinished()) {
qDebug() << "Failed to execute!!";
const QString error = p.readAllStandardError();
if (!error.isEmpty()) {
qDebug () << "Exit status: " << p.exitStatus() << ", Error: " << error;
}
return;
}
// read output
const QString output = p.readAllStandardOutput();
qDebug () << output;
// read error
const QString error = p.readAllStandardError();
if (!error.isEmpty()) {
qDebug () << error;
}
//do whatever you want with output

how to get latitude/longitude from geo address using Qt c++ QGeoServiceProvider?

I am trying to use the osm api via a QGeoServiceProvider and QGeoCodingManager to derive the latitude and longitude from a given physical address.
Thereby I stumbled upon this Question, which seems to do exactly what I need.
However I want to implement this in a qt gui application as a separate function and I don' t understand what is happening in the connect.
Could someone please explain or how I can modify it to get it to work in a function ?
cout << "Try service: " << "osm" << endl;
// choose provider
QGeoServiceProvider qGeoService("osm");
QGeoCodingManager *pQGeoCoder = qGeoService.geocodingManager();
if (!pQGeoCoder) {
cerr
<< "GeoCodingManager '" << "osm"
<< "' not available!" << endl;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
// build address
QGeoAddress qGeoAddr;
qGeoAddr.setCountry(QString::fromUtf8("Germany"));
qGeoAddr.setPostalCode(QString::fromUtf8("88250"));
qGeoAddr.setCity(QString::fromUtf8("Weingarten"));
qGeoAddr.setStreet(QString::fromUtf8("Heinrich-Hertz-Str. 6"));
QGeoCodeReply *pQGeoCode = pQGeoCoder->geocode(qGeoAddr);
if (!pQGeoCode) {
cerr << "GeoCoding totally failed!" << endl;
}
cout << "Searching..." << endl;
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
[&qGeoAddr, pQGeoCode](){
cout << "Reply: " << pQGeoCode->errorString().toStdString() << endl;
switch (pQGeoCode->error()) {
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: cerr << #ERROR << endl; break
CASE(NoError);
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: cerr << "Undocumented error!" << endl;
}
if (pQGeoCode->error() != QGeoCodeReply::NoError) return;
// eval. result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
cout << qGeoLocs.size() << " location(s) returned." << endl;
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(qGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
cout
<< "Lat.: " << qGeoCoord.latitude() << endl
<< "Long.: " << qGeoCoord.longitude() << endl
<< "Alt.: " << qGeoCoord.altitude() << endl;
}
});
So I just removed the QApplication part because I dont have this reference in a function. As a result i get:
Qt Version: 5.10.0
Try service: osm
Searching...
but no coordinates. I assume the connection to where the lat and lon data is acquired fails. But as I mentioned I dont understand the connect here.
Any help is appreciated
EDIT
so I tried to build a connect to catch the finished Signal as suggested.
The code now looks like this:
QGeoServiceProvider qGeoService("osm");
QGeoCodingManager *pQGeoCoder = qGeoService.geocodingManager();
if (!pQGeoCoder) {
cerr
<< "GeoCodingManager '" << "osm"
<< "' not available!" << endl;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
// build address
//QGeoAddress qGeoAddr;
qGeoAddr.setCountry(QString::fromUtf8("Germany"));
qGeoAddr.setPostalCode(QString::fromUtf8("88250"));
qGeoAddr.setCity(QString::fromUtf8("Weingarten"));
qGeoAddr.setStreet(QString::fromUtf8("Heinrich-Hertz-Str. 6"));
this->pQGeoCode = pQGeoCoder->geocode(qGeoAddr);
if (!pQGeoCode) {
cerr << "GeoCoding totally failed!" << endl;
}
cout << "Searching..." << endl;
connect(pQGeoCode,SIGNAL(finished()),this,SLOT(getlonlat()));
With the Slot:
void MainWindow::getlonlat()
{
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
cout << qGeoLocs.size() << " location(s) returned." << endl;
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(qGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
cout
<< "Lat.: " << qGeoCoord.latitude() << endl
<< "Long.: " << qGeoCoord.longitude() << endl
<< "Alt.: " << qGeoCoord.altitude() << endl;
}
}
However the finished signal doesn't get triggered. Therefore the result is the same.
EDIT
Implementing the Code from your Gui Answer:
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QGeoServiceProvider *pQGeoProvider = nullptr;
ui->setupUi(this);
qDebug() << "Qt Version:" << QT_VERSION_STR;
// main application
//QApplication app(argc, argv);
// install signal handlers
QObject::connect(this->ui->qBtnInit, &QPushButton::clicked,
[&]() {
if (pQGeoProvider) delete pQGeoProvider;
std::ostringstream out;
pQGeoProvider = init(out);
log(out.str());
});
QObject::connect(this->ui->qBtnFind, &QPushButton::clicked,
[&]() {
// init geo coder if not yet done
if (!pQGeoProvider) {
std::ostringstream out;
pQGeoProvider = init(out);
log(out.str());
if (!pQGeoProvider) return; // failed
}
// fill in request
QGeoAddress *pQGeoAddr = new QGeoAddress;
pQGeoAddr->setCountry(this->ui->qTxtCountry->text());
pQGeoAddr->setPostalCode(this->ui->qTxtZipCode->text());
pQGeoAddr->setCity(this->ui->qTxtCity->text());
pQGeoAddr->setStreet(this->ui->qTxtStreet->text());
QGeoCodeReply *pQGeoCode
= pQGeoProvider->geocodingManager()->geocode(*pQGeoAddr);
if (!pQGeoCode) {
delete pQGeoAddr;
log("GeoCoding totally failed!\n");
return;
}
{ std::ostringstream out;
out << "Sending request for:\n"
<< pQGeoAddr->country().toUtf8().data() << "; "
<< pQGeoAddr->postalCode().toUtf8().data() << "; "
<< pQGeoAddr->city().toUtf8().data() << "; "
<< pQGeoAddr->street().toUtf8().data() << "...\n";
log(out.str());
}
// install signal handler to process result later
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
[&,pQGeoAddr, pQGeoCode]() {
// process reply
std::ostringstream out;
out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
switch (pQGeoCode->error()) {
case QGeoCodeReply::NoError: {
// eval result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
out << qGeoLocs.size() << " location(s) returned.\n";
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(*pQGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
out
<< "Lat.: " << qGeoCoord.latitude() << '\n'
<< "Long.: " << qGeoCoord.longitude() << '\n'
<< "Alt.: " << qGeoCoord.altitude() << '\n';
}
} break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: out << "Undocumented error!\n";
}
// log result
log(out.str());
// clean-up
delete pQGeoAddr;
/* delete sender in signal handler could be lethal
* Hence, delete it later...
*/
pQGeoCode->deleteLater();
});
});
// fill in a sample request with a known address initially
this->ui->qTxtCountry->setText(QString::fromUtf8("Germany"));
this->ui->qTxtZipCode->setText(QString::fromUtf8("88250"));
this->ui->qTxtCity->setText(QString::fromUtf8("Weingarten"));
this->ui->qTxtStreet->setText(QString::fromUtf8("Danziger Str. 3"));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::log(const QString &qString)
{
this->ui->qTxtLog->setPlainText(this->ui->qTxtLog->toPlainText() + qString);
this->ui->qTxtLog->moveCursor(QTextCursor::End);
}
void MainWindow::log(const char *text)
{
log(QString::fromUtf8(text));
}
void MainWindow::log(const std::string &text)
{
log(text.c_str());
}
QGeoServiceProvider* MainWindow::init(std::ostream &out)
{
// check for available services
QStringList qGeoSrvList
= QGeoServiceProvider::availableServiceProviders();
for (QString entry : qGeoSrvList) {
out << "Try service: " << entry.toStdString() << '\n';
// choose provider
QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
if (!pQGeoProvider) {
out
<< "ERROR: GeoServiceProvider '" << entry.toStdString()
<< "' not available!\n";
continue;
}
QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
if (!pQGeoCoder) {
out
<< "ERROR: GeoCodingManager '" << entry.toStdString()
<< "' not available!\n";
delete pQGeoProvider;
continue;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
out << "Using service " << entry.toStdString() << '\n';
return pQGeoProvider; // success
}
out << "ERROR: No suitable GeoServiceProvider found!\n";
return nullptr; // all attempts failed
}
The main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
And here the Header File for the MainWindow:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
void log(const QString &qString);
void log(const char *text);
void log(const std::string &text);
QGeoServiceProvider* init(std::ostream &out);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
I transformed my older sample to a minimal application with GUI:
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QtWidgets>
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
void log(QTextEdit &qTxtLog, const QString &qString)
{
qTxtLog.setPlainText(qTxtLog.toPlainText() + qString);
qTxtLog.moveCursor(QTextCursor::End);
}
void log(QTextEdit &qTxtLog, const char *text)
{
log(qTxtLog, QString::fromUtf8(text));
}
void log(QTextEdit &qTxtLog, const std::string &text)
{
log(qTxtLog, text.c_str());
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
QWidget qWin;
QVBoxLayout qBox;
QFormLayout qForm;
QLabel qLblCountry(QString::fromUtf8("Country:"));
QLineEdit qTxtCountry;
qForm.addRow(&qLblCountry, &qTxtCountry);
QLabel qLblZipCode(QString::fromUtf8("Postal Code:"));
QLineEdit qTxtZipCode;
qForm.addRow(&qLblZipCode, &qTxtZipCode);
QLabel qLblCity(QString::fromUtf8("City:"));
QLineEdit qTxtCity;
qForm.addRow(&qLblCity, &qTxtCity);
QLabel qLblStreet(QString::fromUtf8("Street:"));
QLineEdit qTxtStreet;
qForm.addRow(&qLblStreet, &qTxtStreet);
QLabel qLblProvider(QString::fromUtf8("Provider:"));
QComboBox qLstProviders;
qForm.addRow(&qLblProvider, &qLstProviders);
qBox.addLayout(&qForm);
QPushButton qBtnFind(QString::fromUtf8("Find Coordinates"));
qBox.addWidget(&qBtnFind);
QLabel qLblLog(QString::fromUtf8("Log:"));
qBox.addWidget(&qLblLog);
QTextEdit qTxtLog;
qTxtLog.setReadOnly(true);
qBox.addWidget(&qTxtLog);
qWin.setLayout(&qBox);
qWin.show();
// initialize Geo Service Providers
std::vector<QGeoServiceProvider*> pQGeoProviders;
{ std::ostringstream out;
QStringList qGeoSrvList
= QGeoServiceProvider::availableServiceProviders();
for (QString entry : qGeoSrvList) {
out << "Try service: " << entry.toStdString() << '\n';
// choose provider
QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
if (!pQGeoProvider) {
out
<< "ERROR: GeoServiceProvider '" << entry.toStdString()
<< "' not available!\n";
continue;
}
QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
if (!pQGeoCoder) {
out
<< "ERROR: GeoCodingManager '" << entry.toStdString()
<< "' not available!\n";
delete pQGeoProvider;
continue;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
qLstProviders.addItem(entry);
pQGeoProviders.push_back(pQGeoProvider);
out << "Service " << entry.toStdString() << " available.\n";
}
log(qTxtLog, out.str());
}
if (pQGeoProviders.empty()) qBtnFind.setEnabled(false);
// install signal handlers
QObject::connect(&qBtnFind, QPushButton::clicked,
[&]() {
// get current geo service provider
QGeoServiceProvider *pQGeoProvider
= pQGeoProviders[qLstProviders.currentIndex()];
// fill in request
QGeoAddress *pQGeoAddr = new QGeoAddress;
pQGeoAddr->setCountry(qTxtCountry.text());
pQGeoAddr->setPostalCode(qTxtZipCode.text());
pQGeoAddr->setCity(qTxtCity.text());
pQGeoAddr->setStreet(qTxtStreet.text());
QGeoCodeReply *pQGeoCode
= pQGeoProvider->geocodingManager()->geocode(*pQGeoAddr);
if (!pQGeoCode) {
delete pQGeoAddr;
log(qTxtLog, "GeoCoding totally failed!\n");
return;
}
{ std::ostringstream out;
out << "Sending request for:\n"
<< pQGeoAddr->country().toUtf8().data() << "; "
<< pQGeoAddr->postalCode().toUtf8().data() << "; "
<< pQGeoAddr->city().toUtf8().data() << "; "
<< pQGeoAddr->street().toUtf8().data() << "...\n";
log(qTxtLog, out.str());
}
// install signal handler to process result later
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
[&qTxtLog, pQGeoAddr, pQGeoCode]() {
// process reply
std::ostringstream out;
out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
switch (pQGeoCode->error()) {
case QGeoCodeReply::NoError: {
// eval result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
out << qGeoLocs.size() << " location(s) returned.\n";
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(*pQGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
out
<< "Lat.: " << qGeoCoord.latitude() << '\n'
<< "Long.: " << qGeoCoord.longitude() << '\n'
<< "Alt.: " << qGeoCoord.altitude() << '\n';
}
} break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: out << "Undocumented error!\n";
}
// log result
log(qTxtLog, out.str());
// clean-up
delete pQGeoAddr;
/* delete sender in signal handler could be lethal
* Hence, delete it later...
*/
pQGeoCode->deleteLater();
});
});
// fill in a sample request with a known address initially
qTxtCountry.setText(QString::fromUtf8("Germany"));
qTxtZipCode.setText(QString::fromUtf8("88250"));
qTxtCity.setText(QString::fromUtf8("Weingarten"));
qTxtStreet.setText(QString::fromUtf8("Danziger Str. 3"));
// runtime loop
app.exec();
// done
return 0;
}
Compiled and tested in cygwin on Windows 10 (64 bit):
$ g++ --version
g++ (GCC) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ qmake-qt5 testQGeoAddressGUI.pro
$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_LOCATION_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_POSITIONING_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtLocation -isystem /usr/include/qt5/QtQuick -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtPositioning -isystem /usr/include/qt5/QtQml -isystem /usr/include/qt5/QtNetwork -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQGeoAddressGUI.o testQGeoAddressGUI.cc
g++ -o testQGeoAddressGUI.exe testQGeoAddressGUI.o -lQt5Widgets -lQt5Location -lQt5Quick -lQt5Gui -lQt5Positioning -lQt5Qml -lQt5Network -lQt5Core -lGL -lpthread
$ ./testQGeoAddressGUI
Qt Version: 5.9.2
Notes:
When I wrote this sample I was very carefully about scope and life-time of involved variables. (Actually, I changed some local variables to pointers and instances created with new to achieve this.) This is my hint for any reader.
In my 1st test, the application ended up in CommunicationError. I'm quite sure that our company's security policy is responsible for this. (I did the same with my older sample which I tested successfully at home – with the same result.)
A 2nd test (at home) went better. First, I tried to find the address with service provider osm which brought 0 results. Changing the service provider to esri returned one result.
I copied the output to maps.google.de:
This is actually the correct result – as I tested the (new) address of the company EKS InTec where I'm working.
The usage of lambdas in the above sample makes it a bit hard to read. Therefore, I re-visited the sample. Now, all relevant stuff has moved to a class MainWindow (hopefully, closer to the requirement of OP). The lambdas were replaced by simple methods.
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QtWidgets>
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
// main window class
class MainWindow: public QWidget {
// variables:
private:
// list of service providers
std::vector<QGeoServiceProvider*> pQGeoProviders;
// Qt widgets (contents of main window)
QVBoxLayout qBox;
QFormLayout qForm;
QLabel qLblCountry;
QLineEdit qTxtCountry;
QLabel qLblZipCode;
QLineEdit qTxtZipCode;
QLabel qLblCity;
QLineEdit qTxtCity;
QLabel qLblStreet;
QLineEdit qTxtStreet;
QLabel qLblProvider;
QComboBox qLstProviders;
QPushButton qBtnFind;
QLabel qLblLog;
QTextEdit qTxtLog;
// methods:
public: // ctor/dtor
MainWindow(QWidget *pQParent = nullptr);
virtual ~MainWindow();
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
private: // internal stuff
void init(); // initializes geo service providers
void find(); // sends request
void report(); // processes reply
void log(const QString &qString)
{
qTxtLog.setPlainText(qTxtLog.toPlainText() + qString);
qTxtLog.moveCursor(QTextCursor::End);
}
void log(const char *text) { log(QString::fromUtf8(text)); }
void log(const std::string &text) { log(text.c_str()); }
};
MainWindow::MainWindow(QWidget *pQParent):
QWidget(pQParent),
qLblCountry(QString::fromUtf8("Country:")),
qLblZipCode(QString::fromUtf8("Postal Code:")),
qLblCity(QString::fromUtf8("City:")),
qLblStreet(QString::fromUtf8("Street:")),
qLblProvider(QString::fromUtf8("Provider:")),
qBtnFind(QString::fromUtf8("Find Coordinates")),
qLblLog(QString::fromUtf8("Log:"))
{
// setup child widgets
qForm.addRow(&qLblCountry, &qTxtCountry);
qForm.addRow(&qLblZipCode, &qTxtZipCode);
qForm.addRow(&qLblCity, &qTxtCity);
qForm.addRow(&qLblStreet, &qTxtStreet);
qForm.addRow(&qLblProvider, &qLstProviders);
qBox.addLayout(&qForm);
qBox.addWidget(&qBtnFind);
qBox.addWidget(&qLblLog);
qBox.addWidget(&qTxtLog);
setLayout(&qBox);
// init service provider list
init();
// install signal handlers
QObject::connect(&qBtnFind, &QPushButton::clicked,
this, &MainWindow::find);
// fill in a sample request with a known address initially
qTxtCountry.setText(QString::fromUtf8("Germany"));
qTxtZipCode.setText(QString::fromUtf8("88250"));
qTxtCity.setText(QString::fromUtf8("Weingarten"));
qTxtStreet.setText(QString::fromUtf8("Danziger Str. 3"));
}
MainWindow::~MainWindow()
{
// clean-up
for (QGeoServiceProvider *pQGeoProvider : pQGeoProviders) {
delete pQGeoProvider;
}
}
void MainWindow::init()
{
// initialize Geo Service Providers
{ std::ostringstream out;
QStringList qGeoSrvList
= QGeoServiceProvider::availableServiceProviders();
for (QString entry : qGeoSrvList) {
out << "Try service: " << entry.toStdString() << '\n';
// choose provider
QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
if (!pQGeoProvider) {
out
<< "ERROR: GeoServiceProvider '" << entry.toStdString()
<< "' not available!\n";
continue;
}
QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
if (!pQGeoCoder) {
out
<< "ERROR: GeoCodingManager '" << entry.toStdString()
<< "' not available!\n";
delete pQGeoProvider;
continue;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
qLstProviders.addItem(entry);
pQGeoProviders.push_back(pQGeoProvider);
out << "Service " << entry.toStdString() << " available.\n";
}
log(out.str());
}
if (pQGeoProviders.empty()) qBtnFind.setEnabled(false);
}
std::string format(const QGeoAddress &qGeoAddr)
{
std::ostringstream out;
out
<< qGeoAddr.country().toUtf8().data() << "; "
<< qGeoAddr.postalCode().toUtf8().data() << "; "
<< qGeoAddr.city().toUtf8().data() << "; "
<< qGeoAddr.street().toUtf8().data();
return out.str();
}
void MainWindow::find()
{
// get current geo service provider
QGeoServiceProvider *pQGeoProvider
= pQGeoProviders[qLstProviders.currentIndex()];
// fill in request
QGeoAddress qGeoAddr;
qGeoAddr.setCountry(qTxtCountry.text());
qGeoAddr.setPostalCode(qTxtZipCode.text());
qGeoAddr.setCity(qTxtCity.text());
qGeoAddr.setStreet(qTxtStreet.text());
QGeoCodeReply *pQGeoCode
= pQGeoProvider->geocodingManager()->geocode(qGeoAddr);
if (!pQGeoCode) {
log("GeoCoding totally failed!\n");
return;
}
{ std::ostringstream out;
out << "Sending request for:\n"
<< format(qGeoAddr) << "...\n";
log(out.str());
}
// install signal handler to process result later
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
this, &MainWindow::report);
/* This signal handler will delete it's own sender.
* Hence, the connection need not to be remembered
* although it has only a limited life-time.
*/
}
void MainWindow::report()
{
QGeoCodeReply *pQGeoCode
= dynamic_cast<QGeoCodeReply*>(sender());
// process reply
std::ostringstream out;
out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
switch (pQGeoCode->error()) {
case QGeoCodeReply::NoError: {
// eval result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
out << qGeoLocs.size() << " location(s) returned.\n";
for (QGeoLocation &qGeoLoc : qGeoLocs) {
QGeoAddress qGeoAddr = qGeoLoc.address();
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
out
<< "Coordinates for "
<< qGeoAddr.text().toUtf8().data() << ":\n"
<< "Lat.: " << qGeoCoord.latitude() << '\n'
<< "Long.: " << qGeoCoord.longitude() << '\n'
<< "Alt.: " << qGeoCoord.altitude() << '\n';
}
} break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: out << "Undocumented error!\n";
}
// log result
log(out.str());
// clean-up
/* delete sender in signal handler could be lethal
* Hence, delete it later...
*/
pQGeoCode->deleteLater();
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
MainWindow win;
win.show();
// runtime loop
app.exec();
// done
return 0;
}
Note:
The look and behavior is the same like for the above example. I changed the output of reply a bit.
While preparing this sample, I realized that it is actually not necessary to set the address of the returned QGeoLocation as it is already there. IMHO, it is interesting that the returned address looks a bit different than the requested. It seems that it is returned in a (I would say) normalized form.

Program not working right on other windows machines

I'm having a problem with my application, in which I'm trying to get all network configurations of the system that it runs on. The final goal is to find the MAC address with highest priority.
The code runs ok and works when I run it with QtCreator and also runs ok when I create a folder containing the dll files and the exe file.
But the problem is that when I run this program on other windows machines (7 and 10) it runs but does not return or show anything. I tried running it as an Administrator, that didn't work neither and this code should be able to work on all windows platforms.
Any suggestions?
I'm currently on Windows 10 and using Qt 5.8 MSVC 2015
The exe file runs with these dlls on Windows 10:
Qt5Core.dll
Qt5Network.dll
msvcp140.dll
msvcr120.dll
vcruntime140.dll
These dlls should be also there for windows 7:
api-ms-win-core-file-l1-2-0.dll
api-ms-win-core-file-l2-1-0.dll
api-ms-win-core-localization-l1-2-0.dll
api-ms-win-core-processthreads-l1-1-1.dll
api-ms-win-core-string-l1-1-0.dll
api-ms-win-core-synch-l1-2-0.dll
api-ms-win-core-timezone-l1-1-0.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll
api-ms-win-crt-filesystem-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-multibyte-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-time-l1-1-0.dll
api-ms-win-crt-utility-l1-1-0.dll
Link below is the exe and dll files together:
https://ufile.io/e9htu
here's my code if needed:
main.cpp
#include <QCoreApplication>
#include "macfinder.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MACFinder macFinder;
macFinder.findMAC();
return a.exec();
}
macfinder.h
#ifndef MACFINDER_H
#define MACFINDER_H
#include <QObject>
#include <QNetworkConfiguration>
#include <QNetworkConfigurationManager>
#include <QNetworkInterface>
#include <QNetworkSession>
#include <QDebug>
class MACFinder : public QObject
{
Q_OBJECT
public:
explicit MACFinder(QObject *parent = 0);
void findMAC();
private:
QNetworkConfigurationManager ncm;
QString filterMAC(QList<QNetworkConfiguration> configs);
signals:
void foundMAC(QString MAC);
private slots:
void configurationsUpdateCompleted();
};
#endif // MACFINDER_H
macfinder.cpp
#include "macfinder.h"
MACFinder::MACFinder(QObject *parent) : QObject(parent)
{
}
QString MACFinder::filterMAC(QList<QNetworkConfiguration> configs)
{
qDebug() << "MAC and Index: ";
QString MAC;
int index;
QNetworkConfiguration nc;
foreach(nc,configs)
{
QNetworkSession networkSession(nc);
QNetworkInterface netInterface = networkSession.interface();
QString debugStr = QString::number(netInterface.index())
+ " | " + netInterface.humanReadableName() + " | "
+ nc.name() + " | " + netInterface.hardwareAddress();
if(netInterface.hardwareAddress().isEmpty())
{
qDebug() << "--> No MAC: " << debugStr;
continue;
}
if(netInterface.name().isEmpty())
{
qDebug() << "--> NO NAME: " << debugStr;
continue;
}
if(netInterface.index() == 0)
{
qDebug() << "--> NO INDEX: " << debugStr;
continue;
}
if(netInterface.flags() & QNetworkInterface::IsLoopBack)
{
qDebug() << "--> loopBack: " << debugStr;
continue;
}
if(netInterface.flags() & (QNetworkInterface::IsRunning | QNetworkInterface::IsUp))
{
qDebug() << "*** Accepted: " << debugStr;
if(MAC.isEmpty())
{
qDebug() << "setting MAC:" << debugStr;
MAC = netInterface.hardwareAddress();
index = netInterface.index();
}
else
{
if(netInterface.index() < index)
{
qDebug() << "setting MAC:" << debugStr;
MAC = netInterface.hardwareAddress();
index = netInterface.index();
}
else
qDebug() << "index is not lower: " << debugStr;
}
}
}
return MAC;
}
void MACFinder::findMAC()
{
qDebug() << "MACFinder::findMAC | updating all configurations";
connect(&ncm,SIGNAL(updateCompleted()),this,SLOT(configurationsUpdateCompleted()));
ncm.updateConfigurations();
}
void MACFinder::configurationsUpdateCompleted()
{
qDebug() << "MACFinder::configurationsUpdateCompleted";
disconnect(&ncm,SIGNAL(updateCompleted()),this,SLOT(configurationsUpdateCompleted()));
QNetworkConfiguration nc;
QList<QNetworkConfiguration> configs = ncm.allConfigurations(QNetworkConfiguration::Active);
qDebug() << "\nAllConfigs: ";
foreach (nc,configs)
{
qDebug() << nc.identifier() << nc.name() << nc.state();
}
QString MAC = filterMAC(configs);
qDebug() << "\nMAC:" << MAC;
if(MAC.isEmpty())
{
qDebug("no MAC address found");
}
emit foundMAC(MAC);
}
I downloaded your app and analyze it on my computer.
problem is you missing some dlls, your app running without error but not working properly. (qgenericbearer.dll , qnativewifibearer.dll with folder bearer are missing ).
you can use windeploy command to deploy your project.
go to Qt, compiler directory on your OS for example:
C:\Qt\Qt5.7.0\5.7\msvc2013\bin
press Shift+right click mouse then click open command window here
type windeployqt.exe c:\Your app directory for example:
windeployqt.exe C:\Users\Mofrad\Downloads\macfindertest\macFinderTest\macAddressTest.exe
now some dlls will copy to your app directory.
Now try your app again and you'll see it's working.

Interact with QProcess - reading and writing to QProcess results in no output

noted: this is a use-specific question, but I hope others can benefit from this too
To get a basic sense of what I want to do:
QProcess runs a command by:
QProcess::start("sh -c \"cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?\" ")
The script expects input from the user (a password), QProcess::readAll() confirms the script's input request. The input is given by QProcess::write().
Here I get lost! -> No output is received. from readAll() and readAllStandardOutput(), both are empty.
I need the output: particularly the echo $? for later processing, but don't get anything since readAll() and readAllStandardOutput() returns empty strings
To me there are several possible issues to cause this, maybe more than one:
The script does not receive this input
The script receives the input, but expects a "return key press"
The script receives the input, QProcess::write automatically does a "return key press", the script continues and finishes but QProcess does not read this output
The Code:
// please ignore the messiness of the code, a placed a number of debugs just to see the code response.
cmd = "cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?" (without quotes)
input => required input for script
QString gen_serv::runCommand(QString cmd, QString input){
Process *p = new QProcess(parent);
p->setProcessChannelMode(QProcess::MergedChannels);
// p->start("sh ", QStringList() << " -c " << cmd);
QString c = QString("sh -c \"" + cmd + "\" ");
p->start(c); <---- ACTUAL COMMAND : sh -c "cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?"
if (p->waitForStarted()) {
if (!p->waitForReadyRead()) {
qDebug(log_lib_gen_serv) << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished(1000)) {
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
//p->write(input.toLatin1());
p->write(QString(input + QString("\n")).toLatin1()); <--- added this "\n" incase the process/console was waiting for a return press, thus the /n should satisfy the return requirement
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
if (!p->waitForFinished()) {
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
qDebug(log_lib_gen_serv) << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
}
QString s = QString(p->readAll() + p->readAllStandardOutput());
return s;
}
else{
qDebug(log_lib_gen_serv) << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
p->waitForFinished();
p->kill();
return QString();
}
Please note:
The script is long and complicated, however it returns a message "done" if successfully executed and an exit code for each case.
Thus the echo $? should capture and return this for processing i.e. return s
I hope this makes sense, any suggestions how I can attempt to solve this issue?

Display a custom help message in TCLAP

I'm using the TCLAP library to do some command line argument parsing. It's pretty great: except for the help messages it prints. Those are kind of ugly.
For instance, this is the output:
USAGE:
./a.out [-r] -n <string> [--] [--version] [-h]
Where:
-r, --reverse
Print name backwards
-n <string>, --name <string>
(required) Name to print
--, --ignore_rest
Ignores the rest of the labeled arguments following this flag.
--version
Displays version information and exits.
-h, --help
Displays usage information and exits.
Command description message
of this program:
#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>
int main(int argc, char** argv){
try {
TCLAP::CmdLine cmd("Command description message", ' ', "0.9");
TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");
cmd.add( nameArg );
TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);
cmd.parse( argc, argv );
std::string name = nameArg.getValue();
bool reverseName = reverseSwitch.getValue();
if ( reverseName ){
std::reverse(name.begin(),name.end());
std::cout << "My name (spelled backwards) is: " << name << std::endl;
} else{
std::cout << "My name is: " << name << std::endl;
}
} catch (TCLAP::ArgException &e) {
std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
}
}
when run with ./a.out -h.
I want more creative control: I want to make my very own help message!
How can I achieve that?
The TCLAP::CmdLineOutput class is the one responsible for printing help (or usage) messages.
If you want TCLAP to print a custom message, you must first derive from the class mentioned above and add its instance to your TCLAP::CmdLine object like:
cmd.setOutput(new CustomHelpOutput());
Here is an example of a custom TCLAP::CmdLineOutput:
class CustomHelpOutput : public TCLAP::StdOutput {
public:
virtual void usage(TCLAP::CmdLineInterface& _cmd) override {
std::cout << "My program is called " << _cmd.getProgramName() << std::endl;
}
};
Note that you are the one responsible for cleaning up after your custom object, because TCLAP has a flag that disables its deletion in the setter.
inline void CmdLine::setOutput(CmdLineOutput* co)
{
if ( !_userSetOutput )
delete _output;
_userSetOutput = true;
_output = co;
}