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 like srm fileNames to delete the file(s). However, I'm having a lot of trouble getting this to work. If I do

    void 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);
    or

       QProcess 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. :-)


  • Lifetime Qt Champion

    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 1

    
    How should I declare cout?
    

    #include <iostream> and change the reference to std::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-out process.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/



  • @jeremy_k Thanks - I'll read this more thoroughly in a moment, but the commented-out process.start("srm" <<cout ) is a typo. Fixing now. :)


  • Lifetime Qt Champion

    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!


  • Lifetime Qt Champion

    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...)
    0_1473369253927_taz.png


  • Lifetime Qt Champion

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


  • Lifetime Qt Champion

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

  • Lifetime Qt Champion

    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


Log in to reply