Directly executing a batch through clicked function in qt - c++

So I'm trying to have my "button" directly execute a Batch file, important here is that I don't want it to show me a dialogue and make me chose the path, which is the problem I'm having right now with the following code
void MainWindow::on_pushButton_clicked()
{
QString filename=QFileDialog::getOpenFileName(
this,
tr("Open File"),
"C://",
"All files (*.*);;Text File (*.txt);;Music file (*.mp3)");
}
I think this is probably really simple, but i can't get it, I'm not even learning c++ at the moment but my boss asked me to create something out of my scope (wants me to create a GUI for a batch file and have them interact) and I thought of this approach, which is just creating a GUI that executes it.
I've looked at this question: asked to execute an external program with Qt
but they don't talk about how the file path can directly be added into the code, or if I should even be using Qprocess and how, and if I can pass it through "clicked" function.
I'm really inexperienced, all of the code above I got with the help of the internet, but I really don't know how to program using c++
so could someone please be kind enough to show me how a file path can be added to the code, assuming it's in C:\Users\name_goes_here\Downloads
I'd really appreciate it :D

I'd recommend using QProcess for anything "execute external program" with Qt.
You could do it like this:
void MainWindow::on_pushButton_clicked()
{
QProcess process;
process.start("C:/Users/name_goes_here/Downloads/yourfile.bat");
process.waitForFinished(); // Assuming that you do want to wait for it to finish before the code execution resumes
}
Note the "/" in the path. Only Windows uses the messed up "\" for path separation, which would require you to write "C:\\Users\\.." in any string in C++ as "\" needs to be escaped.
Luckily, Qt uses "/" as the universal separator and translates it to whatever the OS needs as required. So you should just use "/" whenever working with Qt.
This is from the Qt documentation:
Qt uses "/" as a universal directory separator in the same way that "/" is used as a path separator in URLs. If you always use "/" as a directory separator, Qt will translate your paths to conform to the underlying operating system.
And finally, if you don't know how to code in C++, shouldn't you be learning that first instead of trying to execute batch files from within a library as complex as Qt? Sounds like you're trying to do too many new things at once.

This is fairly simple merging your source and the one you linked:
void MainWindow::on_pushButton_clicked()
{
QProcess::execute(
QString::fromLatin1(
"cmd.exe /c C:\\Users\\name_goes_here\\Downloads\\file.bat"));
}
Notes:
I used QProcess::execute() instead of QProcess::start() to make things even simpler.
To achieve execution of the batch file, I pass it to cmd32.exe as this is the interpreter which is responsible.
As MCVE testQProcessBatch.cc:
// Qt header:
#include <QtWidgets>
void on_pushButton_clicked()
{
#if 0 // WORKS:
QProcess::execute(
QString::fromUtf8("cmd.exe /c C:\\Users\\Scheff\\Downloads\\testBatch.bat"));
#else // WORKS AS WELL:
QProcess::execute(
QString::fromUtf8("C:\\Users\\Scheff\\Downloads\\testBatch.bat"));
#endif // 0
}
int main(int argc, char **argv)
{
qDebug() << "Version:" << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
QMainWindow qWin;
QPushButton qBtn(QString::fromLatin1("Start cmd"));
qWin.setCentralWidget(&qBtn);
qWin.show();
QObject::connect(&qBtn, &QPushButton::clicked,
&on_pushButton_clicked);
// run application
return app.exec();
}
and the test batch file testBatch.bat:
echo "This is testBatch.bat"
pause
Tested with VS2013 on Windows 10:

Thanks for contributing guys!
I tried using the QProcess method but I think I'm too inexperienced when it comes to figuring out problems associated with it (which I did face when using this method). the CMD route is probably good but I also thought it was too difficult and both of these methods didn't work for me.
Here's what I have now (thanks to Detonar and ymoreau) and and it seems to be doing the job, this might not be the most optimal approach, but it worked for me!
I included QDesktopServices and QUrl
void MainWindow::on_pushButton_clicked()
{
QString filename="C:\\Users\\Name_goes_here\\Downloads\\test.bat";(
this);
hide(); //optional
QDesktopServices::openUrl(QUrl("file:///"+filename,QUrl::TolerantMode));
}

