Added a right click menu to the Window class so that portions of the window that don't have elements can still be right clicked

This commit is contained in:
PySimpleGUI 2021-07-24 14:57:25 -04:00
parent eff3dec028
commit 568bf6239b
1 changed files with 32 additions and 27 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3 #!/usr/bin/python3
version = __version__ = "4.45.0.23 Unreleased\nAdded autoscroll parameter to Multiline.print & cprint - defaults to True (backward compatible), ButtonMenu use font for button as menu font if none is supplied, make a copy of menu definition when making ButtonMenu, made menu definition optional for ButtonMenu so can change only some other settings, set class_ for Toplevel windows to fix problem with titles on some Linux systems, fix bug when menu shortcut char in first pos and item is disabled !&Item, Sizegrip - fixed expansion problem. Should not have expanded row, added kill application button to error popup. cprint & Multiline.print will now take a single color and use as text color, keep_on_top added to one_line_progress_meter. Deprication warning added to FindElement as first step of moving out of non-PEP8 world, added TabGroup.add_tab, allow modal window on the Mac again as an experiment. set cwd='.' if dir not found in execute_py_file, check for exists in execute_py_file, right_click_menu added to Radio Checkbox Tabgroup Spin Dlider. Elements that don't have a right_click_menu parm now pick up the default from the Window. Reformatted all docstrings to line up the desriptions for better readability. Added type and rtype to docstrings that were missing any entries. added stderr to Debug print if rerouting stdout. Updated all font entires in docstrings to include styles list, all elements updated to include expand_x and expand_y in the constructor! Added Window.perform_long_operation to automatically run users functions as threads. Fixed Text.get() was returning not the latest value when set by another element. Set cursor color to the same as the text color for Input Combo Spin Multiline Output. Another Sizegrip fix (LAST one... promise... egads...). Added echo_stdout to debug print so that stdout can be captured when run as a subprocess." version = __version__ = "4.45.0.24 Unreleased\nAdded autoscroll parameter to Multiline.print & cprint - defaults to True (backward compatible), ButtonMenu use font for button as menu font if none is supplied, make a copy of menu definition when making ButtonMenu, made menu definition optional for ButtonMenu so can change only some other settings, set class_ for Toplevel windows to fix problem with titles on some Linux systems, fix bug when menu shortcut char in first pos and item is disabled !&Item, Sizegrip - fixed expansion problem. Should not have expanded row, added kill application button to error popup. cprint & Multiline.print will now take a single color and use as text color, keep_on_top added to one_line_progress_meter. Deprication warning added to FindElement as first step of moving out of non-PEP8 world, added TabGroup.add_tab, allow modal window on the Mac again as an experiment. set cwd='.' if dir not found in execute_py_file, check for exists in execute_py_file, right_click_menu added to Radio Checkbox Tabgroup Spin Dlider. Elements that don't have a right_click_menu parm now pick up the default from the Window. Reformatted all docstrings to line up the desriptions for better readability. Added type and rtype to docstrings that were missing any entries. added stderr to Debug print if rerouting stdout. Updated all font entires in docstrings to include styles list, all elements updated to include expand_x and expand_y in the constructor! Added Window.perform_long_operation to automatically run users functions as threads. Fixed Text.get() was returning not the latest value when set by another element. Set cursor color to the same as the text color for Input Combo Spin Multiline Output. Another Sizegrip fix (LAST one... promise... egads...). Added echo_stdout to debug print so that stdout can be captured when run as a subprocess. Added a right click menu callback to cover portions of the window that don't have an element on them."
__version__ = version.split()[0] # For PEP 396 and PEP 345 __version__ = version.split()[0] # For PEP 396 and PEP 345
@ -8168,6 +8168,7 @@ class Window:
self.titlebar_icon = titlebar_icon self.titlebar_icon = titlebar_icon
self.right_click_menu_selected_colors = _simplified_dual_color_to_tuple(right_click_menu_selected_colors, self.right_click_menu_selected_colors = _simplified_dual_color_to_tuple(right_click_menu_selected_colors,
(self.right_click_menu_background_color, self.right_click_menu_text_color)) (self.right_click_menu_background_color, self.right_click_menu_text_color))
self.TKRightClickMenu = None
self._grab_anywhere_ignore_these_list = [] self._grab_anywhere_ignore_these_list = []
self._grab_anywhere_include_these_list = [] self._grab_anywhere_include_these_list = []
self._has_custom_titlebar = use_custom_titlebar self._has_custom_titlebar = use_custom_titlebar
@ -8192,6 +8193,7 @@ class Window:
"You will get the default theme or the one set in global settings\n" "You will get the default theme or the one set in global settings\n"
"If you seriously want this gray window and no more nagging, add theme('DefaultNoMoreNagging') or theme('Gray Gray Gray') for completely gray/System Defaults") "If you seriously want this gray window and no more nagging, add theme('DefaultNoMoreNagging') or theme('Gray Gray Gray') for completely gray/System Defaults")
@classmethod @classmethod
def _GetAContainerNumber(cls): def _GetAContainerNumber(cls):
""" """
@ -9911,6 +9913,31 @@ class Window:
return qsize != 0 return qsize != 0
def _RightClickMenuCallback(self, event):
"""
When a right click menu is specified for an entire window, then this callback catches right clicks
that happen to the window itself, when there are no elements that are in that area.
The only portion that is not currently covered correctly is the row frame itself. There will still
be parts of the window, at the moment, that don't respond to a right click. It's getting there, bit
by bit.
Callback function that's called when a right click happens. Shows right click menu as result.
:param event: information provided by tkinter about the event including x,y location of click
:type event:
"""
# if there are widgets under the mouse, then see if it's the root only. If not, then let the widget (element) show their menu instead
x, y = self.TKroot.winfo_pointerxy()
widget = self.TKroot.winfo_containing(x, y)
if widget != self.TKroot:
return
self.TKRightClickMenu.tk_popup(event.x_root, event.y_root, 0)
self.TKRightClickMenu.grab_release()
def perform_long_operation(self, func, end_key): def perform_long_operation(self, func, end_key):
""" """
Call your function that will take a long time to execute. When it's complete, send an event Call your function that will take a long time to execute. When it's complete, send an event
@ -12489,31 +12516,6 @@ def _fixed_map(style, style_name, option, highlight_colors=(None, None)):
return new_map return new_map
def _add_right_click_menu(element, toplevel_form):
if element.RightClickMenu == MENU_RIGHT_CLICK_DISABLED:
return
if element.RightClickMenu or toplevel_form.RightClickMenu:
menu = element.RightClickMenu or toplevel_form.RightClickMenu
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=toplevel_form.right_click_menu_tearoff, tearoffcommand=element._tearoff_menu_callback)
if toplevel_form.right_click_menu_background_color not in (COLOR_SYSTEM_DEFAULT, None):
top_menu.config(bg=toplevel_form.right_click_menu_background_color)
if toplevel_form.right_click_menu_text_color not in (COLOR_SYSTEM_DEFAULT, None):
top_menu.config(fg=toplevel_form.right_click_menu_text_color)
if toplevel_form.right_click_menu_disabled_text_color not in (COLOR_SYSTEM_DEFAULT, None):
top_menu.config(disabledforeground=toplevel_form.right_click_menu_disabled_text_color)
if toplevel_form.right_click_menu_font is not None:
top_menu.config(font=toplevel_form.right_click_menu_font)
if toplevel_form.right_click_menu_selected_colors[0] not in (COLOR_SYSTEM_DEFAULT, None):
top_menu.config(activeforeground=toplevel_form.right_click_menu_selected_colors[0])
if toplevel_form.right_click_menu_selected_colors[1] not in (COLOR_SYSTEM_DEFAULT, None):
top_menu.config(activebackground=toplevel_form.right_click_menu_selected_colors[1])
AddMenuItem(top_menu, menu[1], element, right_click_menu=True)
element.TKRightClickMenu = top_menu
element.Widget.bind('<Button-3>', element._RightClickMenuCallback)
# @_timeit # @_timeit
def PackFormIntoFrame(form, containing_frame, toplevel_form): def PackFormIntoFrame(form, containing_frame, toplevel_form):
""" """
@ -12621,11 +12623,14 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
top_menu.config(activebackground=toplevel_form.right_click_menu_selected_colors[1]) top_menu.config(activebackground=toplevel_form.right_click_menu_selected_colors[1])
AddMenuItem(top_menu, menu[1], element, right_click_menu=True) AddMenuItem(top_menu, menu[1], element, right_click_menu=True)
element.TKRightClickMenu = top_menu element.TKRightClickMenu = top_menu
if toplevel_form.RightClickMenu: # if the top level has a right click menu, then setup a callback for the Window itself
if toplevel_form.TKRightClickMenu is None:
toplevel_form.TKRightClickMenu = top_menu
toplevel_form.TKroot.bind('<Button-3>', toplevel_form._RightClickMenuCallback)
element.Widget.bind('<Button-3>', element._RightClickMenuCallback) element.Widget.bind('<Button-3>', element._RightClickMenuCallback)
def _add_expansion(element, row_should_expand, row_fill_direction): def _add_expansion(element, row_should_expand, row_fill_direction):
expand = True expand = True
if element.expand_x and element.expand_y: if element.expand_x and element.expand_y:
fill = tk.BOTH fill = tk.BOTH
row_fill_direction = tk.BOTH row_fill_direction = tk.BOTH