如何在运行时从 Glade 定义添加 Gtk::笔记本选项卡

How do you add Gtk::Notebook tabs at runtime from Glade definitions?

本文关键字:Gtk 笔记本 选项 添加 定义 运行时 Glade      更新时间:2023-10-16

我正在创建一个新的GTK应用程序(使用gtkmm),主界面是选项卡式的,有点像Web浏览器。

我想为用户打开的每个文档创建一个新选项卡,每个选项卡的内容由 Glade 定义。 我是 gtkmm 的新手,所以我不确定该怎么做。

如果我将 Glade 中的选项卡设计为一个独立的窗口,当我调用 Gtk::Builder::get_widget() 时它会返回一个指向Gtk::Window的指针,但我不能将其传递给Gtk::Notebook::append_page()因为该函数需要引用并且我只有一个指针。 我不想取消引用指针,因为我相信每次调用get_widget()都会返回相同的指针 - 所以如果我想添加五个相同的页面,我需要在将其添加到Gtk::Notebook之前以某种方式克隆 UI 结构 - 否则更改一个选项卡上的 UI 元素也会导致它在其他四个选项卡上更改,因为它们都指向相同的 UI 小部件。

采用在 Glade 中设计的窗口并将其动态多次添加到Gtk::Notebook的最佳方法是什么?


编辑:

将每个选项卡的定义放入单独的*.glade文件中确实允许我加载多个实例,以便该部分都很好。

但是我仍然无法将加载的结构添加到Gtk::Notebook

  • 如果我告诉Gtk::Builder::get_widget().glade文件中检索根Gtk::Window并将其添加为新选项卡,它将不会编译,因为我必须将Gtk::Widget传递给append_page()并且它不会接受Gtk::Window参数。
  • 如果我告诉它选择最上面的小部件,那么我会收到一堆运行时错误:

    Can't set a parent on widget which has a parent
    gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `tab-expand'
    gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `tab-fill'
    gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `tab-label'
    gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `menu-label'
    gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `position'
    Gtk:ERROR:gtkcontainer.c:3541:gtk_container_propagate_draw: assertion failed: (gtk_widget_get_parent (child) == GTK_WIDGET (container))
    Aborted (core dumped)
    
  • 如果我使用最上面的小部件,而是调用reparent()并将Gtk::Notebook作为新的父项传递,那么新选项卡确实会显示所有正确排列的小部件,但是我无法控制选项卡的标题。

一定有一个"正确"的方法可以做到这一点,我只是想不通它是什么!

感谢gtkmm邮件列表的帮助,我有了解决方案。

在 Glade 中,我创建了一个包含单个Gtk::BoxGtk::Window,并将我所有的控件都放在Box中。 这在尝试将Box添加为新选项卡时会导致问题,因为Box已经有一个父选项卡(Gtk::Window),因此尝试将Gtk::Notebook为新的父选项卡很麻烦。

相反,我发现您可以右键单击 Glade 中Gtk::Box的按钮,然后选择"将小部件添加为顶级"。 这样就根本不需要Gtk::Window,而且由于Box没有父级,打电话给Gtk::Notebook::append_page()并通过Gtk::Box就可以完美地工作了。 然后,我可以使用 append_page() 的变体,让我同时设置选项卡的标题。

但是,仍然需要创建新的Gtk::Builder实例来加载每个选项卡的控件,因为每个选项卡都需要控件的新实例。 如果只是对同一对象继续调用Gtk::Builder::get_widget(),它将返回控件的相同实例。

通常,您应该首先在 Glade 中制作 GUI 的布局,包括窗口、笔记本和/或其他嵌套小部件。 如果你想要不同的选项卡,那么你也可以在 Glade 中制作它们,但作为不嵌套在顶级窗口中的单独对象。 保存.xml文件并将其加载到程序中。

将您的小部件声明为指针,使用 nullptr 初始化,并使用类似这样的东西来访问您在 Glade 中创建的小部件:

 m_refBuilder->get_widget("my_tabbox00", m_pTab00);

现在,您可以将(Glade id)my_tabbox00用作(C++)指针m_pTab00。 只要确保my_tabbox00在格莱德没有父级,它可以包含孩子。 您还可以将 get_widget() 用于笔记本和视口(即使小部件具有父级)。 要追加页面,您可以使用:

m_pNotebook->append_page(*m_pViewport00, *m_pTab00);
请注意,此解决方案会稍微限制您,

因为对于每个选项卡,您必须在 Glade 中创建一个新选项卡和视口。 也许更好的方法是尝试为选项卡创建一个类并为此使用多个对象。