0

我需要将 FileChooserNative 的 signal_response 连接到该函数,但是当我尝试使用Programming with gtkmm 4 book中的示例代码时出现错误。

当我尝试编译这个(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();}

重现问题的最小 .cpp 文件在此处(pastebin)。

我得到in instantiation of function template specialization...错误。完整的构建日志在这里(pastebin)。

我的目标是将文件选择对话框的响应发送到 on_folder_dialog_response 函数,然后在终端中显示文件夹的路径。

将文件选择对话框的响应连接到函数的正确代码是什么?

4

1 回答 1

1

你有一个构建错误,因为你提供的额外参数的类型不是Gtk::FileChooserNative*,而是Glib::RefPtr<Gtk::FileChooserNative>(这是隐藏在后面的auto)。所以你应该有:

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

反而。但是请注意,您的dialog实例将在 结束时终止MyWindow::on_button_browse_clicked,并且您将留下一个空引用。

使用 Gtkmm 3.24(你可能需要对 Gtkmm 4 稍作调整),我为你写了一个小例子:

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

这基本上让用户选择一个文件,并将其父目录的路径打印到控制台。

笔记:

  1. 我使用了对文件选择器的引用而不是参数(就像您尝试过的那样)。这让我无需更改回调的预期原型即可访问它。它还避免了空引用问题。
  2. 我已经避免了老式的sigc::bind/sigc::mem_fun支持 lambda 表达式。我觉得它不那么晦涩难懂。
于 2021-08-08T15:15:09.770 回答