Merge pull request #4300 from PySimpleGUI/Dev-latest

Dev latest
This commit is contained in:
PySimpleGUI 2021-05-20 15:07:20 -04:00 committed by GitHub
commit cafdc42b3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 81 deletions

View File

@ -1,92 +1,73 @@
#!/usr/bin/env python
import PySimpleGUI as sg
"""
Demo - A Custom Menubar Element Simulated Using ButtonMenu Elements
Demo - The MenubarCustom element
With the addition of the Custom Titlebar came the addition of a problem with the
os provided menubar. It's not possible to use the custom titlebar with the
normal menubar. The menubar ends up being placed above the titlebar.
Enter the MenubarCustom!
This "Compound Element" is not really an element but rather a combination of
ButtonMenu elements and Column elements. It's possible for users to create a similar
construct. In fact, this element started as a Demo Program and then migrated into PySimpleGUI.
Because a Menubar is created by the OS and not the underlying GUI framework, the
ability to customize the look and feel of the standard Menubar is not possible.
Additionally, the Titlebar Element and the Meny Element don't work well together.
The order gets swapped.
One way to get around all of the problems above is to simulate a Menu Element.
That's exactly what this demo does.
At the moment, you cannot perform all of the same operations using this custom menubar
that you can with a traditional menubar. Modifying the menu isn't possible yet. In
other words, it's a great start, but more work is needed such as adding an update method, etc.
For statically defined menus, it works great. Shortuts are possible within the menus, but not
for the initial selection.
You can use the same menu defition as the standard Menu element.
The Menubar will tbe themed according to your current theme's colors. The theme's button
colors are used. All of the colors can be changed from the menubar to the menu's text an background.
The disabled color has a problem. The default tkinter gray is used even though PySimpleGUI sets the value.
The color choice for the menubar background and text use the theme's button colors.
You can change these color choices by changing the Menubar in the layout.
Copyright 2021 PySimpleGUI
"""
sg.MENU_SHORTCUT_CHARACTER = '&'
def Menubar(menu_def, text_color, background_color, pad=(0, 0)):
"""
A User Defined element that simulates a Menu element by using ButtonMenu elements
:param menu_def: A standard PySimpleGUI menu definition
:type menu_def: List[List[Tuple[str, List[str]]]
:param text_color: color for the menubar's text
:type text_color:
:param background_color: color for the menubar's background
:type background_color:
:param pad: Amount of padding around each menu entry
:type pad:
:return: A column element that has a row of ButtonMenu buttons
:rtype: sg.Column
"""
row = []
for menu in menu_def:
text = menu[0]
if sg.MENU_SHORTCUT_CHARACTER in text:
text = text.replace(sg.MENU_SHORTCUT_CHARACTER, '')
if text.startswith(sg.MENU_DISABLED_CHARACTER):
disabled = True
text = text[len(sg.MENU_DISABLED_CHARACTER):]
else:
disabled = False
row += [sg.ButtonMenu(text, menu, border_width=0, button_color=f'{text_color} on {background_color}',key=text, pad=pad, disabled=disabled)]
return sg.Column([row], background_color=background_color, pad=(0,0), expand_x=True)
def main():
sg.theme('dark green 7')
# sg.theme('dark gray 14')
# sg.theme('dark gray 13')
sg.theme('dark red')
# sg.theme('black')
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ],
['!Disabled', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ],
['&Edit', ['Me', 'Special', 'Normal',['Normal1', 'Normal2'] , 'Undo']],
['!Disabled', ['Special', 'Normal',['Normal1', 'Normal2'], 'Undo']],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
['&Help', ['&About...']], ]
layout = [
# [sg.Menu(menu_def, tearoff=False, key='-MENU BAR-')], # This is how a Menu is normally defined
[Menubar(menu_def, sg.theme_button_color()[1], sg.theme_button_color()[0], (5, 0))],
[sg.Multiline(size=(70, 20), reroute_stdout=True, reroute_cprint=True, write_only=True)],
]
layout = [[sg.MenubarCustom(menu_def, pad=(0,0), k='-CUST MENUBAR-')],
[sg.Multiline(size=(70, 20), reroute_cprint=True, write_only=True, no_scrollbar=True, k='-MLINE-')]]
window = sg.Window("Custom Titlebar with Custom (Simulated) Menubar", layout, use_custom_titlebar=True)
window = sg.Window("Custom Titlebar with Custom (Simulated) Menubar", layout, use_custom_titlebar=True, keep_on_top=True)
# ------ Event Loop ------ #
while True:
event, values = window.read()
# convert ButtonMenu event so they look like Menu events
elem = window.find_element(event, silent_on_error=True)
if elem and elem.Type == sg.ELEM_TYPE_BUTTONMENU:
event = values[event]
if event in (sg.WIN_CLOSED, 'Exit'):
break
sg.cprint(f'event = {event}', c='white on red')
sg.cprint(f'values = {values}', c='white on green')
sg.cprint(f'event = {event}', c=(sg.theme_background_color(), sg.theme_text_color()))
sg.cprint(f'values = {values}',c=(sg.theme_input_text_color(), sg.theme_input_background_color()))
# ------ Process menu choices ------ #
if event == 'About...':
window.disappear()
sg.popup('About this program', 'Simulated Menubar to accompany a simulated Titlebar',
'PySimpleGUI Version', sg.version, grab_anywhere=True, keep_on_top=True)
'PySimpleGUI Version', sg.get_versions(), grab_anywhere=True, keep_on_top=True)
window.reappear()
elif event == 'Me':
sg.execute_editor(__file__)
elif event.startswith('Open'):
filename = sg.popup_get_file('file to open', no_window=True)
print(filename)

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3
version = __version__ = "4.41.2.3 Unreleased\nFix for getting wrong tab number in Tab.update, added bind_return_key to Combo Element, new Sizegrip element, fixed grab_anywhere so that it doesn't grab multiline slider scrollbars input and a few other elements, changed Sizegrip parm to be grip_image which can be a filename or a bytestring, added a white sizegrip image in addition to the default black, improved tearoff menu placement, completed the MenubarCustom code (to Alpha quality perhaps)"
version = __version__ = "4.41.2.4 Unreleased\nFix for getting wrong tab number in Tab.update, added bind_return_key to Combo Element, new Sizegrip element, fixed grab_anywhere so that it doesn't grab multiline slider scrollbars input and a few other elements, changed Sizegrip parm to be grip_image which can be a filename or a bytestring, added a white sizegrip image in addition to the default black, improved tearoff menu placement, completed the MenubarCustom code including color settings for the bar and the menus"
__version__ = version.split()[0] # For PEP 396 and PEP 345
@ -10402,17 +10402,13 @@ def Titlebar(title='',icon=None, text_color=None, background_color=None, font=No
# Not ready for prime time
def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font=None, tearoff=False, pad=None, bar_background_color=None, bar_text_color=None, key=None, k=None):
def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font=None, tearoff=False, pad=None, background_color=None, text_color=None, bar_background_color=None, bar_text_color=None, key=None, k=None):
"""
A custom Menubar that replaces the OS provided Menubar
THIS FEATURE IS NOT YET COMPLETE!
Why?
Two reasons - 1. they look great (see custom titlebar) 2. if you have a custom titlebar, then you have to use a custom menubar if you want a menubar
NOTE LINUX USERS - at the moment the minimize function is not yet working. Windows users
should have no problem and it should function as a normal window would.
:param menu_definition: The Menu definition specified using lists (docs explain the format)
:type menu_definition: List[List[Tuple[str, List[str]]]
:param disabled_text_color: color to use for text when item is disabled. Can be in #RRGGBB format or a color name "black"
@ -10425,33 +10421,27 @@ def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font
:type tearoff: (bool)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param background_color: color to use for background of the menus that are displayed after making a section. Can be in #RRGGBB format or a color name "black". Defaults to the color of the bar text
:type background_color: (str)
:param text_color: color to use for the text of the many items in the displayed menus. Can be in #RRGGBB format or a color name "black". Defaults to the bar background
:type text_color: (str)
:param bar_background_color: color to use for the menubar. Can be in #RRGGBB format or a color name "black". Defaults to theme's button text color
:type bar_background_color: (str)
:param bar_text_color: color to use for the menu items text when item is disabled. Can be in #RRGGBB format or a color name "black". Defaults to theme's button background color
:type bar_text_color: (str)
:param key: Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window
:type key: str | int | tuple | object
:param k: Same as the Key. You can use either k or key. Which ever is set will be used.
:type k: str | int | tuple | object
:param visible: set visibility state of the element
:type visible: (bool)
:param metadata: User metadata that can be set to ANYTHING
:type metadata: (Any)
:returns: A Column element that has a series of ButtonMenu elements
:rtype: Column
"""
#
# row = []
# for menu in menu_def:
# text = menu[0]
# if sg.MENU_SHORTCUT_CHARACTER in text:
# text = text.replace(sg.MENU_SHORTCUT_CHARACTER, '')
# if text.startswith(sg.MENU_DISABLED_CHARACTER):
# disabled = True
# text = text[len(sg.MENU_DISABLED_CHARACTER):]
# else:
# disabled = False
# row += [sg.ButtonMenu(text, menu, border_width=0, button_color=f'{text_color} on {background_color}',key=text, pad=pad, disabled=disabled)]
#
# return sg.Column([row], background_color=background_color, pad=(0,0), expand_x=True)
#
bar_bg = bar_background_color if bar_background_color is not None else theme_button_color()[0]
bar_text = bar_text_color if bar_text_color is not None else theme_button_color()[1]
menu_bg = background_color if background_color is not None else bar_text
menu_text = text_color if text_color is not None else bar_bg
row = []
for menu in menu_definition:
text = menu[0]
@ -10463,7 +10453,8 @@ def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font
else:
disabled = False
button_menu = ButtonMenu(text, menu, border_width=0, button_color=(bar_text, bar_bg), key=text, pad=(0,0), disabled=disabled, font=bar_font, item_font=font, disabled_text_color=disabled_text_color, text_color=bar_bg, background_color=bar_text, tearoff=tearoff)
button_menu = ButtonMenu(text, menu, border_width=0, button_color=(bar_text, bar_bg), key=text, pad=(0,0), disabled=disabled, font=bar_font, item_font=font, disabled_text_color=disabled_text_color, text_color=menu_text, background_color=menu_bg, tearoff=tearoff)
button_menu.part_of_custom_menubar = True
button_menu.custom_menubar_key = key if key is not None else k
row += [button_menu]