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


  • Qt Champions 2016

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


  • Qt Champions 2016

    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!


  • Qt Champions 2016

    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


  • Qt Champions 2016

    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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.