4

I would like to personalized a menu bar. For example I want to delete the border that appears around the tk.Menu widget (with the add_command() method) an image of what I want to delete

That's my code (I'm using Windows 10)

import tkinter as tk 
from tkinter import ttk

dark_grey = "#212121"
dark_blue="#102A43"
blue_1="#243B53"

root = tk.Tk()
root.state('zoomed')

container = tk.Frame(root, bg = dark_grey)
container.grid_rowconfigure(0, weight = 0)
container.grid_columnconfigure(0, weight = 1)

menu_frame = tk.Frame(container, bg = dark_blue)


menu1 = tk.Menubutton(menu_frame, text = "Menu1", bg = dark_blue, fg = 
                       "white", activebackground = blue_1, activeforeground = 
                       "white")
menu1.grid(row = 0, column = 0)

submenu1 = tk.Menu(menu1, tearoff = 0, bg = dark_blue, 
activebackground= blue_1, fg = "white",borderwidth = 0, activeborderwidth= 0)

submenu1.add_command(label = "Option 1.1")
submenu1.add_command(label = "Option 1.2")

menu1.configure(menu = submenu1)


menu_frame.grid(row = 0, column = 0, sticky = "ew")
container.pack(fill = tk.BOTH, expand = "True")
root.mainloop()

My idea is to create a menu without using tk.Menu and tk.MenuButton. I would like "bind" an <Enter> event to a label, in order to create a sort of drop down under the label. Is it possible?

stovfl
  • 14,998
  • 7
  • 24
  • 51
tsdev2k
  • 43
  • 5
  • Possible? Definitely. Simple? Probably not. It is worth noting that `Menu` uses the native OS's appearance so it will look consistent with other menus on the system. I would personally recommend not worrying to much about it since implementing your own menu will be more code and therefore more chance for functional bugs to improve just appearance. – Tadhg McDonald-Jensen Mar 17 '20 at 21:01
  • _"I would like "bind" an event to a label"_ - what's stopping you from doing that? – Bryan Oakley Mar 17 '20 at 21:05
  • I used a MenuButton with tk.Menu to make what is shown in the picture. The problem is that I have no idea how to let appear a window under a label (instead of the MenuButton) @BryanOakley – tsdev2k Mar 17 '20 at 21:16
  • 1
    @tsdev2k ***"I want to delete the border"***: use `menu.config(borderwidth=0, activeborderwidth=0)` – stovfl Mar 17 '20 at 22:03
  • it doesn't solve the problem, beacuse I want to delete the white border shown in the picture @stovfl – tsdev2k Mar 18 '20 at 12:36
  • @tsdev2k ***"I want to delete the white border "***: This is what `...borderwidth=0` is for. [Edit] your question and show the code of your attempt. Also tell which `theme` and which `OS` you are using. – stovfl Mar 18 '20 at 12:46
  • @stovfl I add my code and the result is what you see in the picture – tsdev2k Mar 19 '20 at 11:45
  • @tsdev2k ***"Windows 10"***: Seems a *Windows* issue as it works for me using `X`. Do `print(submenu1.config())` and verify there are **2** `*borderwidth` entries and both with a value of `0`. – stovfl Mar 19 '20 at 13:16
  • @stovfl there is only one `borderwidth`. It might be a Windows issue. Thanks anyway – tsdev2k Mar 19 '20 at 14:36

1 Answers1

5

Question: Customized menu bar without using the widget tk.Menu?

This example uses a tk.Toplevel as a popup window and displays the added tk.Menubutton.
The Submenu follows ths defined Style of the Top tk.Menubutton.


TODO:

  • Close the Popup Window if clicked outside or another Top Menubutton.
  • Extend with other than only tk.Menubutton
  • Keyboard support

import tkinter as tk


class Menu:
    def __init__(self, parent, **kwargs):
        self._popup = None
        self._menubutton = []
        self.parent = parent

        self.parent.bind('<Button-1>', self.on_popup)

    def on_popup(self, event):
        w = event.widget
        x, y, height = self.parent.winfo_rootx(), self.parent.winfo_rooty(), self.parent.winfo_height()

        self._popup = tk.Toplevel(self.parent.master, bg=self.parent.cget('bg'))
        self._popup.overrideredirect(True)
        self._popup.geometry('+{}+{}'.format(x, y + height))

        for kwargs in self._menubutton:
            self._add_command(**kwargs)

    def add_command(self, **kwargs):
        self._menubutton.append(kwargs)

    def _add_command(self, **kwargs):
        command = kwargs.pop('command', None)

        menu = self.parent
        mb = tk.Menubutton(self._popup, text=kwargs['label'],
                           bg=menu.cget('bg'),
                           fg=menu.cget('fg'),
                           activebackground=menu.cget('activebackground'),
                           activeforeground=menu.cget('activeforeground'),
                           borderwidth=0,
                           )
        mb._command = command
        mb.bind('<Button-1>', self._on_command)
        mb.grid()

    def _on_command(self, event):
        w = event.widget
        print('_on_command("{}")'.format(w.cget('text')))

        self._popup.destroy()

        if w._command is not None:
            w._command()

Usage:

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry("200x200")

        style = {'bg': "#102A43", 'fg': "white", 
                 'activebackground': "#243B53", 'activeforeground': "white",
                 'borderwidth': 0}

        menu1 = tk.Menubutton(self, text="Menu1", **style)
        submenu1 = Menu(menu1)
        submenu1.add_command(label="Option 1.1")
        submenu1.add_command(label="Option 1.2")
        menu1.grid(row=0, column=0)

        menu2 = tk.Menubutton(self, text="Menu2", **style)
        submenu2 = Menu(menu2)
        submenu2.add_command(label="Option 2.1")
        submenu2.add_command(label="Option 2.2")
        menu2.grid(row=0, column=2)


if __name__ == "__main__":
    App().mainloop()

Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6

stovfl
  • 14,998
  • 7
  • 24
  • 51
  • Thank you. I'll try to complete it. – tsdev2k Mar 19 '20 at 20:01
  • @tsdev2k Read [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – stovfl Mar 28 '20 at 09:45
  • `overrideredirect` makes it impossible to catch `` events on child windows. You should catch the focus event of other widgets the root window has. I think even if the root window is `overrideredirect`'d, it still supports the `` event. – Tigran Aug 25 '23 at 11:44