Related

showing cmd terminal in qt widgets application

I'm trying to pass some cmd commands using system() and I would like to be able to "communicate" with cmd, say I code in system("dir") in my mainwindow.cpp under my clicked function
this is what it looks like for example
void MainWindow::on_pushButton_login_clicked()
{
std::string platform_server_ip = ui->lineEdit_platform_server_ip->text().toStdString();
if (platform_server_ip == "dir"
{
QMessageBox::information(this,"Login", "all required log in details are correct");
close();
const char* c = platform_server_ip.c_str();
system(c);
system("ipconfig");
}
I would like to know why it behaves like this and if that's normal. I've included CONFIG += console
in my project file, and checked "run in terminal" (tried it also without) but it never shows me my desired outcome.
Instead what I get, is a blank terminal that pops up along side my GUI, and then when I enter "dir" in my GUI and hit enter, a cmd window pops up really fast and in less than a second, its gone. I've even tried it with system("ipconfig")andsystem ("pause")
as well as with one system command like this system("ipconfig" "&pause")
desired outcome: is just a normal execution of system("ipconfig"), followed by other system commands, that display the same result as typing them in cmd itself.
I've also tried all this in "qt Console application" and I either get the same result, or the output (what would normally be as output on cmd) is then found in "application output" of qt creator.
Is there another better way I can achieve what I want?
I'm truly a noob and would really appreciate some guidance.
You can try
system("cmd /k ipconfig");
This will open another terminal window which will stay open (k stands for keep) at the end of the command execution.
I think you don't need the CONFIG += console project setting, to achieve this. Calling system will start another process, which isn't related at all with the calling application.
If you want to start external programs from within a Qt application, you can use QProcess class, which lets you somehow interact with the started processes through standard in/out. For a very simple example, have a form with a push button and a text edit called textEdit; in the push button clicked slot:
QProcess process;
process.start("ipconfig");
process.waitForReadyRead();
ui->textEdit->setText(process.readAll());
process.waitForFinished();
This way, you won't see additional console windows, and the command output will be shown directly in your text edit.
This can be generalized in a function like this:
bool exec(QString command)
{
QProcess process;
process.start(command);
if(!process.waitForStarted())
{
return false; //the process failed to start
}
//etc...
return true;
}
Depending on whether this is not just a quick hack/tool, you can look at QProcess for more indepth control over your process so that you can read / write the child process pipes.

QT Creator Main.cpp MainWindow.cpp

I'm currently working on my project for my Master thesis in Mechatronics/Robotics. The goal of y project is to read in a .stl-File and calculate the path for an industrial robot.
Till now everything worked fine for me, but now my professor wants me to develop a GUI, because till now I was just using the command window and wrote all parameters manual. Now I'm working with Qt Creator and developed a simple GUI for my project.
In this interface I got a RadioButton for ascii files. In order my functions work I have to determine if the user is entering a ascii file or an binary file. But here's my first problem. In the command window I just check the argv[] for the string "-ascii". If the user enters this, a flag is set to false.
if(0 == strcmp(argv[i], "-ascii")) {
isBinaryFormat = false;
}
Now I just want to do the same int the GUI. If the RadioButton is checked flag is set to false. So I wrote the following in the main.cpp file
if(ui->radioButton->isChecked()) {
isBinaryFormat = false;
}
But ui is unknown in the main function. After searching for help on google I just found tutorials writing the code in the mainwindow.cpp file. But how can I send the information form the mainwindow file to my main function in the main.cpp file.
A second question would be, if I use the QFileDialog::getOpenFilename method, how can I hand the file name to my other functions. The idea is, the user selects a file anywhere on his PC, and the program opens the file and processes it. But here I got the same problem. I can brows for a file, but how can I transfer the information from the mainwindow.cpp to my main.cpp.
I'm thankful for any help I get. Very grateful a lonely coder
First of all you don't write UI Code in the main.cpp.
You write it where the MainWindow Class is so in MainWindow.cpp and MainWindow.h.
Then your ui-> will work because it then has access to that namespace.
I don't see why you would have functions in Main.cpp?
Without seeing more code you're not likely to get an answer to that.
If you want to use external functions in your classes either declare the methods in the class directly or create a new file like global_function.h and .cpp which you can include in your class. ( don't forget the header guards )
Also shouldn't that code look like this:
if(!ui->radioButton->isChecked())
{
isBinaryFormat = false;
}
because of:
If the RadioButton is checked flag is set to false.
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
"/home",
tr("Images (*.png *.xpm *.jpg)"));
getOpenFileName( ) will return a string containing the path and filename of the selected file which you can pass to your functions then.
Please read some more about how to use Qt.
It's not just about the files, there's a class, too. Learn about them. Solution is to add a getter to your MainWindow class that will return whether the radioButton is checked:
class MainWindow : public QMainWindow
{
public:
// optionally, move implementation in the source file
bool isBinaryFormatChecked() const
{
return ui->radioButton->isChecked();
}
// other stuff ...
};
And then you can access it in your main like window.isBinaryFormatChecked() orwindow->isBinaryFormatChecked() depending on whether you have a pointer or not. Another way would be to make ui in your MainWindow public, so you could access the whole user interface, but that breaks proper encapsulation.
I think you need to go through a few of the (excellent in my opinion) examples supplied with Qt before attempting to integrate your already working console code.
Essentially you really don't want to do that check in the main.cpp, but if you must you could have it in a public function of the mainwindow and call that from your main.cpp file. But then that doesn't really make sense as you don't want to check whether the appropriate radio button is set until the user inputs something. You're going to have to read up on event based programming.

Display QProcess output in another window

I'm using the QT Creator on Ubuntu.
I have GUI with a mainwindow and another window called "progress".
Upon clicking a button the QProcess starts and executes an rsync command which copies a folder into a specific directory. I created a textbrowser which reads the output from the rsync command. Also clicking the button causes the "progress" window to pop up.
So far so so good, now my problem.
Instead of showing the rsync output in my mainwindow i want it to be in progress.
I've tried several methods to get the QProcess into the progress via connect but that doesn't seem to work.
mainwindow.cpp
void MainWindow::on_pushButton_clicked()
{
if (ui->checkBox->isChecked()
)
m_time ="-t";
QObject parent;
m_myProcess = new QProcess();
connect(m_myProcess, SIGNAL(readyReadStandardOutput()),this, SLOT(printOutput()));
QString program = "/usr/bin/rsync";
arguments << "-r" << m_time << "-v" <<"--progress" <<"-s"
<< m_dir
<< m_dir2;
m_myProcess->start(program, arguments);
}
progress.cpp
void Progress::printOutput()
{
ui->textBrowser->setPlainText(m_myProcess->readAllStandardOutput());
}
I know it's pretty messy iv'e tried alot of things and haven't cleaned the code yet also I'm pretty new to c++.
My goal was to send the QProcess (m_myProcess) to progress via connect but that didn't seem to work.
Can you send commands like readyReadAllStandardOutput via connect to other windows (I don't know the right term )?
Am I doing a mistake or is there just another way to get the output to my progress window ?
m_myProcess is a member of the class MainWindow and you haven't made it visible to the class Progress. That's why you have the compilation error
m_myProcess was not declared in this scope
What you could do:
Redirect standard error of m_myProcess to standard output, such that you also print what is sent to standard error (unless you want to do something else with it). Using
m_myProcess.setProcessChannelMode(QProcess::MergedChannels);
Make the process object available outside MainWindow
QProcess* MainWindow::getProcess()
{
return m_myProcess;
}
Read the process output line by line in Progress. It needs to be saved in a buffer because readAllStandardOutput() only return the data which has been written since the last read.
... // somewhere
connect(window->getProcess(), SIGNAL(readyReadStandardOutput()), this, SLOT(printOutput())
...
void Progress::printOutput(){
//bigbuffer is member
bigbuffer.append(myProcess->readAllStandardOutput();)
ui->textBrowser->setPlainText(bigbuffer);
}

qt5 designer, using fileopen, displaying file path in lineedit, is there an issue doing it this way?

just started using qt,
looked through docs, google, examples, etc.. trying to find simple examples(working mind you)
that showed how to do (imho) simple things, by themselves.
well i stumbled upon my answer and i was wondering if this approach would cause an issue later as the code becomes more complex.
there are more includes than needed for this example, but this is direct from working code.
mainwindow.h:
i added
private slots:
void vpkButton_clicked();
and after
Ui::MainWindow *ui;
i added
QLineEdit *vpkPathTxt;
in mainwindow.cpp:
after
ui->setupUi(this);
i added
connect( this->ui->vpkButton, SIGNAL( clicked() ), this, SLOT(vpkButton_clicked()) );
to connect my ui button to the proper slot, the issue was getting the string from vpkButton_clicked() to display in the line edit i made in the designer,
what ended up working for me was adding this next:
vpkPathTxt = this->ui->vpkPathTxt;
the function in my main.cpp became very easy:
(QString declarations at top outside voids)
void MainWindow::vpkButton_clicked()
{
vpkName = QFileDialog::getOpenFileName(this,
tr("Open VPK File"), "~/", tr("VPK Files (*_dir.vpk)"));
vpkPathTxt->setText(vpkName);
qDebug() << vpkName;
}
the reason i am ask is because it seems a little too easy to be reliable, and the fact that i havent seen it done like this,
any input welcome
thankyou
One problem with your slot is that you don't consider the case where the user discards the "open file" dialog. In this case, the function QFileDialog::getOpenFileName returns a null QString, so you should only proceed with your logic if the return value was not a null string:
if (!vpkName.isNull()) {
...
}
The second problem is as follows and I made some assumptions since I don't see your full code:
I guess you want to load a file using the file name the user has chosen in the dialog. But you set the file name in the line edit too, which the user can edit by hand. I also guess that the actual file loading happens in a different step (i.e. after clicking another button), so after the user has edited the file name by hand in the line edit it won't be the same than in your local variable vpkName.
When loading the file I'd read the contents of the line edit instead of the variable vpkName so the edit made by hand will be respected.
A different method is to also watch for editing of the line edit and reflect the changes in your variable too. Then it will be ok to read the variable instead of the line edit when loading the file later on.

how to make a console cmd for Qt app in Linux?

I made a basic text editor(called 'Note') in Qt on Arch Linux! so I built the project and made an installer using installjammer. now when I type note in terminal it opens the program.
Now here is my question:
if we use nano or leafpad or mousepad it take the path of the file opens it.
Eg. nano /etc/fstab
how can I do this in my program? do I need to edit something in the installer or in my codes? HELP ME! pls!
~Thanks!
You might want to read the docs for QCoreApplication. Especially:
QStringList QCoreApplication::arguments()
Get the filename from this ist, open the file.
Get the passed command line argument either directly in main() from the argv argument, or through QCoreApplication::arguments(). This is well documented and should be rather easy. The tricky part is actually opening the file. For that, you need to schedule a slot for running right after you call exec() on your QApplication instance. First, create a slot. For example, if you're subclassing QApplication, you can:
class MyApplication: public QApplication {
Q_OBJECT
// ...
private slots:
void checkCmdLine();
// ...
};
In your MyApplication::checkCmdLine() function you get the arguments from QCoreApplication::arguments() and check whether a filename was passed. If yes, you open it.
Now you need to make sure that MyApplication::checkCmdLine() will run right after you call exec() on MyApplication. You do that in your main() function by using QMetaObject::invokeMethod(). For example:
int main(int argc, char* argv[])
{
MyApplication* app = new MyApplication(argc, argv);
// ...
QMetaObject::invokeMethod(app, "checkCmdLine", Qt::QueuedConnection);
app->exec();
// ...
}
If you're not subclassing QApplication, then you can implement the slot in some other QObject subclass and use QMetaObject::invokeMethod() on that instead.