如何将继承Gio::Menu的自定义类用于Gtk::Window界面?
代码示例
class XMenu: public Gio::Menu { public: XMenu(); }; class App : public Gtk::Window { public: App(); protected : Gtk::Button btn; XMenu menu; }; XMenu::XMenu() { append("option1", "app.option1"); append("Quit", "app.quit"); } App::App() { set_default_size(600,600); btn.set_label("Hello"); //auto casted_menu = dynamic_cast<Gtk::Widget&>(menu); set_child(casted_menu); }
编译错误
main.cc:33:19: error: cannot convert ‘XMenu’ to ‘Gtk::Widget&’ 33 | set_child(menu); | ^~~~ | | | XMenu
问题根源
Gio::Menu 是纯数据模型类,仅负责定义菜单的结构和动作关联,不属于Gtk::Widget的继承体系,因此无法直接通过set_child()添加到窗口。Gtk中负责菜单UI渲染的是Gtk::MenuBar(顶部菜单栏)或Gtk::PopoverMenu(弹出式菜单)这类控件,需要将Gio::Menu绑定到这些控件上才能在界面中展示。
解决方案
根据需求选择以下两种实现方式:
方式1:创建顶部菜单栏(Gtk::MenuBar)
修改App类,用垂直容器布局菜单栏与其他控件,将自定义XMenu绑定到Gtk::MenuBar后添加到窗口:
#include <gtkmm.h> class XMenu: public Gio::Menu { public: XMenu(); }; class App : public Gtk::Window { public: App(); protected : Gtk::Box vbox; Gtk::MenuBar menubar; XMenu menu; }; XMenu::XMenu() { append("option1", "app.option1"); append("Quit", "app.quit"); } App::App() { set_default_size(600,600); set_child(vbox); // 将Gio::Menu绑定到MenuBar,完成可视化转换 menubar.set_menu_model(menu); vbox.append(menubar); // 可继续添加其他控件到布局容器 Gtk::Button btn("Hello"); vbox.append(btn); } int main(int argc, char* argv[]) { auto app = Gtk::Application::create("app.example"); return app->make_window_and_run<App>(argc, argv); }
方式2:创建触发式弹出菜单(Gtk::PopoverMenu)
如果需要通过按钮点击弹出菜单,可使用这种方式:
#include <gtkmm.h> class XMenu: public Gio::Menu { public: XMenu(); }; class App : public Gtk::Window { public: App(); protected : Gtk::Button btn; Gtk::PopoverMenu popover; XMenu menu; void on_button_clicked(); }; XMenu::XMenu() { append("option1", "app.option1"); append("Quit", "app.quit"); } void App::on_button_clicked() { popover.popup(); } App::App() { set_default_size(600,600); set_child(btn); btn.set_label("Hello"); btn.signal_clicked().connect(sigc::mem_fun(*this, &App::on_button_clicked)); // 将Gio::Menu绑定到PopoverMenu popover.set_menu_model(menu); popover.set_parent(btn); // 关联触发源为按钮 } int main(int argc, char* argv[]) { auto app = Gtk::Application::create("app.example"); return app->make_window_and_run<App>(argc, argv); }
关键提示
- 动态转换无效的核心原因:
Gio::Menu和Gtk::Widget属于完全独立的类体系,没有继承关系,无法互相转换。 - 所有Gio库中的模型类都需要对应Gtk控件完成可视化,这是Gtk+的模型-视图分离设计逻辑。
内容的提问来源于stack exchange,提问作者misha
相关产品推荐
相关产品推荐

