Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ########################################################################################################################
- # File: menus.py
- # Purpose: Creates a menubar with submenus for Tkinter GUI
- # Author: Dan Huckson, https://github.com/unodan
- # Date: 2018-05-23
- ########################################################################################################################
- from os import path, getcwd
- from tkinter import Menu, PhotoImage
- from importlib import import_module
- def sanitize_label(label):
- if label is None:
- return None, None
- position = label.find('&')
- if position >= 0:
- label = label[:position] + label[position + 1:]
- return label, position
- class MenuItem:
- def __init__(self, parent, key, item, **kwargs):
- self.__parent = parent
- self.__attributes = {}
- self.has_children = False
- self.__index = key
- label = self.__attributes['label'] = item.get('label', None)
- index = kwargs.get('index', None)
- state = self.__attributes['state'] = item.get('state', 'normal')
- image = self.__attributes['image'] = item.get('image', None)
- value = self.__attributes['value'] = item.get('value', None)
- command = self.__attributes['command'] = item.get('command', None)
- onvalue = self.__attributes['onvalue'] = item.get('onvalue', True)
- offvalue = self.__attributes['offvalue'] = item.get('offvalue', False)
- variable = self.__attributes['variable'] = item.get('variable', None)
- compound = self.__attributes['compound'] = item.get('compound', 'left')
- underline = self.__attributes['underline'] = item.get('underline', None)
- accelerator = self.__attributes['accelerator'] = item.get('accelerator', None)
- activeforeground = self.__attributes['activeforeground'] = kwargs.get('activeforeground', None)
- activebackground = self.__attributes['activebackground'] = kwargs.get('activebackground', None)
- if command:
- cmd = command.split('.')
- module = import_module(cmd[0])
- command = getattr(module, cmd[1], None)
- if image:
- image = self.image = PhotoImage(file=path.join(getcwd(), 'tkmenus', 'images', image))
- else:
- image = self.image = PhotoImage(file=path.join(getcwd(), 'tkmenus', 'images', 'blank-21x16.png'))
- widget_type = item.get('type', None)
- if widget_type == 'separator':
- func = parent.insert_separator if index else parent.add_separator
- func(index)
- elif widget_type == 'checkbutton':
- func = parent.insert_checkbutton if index else parent.add_checkbutton
- func(
- label=label,
- index=index,
- state=state,
- command=command,
- onvalue=onvalue,
- offvalue=offvalue,
- variable=variable,
- underline=underline,
- accelerator=accelerator,
- )
- elif widget_type == 'radiobutton':
- func = parent.insert_radiobutton if index else parent.add_radiobutton
- func(
- label=label,
- index=index,
- state=state,
- value=value,
- command=command,
- variable=variable,
- underline=underline,
- accelerator=accelerator,
- )
- else:
- func = parent.insert_command if index else parent.add_command
- func(
- label=label,
- index=index,
- state=state,
- image=image,
- command=command,
- compound=compound,
- underline=underline,
- accelerator=accelerator,
- activeforeground=activeforeground,
- activebackground=activebackground,
- )
- def cget(self, index):
- return self.__attributes.get(index, None)
- def config(self, **kwargs):
- fg = kwargs.get('fg', None)
- if fg:
- self.__attributes['fg'] = fg
- bg = kwargs.get('bg', None)
- if bg:
- self.__attributes['bg'] = bg
- font = kwargs.get('font', None)
- if font:
- self.__attributes['font'] = font
- label = kwargs.get('label', None)
- if label:
- self.__attributes['label'] = label
- image = kwargs.get('image', None)
- if image:
- self.__attributes['image'] = image
- state = kwargs.get('state', None)
- if state:
- self.__attributes['state'] = state
- underline = kwargs.get('underline', None)
- if underline:
- self.__attributes['underline'] = underline
- accelerator = kwargs.get('accelerator', None)
- if accelerator:
- self.__attributes['accelerator'] = accelerator
- activeforeground = kwargs.get('activeforeground', None)
- if activeforeground:
- self.__attributes['activeforeground'] = activeforeground
- activebackground = kwargs.get('activebackground', '#000000')
- if activebackground:
- self.__attributes['activebackground'] = activebackground
- print(kwargs)
- self.__parent.entryconfig(
- self.__index,
- font=font,
- label=label,
- image=image,
- state=state,
- compound='left',
- foreground=fg,
- background=bg,
- underline=underline,
- accelerator=accelerator,
- activeforeground=activeforeground,
- activebackground=activebackground,
- )
- class Menus(Menu):
- def __init__(self, parent, *args, **kwargs):
- super().__init__(parent, *args, **kwargs)
- self.items = {}
- self.__parent = parent
- self.__index = kwargs.pop('index', None)
- def menu(self, uri):
- def get_deep(menu, uri_part):
- parts = uri_part.split('/', 1)
- member = menu.get_child(parts[0])
- if len(parts) > 1:
- member = get_deep(member, parts[1])
- return member
- uri = uri.replace('\\', '/')
- if '/' in uri:
- return get_deep(self, uri)
- return self.items.get(path, None)
- def populate(self, children):
- for key, child in children.items():
- self.add_child(key, child)
- return self
- def add_child(self, key, child, **kwargs):
- bd = kwargs.pop('bd', self.cget('bd'))
- fg = kwargs.pop('fg', self.cget('fg'))
- bg = kwargs.pop('bg', self.cget('bg'))
- font = kwargs.pop('font', self.cget('font'))
- index = kwargs.pop('index', self.__index)
- tearoff = kwargs.pop('tearoff', self.cget('tearoff'))
- activeforeground = kwargs.pop('activeforeground', self.cget('activeforeground'))
- activebackground = kwargs.pop('activebackground', self.cget('activebackground'))
- func = SubMenu if 'children' in child else MenuItem
- self.items[key] = func(
- self,
- key,
- child,
- bd=bd,
- fg=fg,
- bg=bg,
- font=font,
- index=index,
- tearoff=tearoff,
- activeforeground=activeforeground,
- activebackground=activebackground,
- )
- def get_child(self, uri):
- def get_deep(menu, uri_part):
- if not menu:
- return None
- parts = uri_part.split('/', 1)
- member = menu.get_child(parts[0])
- if len(parts) > 1:
- member = get_deep(member, parts[1])
- return member
- uri = uri.replace('\\', '/')
- if '/' in uri:
- return get_deep(self, uri)
- return self.items.get(uri, None)
- def get_children(self):
- return self.items
- def has_children(self):
- return len(self.items)
- def config_children(self, **kwargs):
- bd = kwargs.pop('bd', None)
- fg = kwargs.pop('fg', None)
- bg = kwargs.pop('bg', None)
- font = kwargs.pop('font', None)
- relief = kwargs.pop('relief', None)
- activeforeground = kwargs.pop('activeforeground', None)
- activebackground = kwargs.pop('activebackground', None)
- def process(children):
- for index, child in children.items():
- if isinstance(child, MenuItem) and child.cget('widget_type') == 'separator':
- continue
- child.config(
- bd=bd,
- fg=fg,
- bg=bg,
- font=font,
- relief=relief,
- activeforeground=activeforeground,
- activebackground=activebackground,
- )
- if isinstance(child, SubMenu):
- process(child.get_children())
- process(self.get_children())
- class SubMenu(Menus):
- def __init__(self, parent, key, menu, *args, **kwargs):
- index = kwargs.pop('index', None)
- super().__init__(parent, *args, **kwargs)
- fg = kwargs.pop('fg', self.cget('fg'))
- bg = kwargs.pop('bg', self.cget('bg'))
- bd = kwargs.pop('bd', self.cget('bd'))
- font = kwargs.pop('font', self.cget('font'))
- tearoff = kwargs.pop('tearoff', self.cget('tearoff'))
- activeforeground = kwargs.pop('activeforeground', self.cget('activeforeground'))
- activebackground = kwargs.pop('activebackground', self.cget('activebackground'))
- label = menu.get('label', None)
- image = menu.get('image', None)
- state = menu.get('state', None)
- children = menu.get('children', None)
- compound = menu.get('compound', 'left')
- underline = menu.get('underline', None)
- if image:
- image = self.image = PhotoImage(file=path.join(getcwd(), 'tkmenus', 'images', image))
- elif isinstance(parent, SubMenu):
- image = self.image = PhotoImage(file=path.join(getcwd(), 'tkmenus', 'images', 'blank-21x16.png'))
- func = parent.add_cascade if index is None else parent.insert_cascade
- func(index, label=label, image=image, compound=compound, menu=self, state=state, underline=underline)
- for key, child in children.items():
- func = SubMenu if 'children' in child else MenuItem
- self.items[key] = func(
- self,
- key,
- child,
- bd=bd,
- fg=fg,
- bg=bg,
- font=font,
- tearoff=tearoff,
- activeforeground=activeforeground,
- activebackground=activebackground,
- )
- class MenuBar(Menus):
- def __init__(self, parent, *args, **kwargs):
- super().__init__(parent, *args, **kwargs)
- self.font = kwargs.get('font', None)
- self.items = {}
- self.menus = self.get_children()
- class PopupMenu(Menus):
- def __init__(self, parent, *args, **kwargs):
- super().__init__(parent, *args, **kwargs)
- tearoff = kwargs.pop('tearoff', 0)
- self.items = {}
- self.__leave = False
- self.__delay_destroy = 1000
- self.bind("<Enter>", self.on_enter)
- self.bind("<Leave>", self.on_leave)
- self.bind("<Escape>", self.on_escape)
- self.config(tearoff=tearoff)
- def on_enter(self, event):
- if event:
- self.__leave = False
- def on_leave(self, event):
- self.__leave = True
- def leave():
- if self.__leave:
- self.on_escape(event)
- self.after(self.__delay_destroy, leave)
- def on_escape(self, event):
- if event:
- self.unpost()
- self.__leave = False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement