c++gtkmmgtkmm4

Build error on connection of signal_response of gtkmm4 FileChooserNative to the function


I need to connect signal_response of FileChooserNative to the function, but I got an error when I try to use code from example from Programming with gtkmm 4 book.

When I try to compile this (g++, XCLT, macOS Big Sur):

void MyWindow::on_button_browse_clicked(){
auto dialog = Gtk::FileChooserNative::create("Please choose a folder", *this,
Gtk::FileChooser::Action::SELECT_FOLDER, "Choose", "Cancel");
dialog->set_transient_for(*this);
dialog->set_modal(true);
dialog->signal_response().connect(sigc::bind(sigc::mem_fun(*this,
&MyWindow::on_folder_dialog_response), dialog)); // <- error
dialog->show();}

A minimal .cpp to reproduce the problem is here (pastebin).

I get in instantiation of function template specialization... error. Full build log is here (pastebin).

My goal is to send response from file choosing dialog to the on_folder_dialog_response function and then show path to the folder in terminal.

What is the right code to connect response from file choosing dialog to the function?


Solution

  • You have a build error because the type of the extra argument you provide is not Gtk::FileChooserNative*, but rather Glib::RefPtr<Gtk::FileChooserNative> (this is what hides behind auto). So you should have:

    void MyWindow::on_folder_dialog_response(int response_id, Glib::RefPtr<Gtk::FileChooserNative>& dialog)
    

    instead. Note however that your dialog instance will die by the end of MyWindow::on_button_browse_clicked, and you will be left with a null reference.

    Using Gtkmm 3.24 (you may have to adapt a bit for Gtkmm 4), I have written a small example for you:

    #include <iostream>
    
    #include <gtkmm.h>
    
    class MainWindow : public Gtk::Window
    {
    
    public:
    
        MainWindow();
    
    private:
    
        // Handler for when the user clicks the "Open file chooser dialog..." button
        // on the main window. This:
        //
        //  1. Creates the file chooser.
        //  2. Connects the response signal handler, to know about what the user
        //     will have done with the chooser.
        //  3. Shows the file chooser.
        //
        // So when this is done the user is presented the file chooser.
        void OnButtonBrowseClicked()
        {
            m_fileChooser = Gtk::FileChooserNative::create("Please choose a folder",  
                                                           *this,    
                                                           Gtk::FileChooserAction::FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                                           "Choose",
                                                           "Cancel");
    
            m_fileChooser->signal_response().connect(
                [this](int p_responseID)
                {
                    OnBrowseButtonClicked(p_responseID);
                }
            );
    
            m_fileChooser->show();
    
        } // m_fileChooser will not be destroyed here because it is a member.
    
        // User response handler for the file chooser.
        void OnBrowseButtonClicked(int p_responseID)
        {
            switch(p_responseID)
            {
                case Gtk::ResponseType::RESPONSE_ACCEPT:
                {
                    std::cout << m_fileChooser->get_file()->get_path() << std::endl;
                    break;
                }
                case Gtk::ResponseType::RESPONSE_CANCEL:
                {
                    std::cout << "Cancel clicked : " << p_responseID  << std::endl;
                    break;
                } 
                default:
                {
                    std::cout << "Unexpected button clicked: " << p_responseID << std::endl;
                    break;
                }
            }
        }
    
        // Keeping a reference on the picker. This allows me to use it whenever I need. I can
        // also reset it if I don't need it anymore.
        Glib::RefPtr<Gtk::FileChooserNative> m_fileChooser;
    
        Gtk::Button m_browseBtn;
    
    };
    
    MainWindow::MainWindow()
    : m_browseBtn{"Open file chooser dialog..."}
    {
        add(m_browseBtn);
    
        m_browseBtn.signal_clicked().connect(
            [this]()
            {
                OnButtonBrowseClicked();
            }
        );
    }
    
    int main(int argc, char *argv[])
    {
        auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
      
        MainWindow window;
        window.show_all();
      
        return app->run(window);
    }
    

    This basically lets the user choose a file and the path to its parent directory is printed to the console.

    Notes:

    1. I have used a reference to the file chooser instead of an argument (like you have tried). This lets me access it without having to change the callback's expected prototype. It also avoids the null reference issue.
    2. I have avoided the old-school sigc::bind/sigc::mem_fun in favor of lambda expressions. I find it to be less obscure.