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
-
能达到要求, GTK风格// 创建一个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::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");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具