How to call a variable defined in one function in another function
-
(Apologies for non-correct terms. I'm not a C++ programmer) :-)
I'm working on a GUI that will take a file chosen by the user and delete it using the
srm
command from the secure-delete package (on Linux). This is the code in Taz.cpp for the user to choose a file :void Taz::on_chooseButton_clicked() { QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); }
So if I understand this correctly,
fileNames
is the variabel referencing whatever file the user has chosen (or is this incorrect)?
(NOTE: code for this taken from https://doc.qt.io/qt-5.7/qfiledialog.html)
My goal for this is for the user to click the "Choose file" button that references the "onn_chooseButton_clicked() slot, which will open a file dialog from which he/she can select the file(s) to delete. If I understand the code correctly the list of files chosen is stored in the fileNames variable.Next, I want the user to press the "Shred" button, which will call the
srm <chosen_files>
command. This is where I'm having trouble. Obviously the files being deleted will be different every time, so I need a variable to substitute. Based on my understanding, I should be able to do something likesrm fileNames
to delete the file(s). However, I'm having a lot of trouble getting this to work. If I dovoid Taz::on_shredButton_clicked() { system(qPrintable("srm -r /home/fred/delete_me")) }
the code will work perfectly and delete the file
delete_me
when I press the Shred button on the Gui. However, if I try to assign the fileNames variabel in place of the
absolute path, I get nothing. I've tried various combinations such as
system("srm " << fileNames.c_str());
system(qPrintable("srm "<<fileNames));
system(qPrintable("srm %s", fileName);
orQProcess process; process.start("srm fileNames" );
None of them will work.
If I were in python I would say this is partly due because fileName is not a globally defined variable, but I can't see if that is the case here in C++/Qt.(That is,void
signals a new function in C++, right?)Thanks for any help! I know my abysmal understanding of C++ is to blame, and I can't wait to get this behind me and start back work on my project. :-)
-
Hi and welcome
From dialog you get a QStringList
http://doc.qt.io/qt-5/qstringlist.html
So you should loop it and call pr file
for (int i = 0; i < fileNames.size(); ++i)
cout << fileNames.at(i);It would be much better to use QProcess if possible.
-
@mrjj Would this be correct?
void Taz::on_chooseButton_clicked() { QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); for (int i = 0; i < fileNames.size(); ++i) cout << fileNames.at(i); }
...
void Taz::on_shredButton_clicked() { QProcess process; process.start("srm" <<cout ); }
Currently when I try to
make
this I get an error:g++ -c -pipe -O2 -std=gnu++0x -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I/opt/Qt/5.6/gcc_64/include -I/opt/Qt/5.6/gcc_64/include/QtWidgets -I/opt/Qt/5.6/gcc_64/include/QtGui -I/opt/Qt/5.6/gcc_64/include/QtCore -I. -I. -I/opt/Qt/5.6/gcc_64/mkspecs/linux-g++ -o taz.o taz.cpp taz.cpp: In member function ‘void Taz::on_chooseButton_clicked()’: taz.cpp:40:9: error: ‘cout’ was not declared in this scope cout << fileNames.at(i); ^ Makefile:945: recipe for target 'taz.o' failed make: *** [taz.o] Error 1
How should I declare cout?
Thanks!
-
@Fred-Barclay said in How to call a variable defined in one function in another function:
taz.cpp: In member function ‘void Taz::on_chooseButton_clicked()’:
taz.cpp:40:9: error: ‘cout’ was not declared in this scope
cout << fileNames.at(i);
^
Makefile:945: recipe for target 'taz.o' failed
make: *** [taz.o] Error 1How should I declare cout?
#include <iostream>
and change the reference tostd::cout
to fix the error reported by the compiler, but that's not going to produce useful results. cout is an output file stream.cout << fileName.at(i)
will write one file name at a time to standard output, without a newline or space to separate them. The commented-outprocess.start("srm" <<cout )
definitely isn't right.You may want to find a basic C++ tutorial such as http://www.cplusplus.com/doc/tutorial/classes/
-
hi
Just a note:
The arguments for QProcess should be put in a list//Example
QString program = "./path/to/srm";
QStringList arguments;
arguments << "file1" << "file 2";
QProcess myProcess(parent);
myProcess.start(program, arguments);since fileNames is such list, you can use it directly.
as in
myProcess.start(program, fileNames );Also sorry for cout. what just to write out the names to check
for (int i = 0; i < fileNames.size(); ++i)
cout << fileNames.at(i); // <<< this prints the entry [i] from the list -
@mrjj Would this be correct? I'm just trying to get the contents of fileName echoed into a text file - before I try calling
srm -r fileNames
with another button.void Taz::on_chooseButton_clicked() { // New behavior QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); QObject *parent; QString program = "/bin/echo"; QStringList arguments; arguments << "fileNames" << ">> /home/fred/fn.txt"; QProcess *myProcess = new QProcess(parent); myProcess->start(program, arguments); }
When compiling with
make
I get a warning:taz.cpp: In member function ‘void Taz::on_chooseButton_clicked()’: taz.cpp:41:46: warning: ‘parent’ may be used uninitialized in this function [-Wmaybe-uninitialized] QProcess *myProcess = new QProcess(parent);
The GUI does finish compiling, though. However, nothing is echoed into /home/fred/fn.txt. :(
Thanks! -
Hi
well, this is not ok.
QObject *parent;
..
QProcess *myProcess = new QProcess(parent);
as parent is a dangling pointer so its invalid to do.
( its just points to random location)
( that is what it means with warning: ‘parent’ may be used uninitialized)
so just use
QProcess *myProcess = new QProcess(this); // this being Taz ( mainwinow i guess)also, you are not really processing the list
but you should get "fileNames" in the fn.txt?maybe you can do
fileNames << ">> /home/fred/fn.txt";
and
myProcess->start(program, fileNames );But in any case
"fileNames" do not expand to the real list as it would in say bash.
it just is text. like "hello". -
@mrjj Thanks - unallocated error fixed. You're right, I'm definitely not processing the list fileNames. I was just hoping I could get something (even the word "fileNames") to be echoed into a file.
This yields nothing; is it what you are talking about?
void Taz::on_chooseButton_clicked() { // New behavior QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); QString program = "/bin/echo"; QStringList arguments; fileNames << ">> /home/fred/fn.txt"; QProcess *myProcess = new QProcess(this); myProcess->start(program, fileNames ); }
BTW: here is my entire taz.cpp file: https://gist.github.com/Fred-Barclay/f0454d31681fe3744659cd18dfd62403
and here is a screenshot (just in case...)
-
Hi
it looks ok now.you should use qDebug() to check stuff out
(#include <QDebug>)and do
qDebug() << " numfiles:" << fileNames.size();
It will show in Creator in output window.
Should give you a non zero value.also
QProcess has a error() function u should also call to see if any errors.for test u can also try
QProcess sh;
sh.start("sh", QStringList() << "-c" << "ifconfig" << ">> /home/fred/fn.txt"); -
Hi,
IIRC, you should split
>>
and/home/fred/fn.txt
and add both separately to your argument list. -
@SGaist Hmm... that would make sense but even then nothing seems to happen when or after I press the button ("Choose File" in the screenshot above):
void Taz::on_chooseButton_clicked() { // New behavior QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); QString program = "/bin/echo"; QStringList arguments; arguments << "fileName" << ">>" << "/home/fred/fn.txt"; QProcess *myProcess = new QProcess(this); myProcess->start(program, arguments); }
-
You should add some error checking to your code. That would help pinpoint the problem.
-
@Fred-Barclay said in How to call a variable defined in one function in another function:
@SGaist Hmm... that would make sense but even then nothing seems to happen when or after I press the button ("Choose File" in the screenshot above):
void Taz::on_chooseButton_clicked() { // New behavior QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); QString program = "/bin/echo"; QStringList arguments; arguments << "fileName" << ">>" << "/home/fred/fn.txt"; QProcess *myProcess = new QProcess(this); myProcess->start(program, arguments); }
Is the expectation that "fileName" will be appended to the file /home/fred/fn.txt?
Neither echo nor QProcess have special handling for ">>" as far as I am aware. Redirection to a file using this syntax is usually the domain of a shell such as bash. QProcess either redirects output to the enclosing program's output, or makes it available via QProcess::readChannel().
What you'll get instead is the string "fileName >> /home/fred/fn.txt" written to standard output.
#include <QCoreApplication> #include <iostream> #include <QProcess> #include <QObject> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QProcess p; p.setProcessChannelMode(QProcess::ForwardedChannels); QStringList arguments; arguments << "fileName" << ">>" << "/home/fred/fn.txt"; QObject::connect<void(QProcess::*)(int)>(&p, &QProcess::finished, [=](){ std::cout << "process done" << std::endl; }); p.start("/bin/echo", arguments); return a.exec(); }
-
Hi. For a non c++ programmer, you seem to be catching on. Your posting of...
void Taz::on_chooseButton_clicked() { // New behavior QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) fileNames = dialog.selectedFiles(); QString program = "/bin/echo"; QStringList arguments; arguments << "fileName" << ">>" << "/home/fred/fn.txt"; QProcess *myProcess = new QProcess(this); myProcess->start(program, arguments); }
isn't too bad. Just a little overly complex, so this
void Taz::on_chooseButton_clicked() { // New behavior QFileDialog dialog(this); dialog.setViewMode(QFileDialog::Detail); dialog.setFileMode(QFileDialog::ExistingFiles); QStringList fileNames; if (dialog.exec()) { fileNames = dialog.selectedFiles(); QProcess::execute("echo", fileNames); } }
should echo the filenames to your Application Output screen. This is actually a lot closer to what you're end game should look like.
HTH
Mike