Passing/giving commands to CMD through Qt GUI - c++

What I'm trying to achieve (And struggling with) is basically passing commands to CMD through my QT Mainwindow application.
I would like to have my code, first run CMD (preferably hidden). I used here QProcess like this:
(in my Mainwindow.cpp file)
QString exePath = "C:/Windows/System32/cmd.exe";
QProcess pro;
pro.startDetached(exePath);
pro.waitForStarted();
this question helped me a lot
However, what this answer/question lacks is actual help on "appending" commands to CMD (not sure if this is a correct term, please correct me if I'm wrong!)
I have tried the following with this piece of code
(also in my Mainwindow.cpp file)
string exepathstring = "C:/Windows/System32/cmd.exe"; //because fstream doesnt accept argument of type QString
QProcess pro;
pro.startDetached(exePath); //do I have to use "detached" here?
pro.waitForFinished(); //not sure if i should use "for
//finished" or "for started" or something else
string connecttoserver = ui->lineEdit_command->text().toStdString(); //this is where people input a cmd command
//need to convert it to to be able to append it
fstream myoutfile(exepathstring, ios::in | ios::out | ios::app);
myoutfile <<""<< connecttoserver << endl;
Hoping that I can use a normal "append to file" code but it does nothing, I don't even get an error :(
could someone tell me where i'm going wrong?
and how can I go about achieving what I want?
which is
starting cmd (preferably in hidden) upon launch of my "mainwindow app"
take user input and let my app pass it to cmd upon my button click.
Here's my entire mainwindow.cpp source file
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QString>
#include <fstream>
#include <iostream>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{ui->setupUi(this);}
MainWindow::~MainWindow()
{delete ui;}
void MainWindow::on_pushButton_clicked()
{
QString exePath = "C:/Windows/System32/cmd.exe";
string exepathstring = "C:/Windows/System32/cmd.exe"; //because fstream doesnt accept argument of type QString
QProcess pro;
pro.startDetached(exePath);
pro.waitForFinished(); //not sure if i should use "for finished" or "for started" or something else
string connecttoserver = ui->lineEdit_command->text().toStdString(); /*this is where people input a cmd command
need to convert it to to be able to append it*/
fstream myoutfile(exepathstring, ios::in | ios::out | ios::app);
myoutfile <<""<< connecttoserver << endl;
}
Any input would really help me a lot ^.^ also I'm really sorry if I had used wrong terminology

If you looked at this post, one apparent problem is that you are using the static method startDetached() with the blocking function waitForFinished() ... QProcess::waitForStarted()/waitForFinished() won't catch signals from detached QProcess;
Thus you could use:
QProcess pro;
pro.start(exePath);
pro.waitForStarted(); // the correct is `waitForStarted()`
What your trying to do with fstream is not clear - to me - while in your description, you want user to send a command to your process:
then this could, for instance, be :
QByteArray user_cmd = QVariant(ui->lineEdit_command->text()).toByteArray();
pro.write(user_cmd);
pro.write("\n\r"); // press Enter to execute the command
Thus your code could be:
.h
#include <QProcess>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void readResult();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QProcess* pro;
};
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::on_pushButton_clicked);
QString exePath = "C:/Windows/System32";
pro = new QProcess(parent);
pro->setWorkingDirectory(exePath);
pro->setReadChannel(QProcess::StandardOutput);
connect(pro,&QProcess::readyReadStandardOutput, this, &MainWindow::readResult);
pro->start("cmd.exe");
if (!pro->waitForStarted())
{
qDebug() << "The process didnt start" << pro->error();
}
}
void MainWindow::on_pushButton_clicked()
{
if (ui->lineEdit_command->text().isEmpty())
return;
QByteArray cmd = QVariant(ui->lineEdit_command->text()).toByteArray();
pro->write(cmd);
pro->write("\n\r");
ui->lineEdit_command->clear();
}
void MainWindow::readResult()
{
while(pro->bytesAvailable()){
QString dirout = pro->readLine();
qDebug() << dirout;
}
}
MainWindow::~MainWindow()
{
delete ui;
}

Related

How can i make a two message events for json Data by pushButton click in Qt?

