This page say :

请选择一篇博客进行编辑

GTKMM 4 文件浏览对话框

前言

  • gtkmm4 弃用了Gtk::FileChooserDialog 而引进了Gtk::FileDialog
  • 有几点需求和问题:
    • 我需要选择文件夹的对话框能连文件一起显示
    • gtkmm4 依然能使用 Gtk::FileChooserNative
    • 用本土的文件浏览对话框 还是 GTK 的
    • gtkmm3 使用Gtk::FileChooserDialog 能满足第一个需求吗

使用 Gtk::FileChooserNative

// 创建一个FileChooserNative
auto dialog = Gtk::FileChooserNative::create("Please choose a folder",
              *this,
              Gtk::FileChooser::Action::SELECT_FOLDER,
              "Choose",
              "Cancel");
//    dialog->set_transient_for(*this);
//
//    // 创建一个过滤器
auto filters = Gio::ListStore<Gtk::FileFilter>::create();
auto filter_text = Gtk::FileFilter::create();
filter_text->set_name("Any files");
//    filter_text->add_mime_type("any/any");
filter_text->add_pattern("*");
filters->append(filter_text);
dialog->add_filter(filter_text);
//    dialog->set_filter(filter_tex
// 运行对话框
dialog->show();
  • 意思是调用原生的对话框
    >.我是在winodws上开发Gtk应用,所以它提供windows风格的文件对话框
  • 但是如果行为是 Gtk::FileChooser::Action::SELECT_FOLDER 时, 上面的过滤器就不起效果, 对话框中也不会显示过滤下拉菜单选项, 也只显示文件夹

Gtk::FileDialog

  • 官网例子: https://gnome.pages.gitlab.gnome.org/gtkmm-documentation/sec-dialogs-filedialog.html
    官网例子很简单,一个文件选择(带过滤器), 一个文件夹选择(不显示文件,无过滤器,默认使用本土风格的文件对话框)
  • 我尝试在它select_folder(文件夹选择)的情况下给它加过滤器,希望它能显示文件, 于是发现了下面的 "特性"
    auto dialog = Gtk::FileDialog::create();
    auto filters = Gio::ListStore<Gtk::FileFilter>::create();
    auto filter_text = Gtk::FileFilter::create();
    filter_text->set_name("Any files");
    filter_text->add_mime_type("some mime_type balabala");
    filter_text->add_pattern("*");
    filters->append(filter_text);
    dialog->set_filters(filters);
    // Show the dialog and wait for a user response:
    dialog->select_folder(sigc::bind(sigc::mem_fun(
                                         *this, &ExampleWindow::on_folder_dialog_finish), dialog));
    
    能达到我上面的需求: 选择文件夹的对话框能连文件一起显示 是GTK风格的文件浏览对话框
    但如果注释掉add_mime_type这一行, 那么显示本土风格的对话框,而且就和上面FileChooserNative一样达不到需求

gtkmm3 使用 Gtk::FileChooserDialog

  • // 创建一个FileChooserDialog
    Gtk::FileChooserDialog dialog("Please choose a folder or file",                            Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
    
    // 添加“打开”按钮
    dialog.add_button("_Open", Gtk::RESPONSE_ACCEPT);
    
    // 添加“取消”按钮
    dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
    
    // 设置对话框的标题
    dialog.set_title("Select Folder or File");
    
    // 设置对话框的默认文件夹
    //    dialog.set_current_folder("/path/to/default/folder");
    
    // 设置是否显示文件
    dialog.set_show_hidden(true); // 显示隐藏文件
    auto filter_text = Gtk::FileFilter::create();
    filter_text->set_name("Any files");
    filter_text->add_mime_type("text/plain");
    filter_text->add_pattern("*");
    dialog.set_filter(filter_text);    // 不使用过滤器,显示所有文件
    
    dialog.set_transient_for(*this);
    
    //Add response buttons the the dialog:
    dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
    dialog.add_button("Select", Gtk::RESPONSE_OK);
    
    int result = dialog.run();
    
    //Handle the response:
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            std::cout << "Select clicked." << std::endl;
            std::cout << "Folder selected: " << dialog.get_filename()
                      << std::endl;
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            std::cout << "Cancel clicked." << std::endl;
            break;
        }
        default:
        {
            std::cout << "Unexpected button clicked." << std::endl;
            break;
        }
    }
    
    能达到要求, GTK风格

