文件选择器(FileChooser)

FileChooser是一个可以由用于显示文件列表的部件实现的接口。gtkmm提供了三种用于选择最近文件或其他文件的内置实现:FileChooserWidgetFileChooserDialogFileChooserNative

FileChooserWidget是一个用于显示最近使用文件列表或其他文件的简单部件。FileChooserWidgetFileChooserDialog的基本构建块,但是你根据需要可以将其嵌入到用户界面中。

20.2.1. 简单的文件选择对话框示例

下面显示的是一个如何在程序中使用FileChooserDialog类的简单示例。这个简单示例程序有一个带有File Chooser Dialog菜单项的菜单栏。选择此菜单项时,将弹出一个显示文件列表的对话框。如果你选中侧边栏的Recent,则对话框将显示最近使用文件列表。

如果这是你第一次使用使用了最近文件框架的应用程序,那么对话框最初可能是空的。否则它应该显示其他应用程序注册的最近使用文件列表。

选择File Chooser Dialog菜单项和Recent侧边项后,你将看到与下方窗口类似的内容。

源代码

File: examplewindow.h (For use with gtkmm 4)

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>
#include <memory>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow(const Glib::RefPtr<Gtk::Application>& app);
  ~ExampleWindow() override;

protected:
  //Signal handlers:
  void on_menu_file_files_dialog();
  void on_menu_file_quit();
  void on_menu_file_new();
  void on_dialog_response(int response_id);

  //Child widgets:
  Gtk::Box m_Box;

  Glib::RefPtr<Gtk::Builder> m_refBuilder;
  Glib::RefPtr<Gio::SimpleActionGroup> m_refActionGroup;

  Glib::RefPtr<Gtk::RecentManager> m_refRecentManager;

  std::unique_ptr<Gtk::FileChooserDialog> m_pDialog;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc (For use with gtkmm 4)

#include "examplewindow.h"
#include <gtkmm/application.h>

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<ExampleWindow>(argc, argv, app);
}

File: examplewindow.cc (For use with gtkmm 4)

#include "examplewindow.h"
#include <iostream>

