Search code examples
pythongtkpygobject

PyGObject: How to create hamburger menu programmatically


I would like to create a "primary menu" programmatically, which I believe is also called a "hamburger menu". I have done several of these while working on web development side, but I have never done these using Python and GTK. This topic seems to be controversial and there are a lot of different solutions out there. I would like to create a menu like this using the non-deprecated way.

In the documentation is mentioned that the old style menus are deprecated (the whole section is archived under "deprecated"): https://python-gtk-3-tutorial.readthedocs.io/en/latest/menus.html

In this example, the whole HeaderBar is made programmatically and a (popover) menu is added into it: GtkMenuButton popups

While that seems to do the trick, it's not a "hamburger" menu and the documentation seems to suggest "Your menus should be defined in XML using Gio.Menu": https://python-gtk-3-tutorial.readthedocs.io/en/latest/application.html#menus

So I am quite lost here. Can someone give me an example how to achieve this? Preferably done programmatically, but if the XML is the only way then so be it.

Thanks in advance!


Solution

  • I post my solution that I was able to do with the kind help from irc.gnome.org #python channel. It's not perfect, menu actions are still not working, but at least I got the menu done which was the point of this post.

    #!/usr/bin/env python3
    
    # Python imports
    import sys
    
    # GTK imports
    import gi
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gio
    from gi.repository import Gtk
    
    class AppWindow(Gtk.ApplicationWindow):
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            self.set_border_width(10)
            self.set_default_size(640, 480)
    
            open_selection = Gtk.ModelButton(action_name="open_file", label="Open")
            about_selection = Gtk.ModelButton(action_name="about_application", label="About")
    
            vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, margin=10, spacing=10)
            vbox.add(open_selection)
            vbox.add(about_selection)
            vbox.show_all()
    
            self.popover = Gtk.Popover()
            self.popover.add(vbox)
            self.popover.set_position(Gtk.PositionType.BOTTOM)
    
            menu_button = Gtk.MenuButton(popover=self.popover)
            menu_icon = Gtk.Image.new_from_icon_name("open-menu-symbolic", Gtk.IconSize.MENU)
            menu_icon.show()
            menu_button.add(menu_icon)
            menu_button.show()
    
            headerbar = Gtk.HeaderBar()
            headerbar.props.show_close_button = True
            headerbar.props.title = "Hamburger Menu Demo"
            headerbar.add(menu_button)
            headerbar.show()
            self.set_titlebar(headerbar)
    
        def open_file(self, widget):
            print("Open file")
    
    class Application(Gtk.Application):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, application_id="org.example.myapp")
            self.window = None
    
        def do_startup(self):
            Gtk.Application.do_startup(self)
    
            action = Gio.SimpleAction.new("open_file", None)
            action.connect("activate", self.open_file)
            action.set_enabled(True)
            self.add_action(action)
    
            action = Gio.SimpleAction.new("about_application", None)
            action.connect("activate", self.on_about)
            self.add_action(action)
    
            action = Gio.SimpleAction.new("quit", None)
            action.connect("activate", self.on_quit)
            self.add_action(action)
    
        def do_activate(self):
            # We only allow a single window and raise any existing ones
            if not self.window:
                # Windows are associated with the application
                # when the last one is closed the application shuts down
                self.window = AppWindow(application=self, title="Main Window")
    
            self.window.present()
    
        def open_file(self, action, param):
            print("Open file")
    
        def on_about(self, action, param):
            print("About application")
    
        def on_quit(self, action, param):
            self.quit()
    
    
    if __name__ == "__main__":
        app = Application()
        app.run(sys.argv)