继承Gtk::FileChooserWidget

  • 没有尝试

注意事项与详细解析

  • 在 gtkmm 4 中,Gtk::FileDialog 类提供了一个 select_folder 方法,用于弹出一个文件夹选择对话框,让用户选择一个文件夹。这个方法是异步的,意味着它不会阻塞程序的执行,而是立即返回并继续执行后续的代码,同时文件选择对话框会在另一个线程中显示并等待用户操作。

  • 让我们来详细解析一下这段代码

    dialog->select_folder(sigc::bind(sigc::mem_fun(*this, &ExampleWindow::on_folder_finish), dialog));
    
    • dialog->select_folder(...):
      这是 Gtk::FileDialog 类的 select_folder 方法的调用。dialog 是一个指向 Gtk::FileDialog 实例的指针。这个方法会弹出一个文件夹选择对话框。

    • sigc::bind(...):
      sigc::bind 是 sigc++ 库中的一个函数,用于绑定一个回调函数和它的参数。sigc++ 是一个用于 C++ 的信号和槽库,它允许你连接信号(事件)到槽(回调函数)。在这个例子中,sigc::bind 将 on_folder_finish 成员函数绑定到 ExampleWindow 的实例(通过 *this 指针访问)上,并传递 dialog 作为参数。

    • sigc::mem_fun(*this, &ExampleWindow::on_folder_finish):
      sigc::mem_fun 是一个帮助函数,用于将类的成员函数转换为一个可以通过 sigc::bind 使用的可调用对象。在这里,它创建了一个可以调用 ExampleWindow 类的 on_folder_finish 成员函数的可调用对象。*this 是指向当前 ExampleWindow 实例的指针,&ExampleWindow::on_folder_finish 是指向 on_folder_finish 成员函数的指针。

    • &ExampleWindow::on_folder_finish:
      这是一个指向 ExampleWindow 类中 on_folder_finish 成员函数的指针。这个成员函数应该被声明为:

      void ExampleWindow::on_folder_finish(
      const Glib::RefPtr<Gio::AsyncResult>& result,
      const Glib::RefPtr<Gtk::FileDialog>& dialog);
      

      并且必须在函数体内执行:
      dialog->select_folder_finish(result);
      以便在文件夹选择操作完成时接收通知, 并正确释放内存

    • dialog:
      这个参数是传递给 on_folder_finish 槽函数的 Gtk::FileDialog 实例的指针。这样,当文件夹选择对话框关闭后,on_folder_finish 函数就可以访问这个对话框,并可能执行一些后续操作,比如获取用户选择的文件夹路径。
      注意gtkmm4中auto dialog = Gtk::FileDialog::create(); 这样初始化的 dialog 是一个共享指针

  • 用 lambda 取代上面难以阅读的代码
    C++11之后就可以用lambda来取代 bind 等绑定函数与函数适配器
    方便且直观 :

    dialog->select_folder([dialog](const Glib::RefPtr<Gio::AsyncResult>& result)
    {
        try
        {
            auto folder = dialog->select_folder_finish(result);
            std::cout << "Folder selected: " << folder->get_path() << std::endl;
        }
        catch (const Gtk::DialogError& err)
        {
            // Can be thrown by dialog->select_folder_finish(result).
            std::cout << "No folder selected. " << err.what() << std::endl;
        }
        catch (const Glib::Error& err)
        {
            std::cout << "Unexpected exception. " << err.what() << std::endl;
        }
    });
    

    前面说过select_folder是个异步的操作, 所以这里 dialog 以值传递的方式进入 lambda 才是正确的
    这样你想在[捕获]里绑定多少个参数都可以, 简单且直观 唯我 Lambda

其实...

  • 其实用gtk风格的 dialog->open(...)就足以满足要求
    而且文件和文件夹都可作为接受目标
    后续用<filesystem>提供的is_directory做一下是否是文件夹判断就行了
  • 设置一下接受按钮的文本为 dialog->set_accept_label("Select");
posted @ 2024-02-07 17:21  Computer_Tech  阅读(4)  评论(0编辑  收藏  举报