ExampleWindow::ExampleWindow(const Glib::RefPtr<Gtk::Application>& app)
: m_Box(Gtk::Orientation::VERTICAL),
  m_refRecentManager(Gtk::RecentManager::get_default())
{
  set_title("Recent files example");
  set_default_size(300, 150);

  //We can put a PopoverMenuBar at the top of the box and other stuff below it.
  set_child(m_Box);

  //Create actions for menus and toolbars:
  m_refActionGroup = Gio::SimpleActionGroup::create();

  //File menu:
  m_refActionGroup->add_action("new",
    sigc::mem_fun(*this, &ExampleWindow::on_menu_file_new));

  //A menu item to open the file chooser dialog:
  m_refActionGroup->add_action("files-dialog",
    sigc::mem_fun(*this, &ExampleWindow::on_menu_file_files_dialog));

  m_refActionGroup->add_action("quit",
    sigc::mem_fun(*this, &ExampleWindow::on_menu_file_quit) );

  insert_action_group("example", m_refActionGroup);


  m_refBuilder = Gtk::Builder::create();

  // When the menubar is a child of a Gtk::Window, keyboard accelerators are not
  // automatically fetched from the Gio::Menu.
  // See the examples/book/menus/main_menu example for an alternative way of
  // adding the menubar when using Gtk::ApplicationWindow.
  app->set_accel_for_action("example.new", "<Primary>n");
  app->set_accel_for_action("example.files-dialog", "<Primary>o");
  app->set_accel_for_action("example.quit", "<Primary>q");

  //Layout the actions in a menubar and a toolbar:
  const char* ui_info =
    "<interface>"
    "  <menu id='menubar'>"
    "    <submenu>"
    "      <attribute name='label' translatable='yes'>_File</attribute>"
    "      <item>"
    "        <attribute name='label' translatable='yes'>_New</attribute>"
    "        <attribute name='action'>example.new</attribute>"
    "        <attribute name='accel'>&lt;Primary&gt;n</attribute>"
    "      </item>"
    "      <item>"
    "        <attribute name='label' translatable='yes'>File Chooser _Dialog</attribute>"
    "        <attribute name='action'>example.files-dialog</attribute>"
    "        <attribute name='accel'>&lt;Primary&gt;o</attribute>"
    "      </item>"
    "      <item>"
    "        <attribute name='label' translatable='yes'>_Quit</attribute>"
    "        <attribute name='action'>example.quit</attribute>"
    "        <attribute name='accel'>&lt;Primary&gt;q</attribute>"
    "      </item>"
    "    </submenu>"
    "  </menu>"
    "  <object class='GtkBox' id='toolbar'>"
    "    <property name='can_focus'>False</property>"
    "    <child>"
    "      <object class='GtkButton' id='toolbutton_new'>"
    "        <property name='can_focus'>False</property>"
    "        <property name='tooltip_text' translatable='yes'>New</property>"
    "        <property name='action_name'>example.new</property>"
    "        <property name='icon_name'>document-new</property>"
    "        <property name='hexpand'>False</property>"
    "        <property name='vexpand'>False</property>"
    "      </object>"
    "    </child>"
    "    <child>"
    "      <object class='GtkButton' id='toolbutton_quit'>"
    "        <property name='can_focus'>False</property>"
    "        <property name='tooltip_text' translatable='yes'>Quit</property>"
    "        <property name='action_name'>example.quit</property>"
    "        <property name='icon_name'>application-exit</property>"
    "        <property name='hexpand'>False</property>"
    "        <property name='vexpand'>False</property>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  try
  {
    m_refBuilder->add_from_string(ui_info);
  }
  catch(const Glib::Error& ex)
  {
    std::cerr << "building menubar and toolbar failed: " <<  ex.what();
  }

  //Get the menubar and toolbar widgets, and add them to a container widget:
  auto object = m_refBuilder->get_object("menubar");
  auto gmenu = std::dynamic_pointer_cast<Gio::Menu>(object);
  if (gmenu)
  {
    //Menubar:
    auto pMenubar = Gtk::make_managed<Gtk::PopoverMenuBar>(gmenu);
    m_Box.append(*pMenubar);
  }
  else
    g_warning("GMenu not found");

  auto pToolbar = m_refBuilder->get_widget<Gtk::Box>("toolbar");
  if (pToolbar)
    //Toolbar:
    m_Box.append(*pToolbar);
  else
    g_warning("toolbar not found");
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_menu_file_new()
{
  std::cout << " New File" << std::endl;
}

void ExampleWindow::on_menu_file_quit()
{
  hide(); //Closes the main window to stop the app->make_window_and_run().
}

void ExampleWindow::on_menu_file_files_dialog()
{
  if (!m_pDialog)
  {
    m_pDialog.reset(new Gtk::FileChooserDialog(*this, "Files",
      Gtk::FileChooser::Action::OPEN, /* use_header_bar= */ true));
    m_pDialog->set_transient_for(*this);
    m_pDialog->set_modal(true);
    m_pDialog->signal_response().connect(
      sigc::mem_fun(*this, &ExampleWindow::on_dialog_response));

    m_pDialog->add_button("Select File", Gtk::ResponseType::OK);
    m_pDialog->add_button("_Cancel", Gtk::ResponseType::CANCEL);
  }
  m_pDialog->show();
}

void ExampleWindow::on_dialog_response(int response_id)
{
  m_pDialog->hide();

  if (response_id == Gtk::ResponseType::OK)
  {
    auto selected_uri = m_pDialog->get_file()->get_uri();
    std::cout << "URI selected = " << selected_uri << std::endl;
    std::cout << (m_refRecentManager->has_item(selected_uri) ? "A" : "Not a")
      << " recently used file" << std::endl;
  }
}

ExampleWindow的构造函数使用Builder创建菜单和工具栏(更多有关信息请参阅Chapter 13 ― 菜单和工具栏)。然后将菜单和工具栏添加到窗口中。

20.2.2. 筛选文件

对于任意FileChooser类,如果你不想显示文件列表中的所有项目,你可以筛选列表以仅显示所需的项目。你可以使用FileFilter帮助你对列表进行筛选。这个类允许你按文件名(add_pattern())或MIME类型(add_mime_type())筛选文件。

创建并设置筛选器以使其只匹配你所需项目之后,你可以使用FileChooser::add_filter()函数将筛选器应用于你所选的部件。