How can I make a message?
I want make 2 message events. First, if is nothing include in my lineEdits and push the button. Must come error message "You have not includet the data". And second, if i include my lineEdits and push the button. Must come message "You have includet the data." But it's not work for me. If i push the button, then program saved empty json. If i push write data in lineEdits and push the button, then program saved as normal json. But no matter how I write, the programs always overwrite old json file. And I always get the logging that I have stored data.
Here is my code:
My .Cpp file:
#include "address_dialog.h"
#include "ui_address_dialog.h"
Address_Dialog::Address_Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Address_Dialog)
{
ui->setupUi(this);
connect(ui->pb_Cancel,SIGNAL(clicked(bool)),this,SLOT(close()));
//Save data in json on click
connect(ui->pb_save,SIGNAL(clicked(bool)),
this,SLOT(on_pb_save_clicked()));
}
Address_Dialog::~Address_Dialog()
{
delete ui;
}
void Address_Dialog::SaveDat()
{
m_address.mVorname= ui->le_Vorname->text();
m_address.mNachname= ui->le_Nachname->text();
m_address.mLand= ui->le_Land->text();
m_address.mName= ui->le_Name->text();
m_address.mPassword= ui->le_Password->text();
QJsonObject json_obj;
json_obj["FirstName"]= m_address.mVorname;
json_obj["MiddleName"]= m_address.mNachname;
json_obj["Country"]= m_address.mLand;
json_obj["NickName"]= m_address.mName;
json_obj["Password"]= m_address.mPassword;
//Open the file for Recording using the path specified
QString file_path = "C:/Users/frs/Documents/test_obj.json";
QFile save_file(file_path);
save_file.open(QIODevice::WriteOnly);
//if(!save_file.open(QIODevice::WriteOnly))
//QMessageBox::warning(0,"Error","Cannot open the file");
QJsonDocument json_doc(json_obj);
QString json_string = json_doc.toJson();
if(save_file.write(json_string.toLocal8Bit()))
QMessageBox::information(0,"Saving....",
"The item has been successfully added");
else
QMessageBox::critical(0,"Error","The item cannot be added");
save_file.close();
}
void Address_Dialog::on_pb_save_clicked()
{
SaveDat();
}
That is my .H file
#ifndef ADDRESS_DIALOG_H
#define ADDRESS_DIALOG_H
#include <QDialog>
#include <QMessageBox>
#include "address.h"
#include <QFile>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QString>
#include <QDir>
namespace Ui
{
class Address_Dialog;
}
class Address_Dialog : public QDialog
{
Q_OBJECT
public:
explicit Address_Dialog(QWidget *parent = 0);
~Address_Dialog();
Address m_address;//Creation of the Class object <=> /*QString mVorname,
// mNachname, mLand, mName, mPassword;*/
private slots:
void on_pb_save_clicked();
void SaveDat();
private:
Ui::Address_Dialog *ui;
};
#endif // ADDRESS_DIALOG_H
I found a solution. That was easy. I thanks all for response.
Here is my code:
if(ui->le_Vorname->text().isEmpty() || ui->le_Nachname->text().isEmpty() ||
ui->le_Land->text().isEmpty() || ui->le_Name->text().isEmpty() ||
ui->le_Password->text().isEmpty())
{
ui->pb_save->setEnabled(false);
QMessageBox::critical(0,"Error","The item cannot be added");
}else
{
ui->pb_save->setEnabled(true);
save_file.write(json_string.toLocal8Bit());
QMessageBox::information(0,"Saving....", "The item has been successfully added");
}
save_file.close();

How to read data using QSerialPort to write to a file using QFile?

New to C++ and Qt, I'm trying to use a microcontroller to send a large set of data (made up of integers and commas) over serial to be put in a .csv file for use in Excel. My mainwindow.cpp code so far (where I've put all the action for testing purposes):
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string>
#include <QtSerialPort/QSerialPort>
#include <QString>
#include <QTextEdit>
#include <QFile>
#include <QTextStream>
QSerialPort *serial;
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
serial = new QSerialPort(this);
serial->setPortName("/dev/cu.usbmodemfa131");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadWrite);
connect(serial, SIGNAL(readyRead()), this, SLOT(serialReceived()));
}
MainWindow::~MainWindow()
{
delete ui;
serial->close();
}
void MainWindow::serialReceived()
{
QString filename = "/Users/me/Documents/myFile/datacollecting.csv";
QFile file(filename);
QTextStream out(&file);
file.open(QIODevice::ReadWrite);
QByteArray ba;
ba = serial->readAll();
out << ba;
file.close();
}
The code however is giving me some issues. It does not work reliably at all and in the resultant file it only stores the last 10 or so (out of several thousand) characters. I have searched around but have not found a way to properly store large chunks of data over serial. Is there a better way to achieve what I'm trying to do above? New to this so any help would be greatly appreciated!
As already written in comments you should open your output file in append mode by adding QIODevice::Append flag so that all data is written to the end of the file.
You can also connect to error signal where you can inspect possible errors. See serial port enums here.
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
void MainWindow::handleError(QSerialPort::SerialPortError error)
{
...
}

