pythongtkpygobject

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.


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)