Python Forum
Adding a sub menu to a ttk.OptionMrnue ?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Adding a sub menu to a ttk.OptionMrnue ?
#6
Maybe this is what you want. It is the same thing as before, but it uses OptionMenu to create the menu button and menu. Adding the submenu is done the same way as the previous example. Create a new menu. Add radio buttons for the options, Add the new menu to the existing menu using add_cascade.
import tkinter as tk
import tkinter.ttk as ttk


root = tk.Tk()
var = tk.StringVar(root, "One")
option_menu = ttk.OptionMenu(root, var, "One", "Two", "Three")
option_menu.pack()

# Create a new menu with radio buttons and add to OptionMenu["menu"]
imenu = option_menu["menu"]
submenu = tk.Menu(imenu, tearoff=False)
submenu.add_radiobutton(label="A", variable=var)
submenu.add_radiobutton(label="B", variable=var)
imenu.add_cascade(label="Four", menu=submenu)

var.trace_add("write", lambda a, b, c: print(var.get()))
root.mainloop()
And here it is written as a subclass.
class TackyOptionMenu(ttk.OptionMenu):
    def tack_on(self, label, *options):
        menu = self["menu"]
        var = self._variable  # This is the variable passed in when the OptionMenu was created.
        submenu = tk.Menu(menu, tearoff=False)  # Create the submenu
        for option in options:
            submenu.add_radiobutton(label=option, variable=var)  # Add the radio buttons
        menu.add_cascade(label=label, menu=submenu)  # Add submenu to menu.


root = tk.Tk()
var = tk.StringVar(root, "One")
option_menu = TackyOptionMenu(root, var, "One", "Two", "Three")
option_menu.tack_on("Four", "A", "B", "C")
option_menu.pack()

var.trace_add("write", lambda a, b, c: print(var.get()))
root.mainloop()
I don't like this approach as much as starting from scratch. You are limited to tacking on the submenu at the very end. I'd rather have total control of how the menus are populated.
import tkinter as tk
import tkinter.ttk as ttk


class CascadedOptionMenu(ttk.Menubutton):
    """An option menu with cascaded submenus."""
    def __init__(self, parent, options, variable=None, command=None, **kwargs):
        self.command = command
        super().__init__(parent, **kwargs)
        self.var = variable if variable else tk.StringVar(self, options[0])
        self.var.trace_add("write", self._select_cb)
        self.configure(textvariable=self.var)

        menu = tk.Menu(self, tearoff=False)
        self["menu"] = menu
        for option in options:
            if isinstance(option, str):
                menu.add_radiobutton(label=option, variable=self.var)
            else:
                label, *suboptions = option
                submenu = tk.Menu(self, tearoff=False)
                for option in suboptions:
                    submenu.add_radiobutton(label=option, variable=self.var)
                menu.add_cascade(label=label, menu=submenu)

    @property
    def value(self):
        """Return value."""
        return self.var.get()

    @value.setter
    def value(self, new_value):
        """Set value."""
        self.var.set(new_value)

    def _select_cb(self, *_):
        """Callback when selelction changes.  Calls command."""
        if self.command:
            self.command(self.value)


if __name__ == "__main__":
    root = tk.Tk()
    menu = CascadedOptionMenu(
        root,
        options=["One", ("Two", "A", "B"), "Three", ("Four", "C", "D")],
        command=print)
    menu.pack()
    root.mainloop()
Reply


Messages In This Thread
Adding a sub menu to a ttk.OptionMrnue ? - by Robo - Apr-16-2024, 10:31 AM
RE: Adding a sub menu to a ttk.OptionMrnue ? - by deanhystad - Apr-18-2024, 12:37 PM

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020