How do i play a stream with QMediaPlayer

I have set up a server and video streaming so that I can connect to the stream with ffplay using the following command line:
ffplay rtmp://<IP>/path
Is it possible to use QMediaPlayer QMediaContent or something to connect to this stream?
Or maybe any other kind of stream I can create with ffserver.
using the same path as with ffplay results in "Unsupported url scheme!"
With further experiments i have tried ffserver http server streaming, but that ended with Qt crashing in MFStreamer::doRead()
Apparently it should have called BeginRead for MFStreamer but it didn't.
How do i play video streams with QMediaPlayer?
Edit: here's my code
videotest.cpp
#include "videotest.h"
#include <QVBoxLayout>
#include <QVideoWidget>
#include <qmediaplayer.h>
#include <QMediaContent>
#include <QNetworkAccessManager>
#include <QNetworkReply>
struct VideoTest::Private
{
QMediaPlayer * mediaPlayer;
QNetworkAccessManager * networkAccessManager;
QNetworkReply * reply;
};
VideoTest::VideoTest(QWidget *parent)
: QMainWindow(parent)
{
d = new Private;
d->mediaPlayer = new QMediaPlayer(this, QMediaPlayer::StreamPlayback);
d->networkAccessManager = new QNetworkAccessManager(this);
ui.setupUi(this);
QVideoWidget * videoWidget = new QVideoWidget(ui.centralWidget);
videoWidget->show();
QPalette palette = videoWidget->palette();
palette.setColor(QPalette::Background, QColor(0, 0, 0));
videoWidget->setPalette(palette);
ui.videoLayout->addWidget(videoWidget);
d->mediaPlayer->setVideoOutput(videoWidget);
connect(ui.playButton, SIGNAL(clicked()), d->mediaPlayer, SLOT(play()));
connect(ui.pauseButton, SIGNAL(clicked()), d->mediaPlayer, SLOT(pause()));
connect(ui.videoUrlEdit, SIGNAL(editingFinished()), this, SLOT(sourceChanged()));
connect(d->mediaPlayer, SIGNAL(error()), this, SLOT(stateChanged()));
connect(d->mediaPlayer, SIGNAL(stateChanged), this, SLOT(stateChanged()));
}
VideoTest::~VideoTest()
{
delete d;
}
void VideoTest::sourceChanged()
{
d->reply = d->networkAccessManager->get(QNetworkRequest(ui.videoUrlEdit->text()));
if(d->reply)
{
connect(d->reply, SIGNAL(readyRead()), this, SLOT(networkRequestReady()));
}
}
void VideoTest::stateChanged()
{
QString text = ui.textEdit->toPlainText();
text.append("\n").append(d->mediaPlayer->errorString()).append(" : ").append(d->mediaPlayer->mediaStatus());
ui.textEdit->setText(text);
}
void VideoTest::networkRequestReady()
{
d->mediaPlayer->setMedia(QMediaContent(), d->reply);
}
videotest.h
#ifndef VIDEOTEST_H
#define VIDEOTEST_H
#include <QtWidgets/QMainWindow>
#include "ui_videotest.h"
class VideoTest : public QMainWindow
{
Q_OBJECT
public:
VideoTest(QWidget *parent = 0);
~VideoTest();
public slots:
void sourceChanged();
void stateChanged();
void networkRequestReady();
private:
Ui::VideoTestClass ui;
struct Private;
Private * d;
};
#endif // VIDEOTEST_H
I found a way to make it work.
I gave up on Qt. The guys at Qt were insistent that it should work, but were unable to produce any configuration that works. They said that it should work if you stream from VLC, but I didn't get it to work. I also tried ffmpeg, ffserver and nginx rtmp streaming. I got these things working with mplayer, ffplay, VLC and some even with Windows Media Player, but never QMediaPlayer.
I tried to just give the URL to setMedia.
I tried to make a custom QIODevice to read the stream data and give that data to QMediaPlayer which was initialized with StreamPlayback, but it just would not succeed in reading the data.
In the end, all I needed was something to play a stream, is a QWidget and isn't GPL licensed.
I used libVLC and vlc-qt both of which work wonderfully.
Following these instructions was easy, but you need to remember to copy the header files from vlc-qt/windows/vlc_headers/2.2/ to vlc/sdk/include/vlc/plugins (sic). This is important, if you don't do this you might get errors during compilation. Note that these paths might be different if you have different versions of your platform doesn't match mine. Also, it might not be necessary when you read this.
VideoTest.h
#ifndef VIDEOTEST_H_
#define VIDEOTEST_H_
#include <QtWidgets/QMainWindow>
#include "ui_videotest.h"
class VideoTest: public QMainWindow
{
Q_OBJECT
public:
VideoTest(QWidget * p_parent = 0);
~VideoTest();
public slots:
void sourceChanged();
private:
struct Private;
Private * d;
Ui::VideoTestClass ui;
};
#endif
videotest.cpp
#include "videotest.h"
#include <vlc-qt/Common.h>
#include <vlc-qt/Instance.h>
#include <vlc-qt/Media.h>
#include <vlc-qt/MediaPlayer.h>
#include <vlc-qt/WidgetVideo.h>
struct VideoTest::Private
{
VlcInstance * vlcInstance;
VlcMediaPlayer * vlcMediaPlayer;
VlcMedia * vlcMedia;
VlcWidgetVideo * vlcVideoWidget;
};
VideoTest::VideoTest(QWidget * p_parent)
{
d = new Private();
ui.setupUi(this);
d->vlcMedia = 0;
d->vlcInstance = new VlcInstance(VlcCommon::args(), this);
d->vlcMediaPlayer = new VlcMediaPlayer(d->vlcInstance);
d->vlcVideoWidget = new VlcWidgetVideo(this);
d->vlcMediaPlayer->setVideoWidget(d->vlcVideoWidget);
d->vlcVideoWidget->setMediaPlayer(d->vlcMediaPlayer);
ui.videoLayout->addWidget(d->vlcVideoWidget);
connect(ui.playButton, SIGNAL(clicked()), d->vlcMediaPlayer, SLOT(play()));
connect(ui.pauseButton, SIGNAL(clicked()), d->vlcMediaPlayer, SLOT(pause()));
connect(ui.videoUrlEdit, SIGNAL(editingFinished()), this, SLOT(sourceChanged()));
}
VideoTest::~VideoTest()
{
delete d->vlcInstance;
delete d->vlcMediaPlayer;
delete d->vlcMedia;
delete d;
}
VideoTest::sourceChanged()
{
QUrl url(ui.videoUrlEdit->test());
if(url.isValid() == false)
{
return;
}
d->vlcMediaPlayer->stop();
delete d->vlcMedia;
d->vlcMedia = new VlcMedia(url.toString(), d->vlcInstance);
d->vlcMediaPlayer->open(d->vlcMedia);
}
VideoTest.ui
Make your own, I don't work for you :D
Just make sure that it has pauseButton, playButton, videoUrlEdit(QLineEdit) and videoLayout where the video widget will be inserted.
I've just managed to play stream in QML VideoOutput with C++ QMediaPlayer using the setMedia(QUrl("http://127.0.0.1:8080"));
The stream was created by VLC media player using the HTTP to the 8080 port. I've also succeeded in playing the stream created by VLC media player to local file by passing it to QMediaPlayer via setMedia(QMediaContent(), &localFile);.

QFile::copy static function not copying file

I want to copy a text file with QFile with this code:
void MainWindow::on_pushButton_4_clicked()
{
QFile::copy("C:/p/text.txt", "C:/p/text1.txt");
}
I get no errors when I build it, but when I run the program, nothing happens.
Here's the complete source code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QfileDialog>
#include <QFile>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
int currentIndex = 0;
void MainWindow::on_pushButton_2_clicked()
{
ui->lineEdit->setText(QFileDialog::getExistingDirectory());
}
void MainWindow::on_pushButton_clicked()
{
currentIndex ++;
ui->stackedWidget->setCurrentIndex(currentIndex);
}
void MainWindow::on_pushButton_3_clicked()
{
currentIndex --;
if(currentIndex < 0)
{
currentIndex ++;
}
ui->stackedWidget->setCurrentIndex(currentIndex);
}
void MainWindow::on_pushButton_4_clicked()
{
QFile::copy("C:/p/text.txt", "C:/p/text1.txt");
}
What could cause this strange behaviour?
I've noticed same problem and it seems that implementation of copy() is not good. It somehow think you have no enough permission to copy even if you do have. Some Windows permission conflict.
There is no good workaround but you might try to copy file by redoing whole process (it works sometimes):
Open source file for reading
Open (create) destination file for writing.
copy all data from first file to second one.
Far from perfect but sometimes it works.

Get system username in Qt

Is there any cross platform way to get the current username in a Qt C++ program?
I've crawled the internet and the documentation for a solution, but the only thing I find are OS dependent system calls.
I was actually thinking about it a couple of days ago, and I came to the conclusion of having different alternatives, each with its own trade-off, namely:
Environment variables using qgetenv.
The advantage of this solution would be that it is really easy to implement. The drawback is that if the environment variable is set to something else, this solution is completely unreliable then.
#include <QString>
#include <QDebug>
int main()
{
QString name = qgetenv("USER");
if (name.isEmpty())
name = qgetenv("USERNAME");
qDebug() << name;
return 0;
}
Home location with QStandardPaths
The advantage is that, it is relatively easy to implement, but then again, it can go unreliable easily since it is valid to use different username and "entry" in the user home location.
#include <QStandardPaths>
#include <QStringList>
#include <QDebug>
#include <QDir>
int main()
{
QStringList homePath = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
qDebug() << homePath.first().split(QDir::separator()).last();
return 0;
}
Run external processes and use platform specific APIs
This is probably the most difficult to implement, but on the other hand, this seems to be the most reliable as it cannot be changed under the application so easily like with the environment variable or home location tricks. On Linux, you would use QProcess to invoke the usual whoami command, and on Windows, you would use the GetUserName WinAPI for this purpose.
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
int main(int argc, char **argv)
{
// Strictly pseudo code!
#ifdef Q_OS_WIN
char acUserName[MAX_USERNAME];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName))
qDebug << acUserName;
return 0;
#elif Q_OS_UNIX
QCoreApplication coreApplication(argc, argv);
QProcess process;
QObject::connect(&process, &QProcess::finished, [&coreApplication, &process](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << process.readAllStandardOutput();
coreApplication.quit();
});
process.start("whoami");
return coreApplication.exec();
#endif
}
Summary: I would personally go for the last variant since, even though it is the most difficult to implement, that is the most reliable.
There is no way to get the current username with Qt.
However, you can read this links :
http://www.qtcentre.org/threads/12965-Get-user-name
http://qt-project.org/forums/viewthread/11951
I think the best method is :
#include <stdlib.h>
getenv("USER"); ///for MAc or Linux
getenv("USERNAME"); //for windows
EDIT : You can use qgetenv instead of getenv.
In QT5 and up it is possible to do the following :
QString userName = QDir::home().dirName();
`QDir::home() returns the user's home directory.
You can use qEnvironmentVariable
QString sysUsername = qEnvironmentVariable("USER");
if (sysUsername.isEmpty()) sysUsername = qEnvironmentVariable("USERNAME");
Also you can use QProcessEnvironment like this:
QProcessEnvironmentenv = QProcessEnvironment::systemEnviroment();
QString username = env.value("USER");
There is a way to get the current windows username with Qt. Here it is
mainwindow.ui
This is the form ui
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QDir>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->getUser();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::getUser()
{
QProcess *username = new QProcess();
QStringList cmdParamaters, split;
QString clean1, clean2, clean3,userName;
int cutOff, strLen;
cmdParamaters << "/c"<<"\"%USERPROFILE%\"";
username->setProcessChannelMode(QProcess::MergedChannels);
username->start("cmd.exe",cmdParamaters);
username->waitForFinished();
QString vusername (username->readAllStandardOutput());
cutOff = vusername.indexOf("'", 1);
ui->label_2->setText(vusername);
clean1 = vusername.left(cutOff);
ui->label_3->setText(clean1);
clean2 = clean1.remove(0,3);
strLen = clean2.length();
ui->label_4->setText(clean2);
clean3 = clean2.left(strLen-2);
split = clean3.split("\\");
userName = split[2]; //This is the current system username
ui->label_5->setText(userName);
delete username;
}
Output:
Code output