Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 80 additions & 44 deletions PySimpleGUI.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python3

version = __version__ = "4.59.0.16 Released 5-Apr-2022"
version = __version__ = "4.59.0.21 Released 5-Apr-2022"

_change_log = """
Changelog since 4.59.0 released to PyPI on 5-Apr-2022
Expand Down Expand Up @@ -64,6 +64,22 @@
Made the ttk scrollbar settings tab look nicer
4.59.0.16
Added button to test ttk scrollbar settings within the System Settings window. Aids in changing the design if scrollbar colors, sizes, etc.
4.59.0.17
Noted tricky problem - if "always use custom titlebar" is set in system settings, then USER still needs to account for this in their layout
That means using the MenubarCustom instaed of Menu. For now, user will have to handle this. Will come back to it to fix up later
Made MenubarCustom have a pad=0 by default so that it's snug under the titlebar and extends to edges correctly.
Renamed ttk scrollbar system settings tab to ttk
4.59.0.18
Got the Debug Print stuff working right! YES!
Added new parm "wait" which is an alias for the "blocking" parm. Some may like it better. Take your choice
Changed button text to "Click to continue" if the blocking/wait parm is set so that it's obvious that your program is waiting on you
4.59.0.19
OK... this time got the Debug Prit stuff working right for real! YES? ;-)
4.59.0.20
irony - when you accidently leave debug prints in your debug print code
4.59.0.21
Additional exception handling needed for debug window closure at any point

"""

__version__ = version.split()[0] # For PEP 396 and PEP 345
Expand Down Expand Up @@ -8337,7 +8353,6 @@ def __init__(self, menu_definition, background_color=None, text_color=None, disa
:param metadata: User metadata that can be set to ANYTHING
:type metadata: (Any)
"""

self.BackgroundColor = background_color if background_color is not None else theme_input_background_color()
self.TextColor = text_color if text_color is not None else theme_input_text_color()

Expand Down Expand Up @@ -11888,22 +11903,22 @@ def read_all_windows(timeout=None, timeout_key=TIMEOUT_KEY):

return window, event, values


###### ## ## ###### ######## ######## ## ##
## ## ## ## ## ## ## ## ### ###
## #### ## ## ## #### ####
###### ## ###### ## ###### ## ### ##
## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ##
###### ## ###### ## ######## ## ##

######## ######## ### ## ##
## ## ## ## ## ## ##
## ## ## ## ## ####
## ######## ## ## ##
## ## ## ######### ##
## ## ## ## ## ##
## ## ## ## ## ##
# MP""""""`MM dP
# M mmmmm..M 88
# M. `YM dP dP .d8888b. d8888P .d8888b. 88d8b.d8b.
# MMMMMMM. M 88 88 Y8ooooo. 88 88ooood8 88'`88'`88
# M. .MMM' M 88. .88 88 88 88. ... 88 88 88
# Mb. .dM `8888P88 `88888P' dP `88888P' dP dP dP
# MMMMMMMMMMM .88
# d8888P
# M""""""""M
# Mmmm mmmM
# MMMM MMMM 88d888b. .d8888b. dP dP
# MMMM MMMM 88' `88 88' `88 88 88
# MMMM MMMM 88 88. .88 88. .88
# MMMM MMMM dP `88888P8 `8888P88
# MMMMMMMMMM .88
# d8888P

# ------------------------------------------------------------------------- #
# SystemTray - class for implementing a psyeudo tray #
Expand Down Expand Up @@ -12378,8 +12393,7 @@ def Titlebar(title='', icon=None, text_color=None, background_color=None, font=N
background_color=bc, pad=(0, 0), metadata=TITLEBAR_METADATA_MARKER, key=key)


# Not ready for prime time
def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font=None, tearoff=False, pad=None, p=None, background_color=None, text_color=None,
def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font=None, tearoff=False, pad=0, p=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
Expand All @@ -12397,7 +12411,7 @@ def MenubarCustom(menu_definition, disabled_text_color=None, bar_font=None, font
:type font: (str or (str, int[, str]) or None)
:param tearoff: if True, then can tear the menu off from the window ans use as a floating window. Very cool effect
:type tearoff: (bool)
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int)
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int). TIP - 0 will make flush with titlebar
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
:param p: Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used
:type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
Expand Down Expand Up @@ -17234,12 +17248,12 @@ def __init__(self, size=(None, None), location=(None, None), relative_location=(
else:
self.quit_button = DummyButton('Quit', key='Quit')
self.layout = [[self.output_element],
[pin(self.quit_button), B('Pause', key='-PAUSE-'), Stretch()]]
[pin(self.quit_button), pin(B('Pause', key='-PAUSE-')), Stretch()]]

self.layout[-1] += [Sizegrip()]

self.window = Window('Debug Window', self.layout, no_titlebar=no_titlebar, auto_size_text=True, location=location, relative_location=relative_location,
font=font or ('Courier New', 10), grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, finalize=False, resizable=resizable)
font=font or ('Courier New', 10), grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, finalize=True, resizable=resizable)
return

def Print(self, *args, end=None, sep=None, text_color=None, background_color=None, erase_all=False, font=None, blocking=None):
Expand All @@ -17254,14 +17268,9 @@ def Print(self, *args, end=None, sep=None, text_color=None, background_color=Non
do_not_reroute_stdout=self.do_not_reroute_stdout, resizable=self.resizable, echo_stdout=self.echo_stdout, blocking=blocking)

timeout = 0 if not blocking else None
event, values = self.window.read(timeout=0)
if event == 'Quit' or event is None:
self.Close()
self.__init__(size=self.size, location=self.location, relative_location=self.relative_location, font=self.font, no_titlebar=self.no_titlebar,
no_button=self.no_button, grab_anywhere=self.grab_anywhere, keep_on_top=self.keep_on_top,
do_not_reroute_stdout=self.do_not_reroute_stdout, resizable=self.resizable, echo_stdout=self.echo_stdout, blocking=blocking)
if erase_all:
self.window['-MULTILINE-'].update('')
self.output_element.update('')

if self.do_not_reroute_stdout:
end_str = str(end) if end is not None else '\n'
sep_str = str(sep) if sep is not None else ' '
Expand All @@ -17273,27 +17282,45 @@ def Print(self, *args, end=None, sep=None, text_color=None, background_color=Non
if i != num_args - 1:
outstring += sep_str
outstring += end_str

self.output_element.update(outstring, append=True, text_color_for_value=text_color, background_color_for_value=background_color, font_for_value=font)
else:
print(*args, sep=sepchar, end=endchar)
# This is tricky....changing the button type depending on the blocking parm. If blocking, then the "Quit" button should become a normal button
if blocking and blocking != self.blocking:
if blocking:
self.quit_button.BType = BUTTON_TYPE_READ_FORM
self.quit_button.update(text='More')
elif blocking != self.blocking:
try: # The window may be closed by user at any time, so have to protect
self.quit_button.update(text='Click to continue...')
except:
pass
else:
self.quit_button.BType = BUTTON_TYPE_CLOSES_WIN_ONLY
self.quit_button.update(text='Quit')
try: # The window may be closed by user at any time, so have to protect
self.quit_button.update(text='Quit')
except:
pass

try: # The window may be closed by user at any time, so have to protect
if blocking:
self.window['-PAUSE-'].update(visible=False)
else:
self.window['-PAUSE-'].update(visible=True)
except:
pass

paused = None
while True:
if event == WIN_CLOSED or (not blocking and event == 'Quit'):
paused = False
event, values = self.window.read(timeout=timeout)

if event == WIN_CLOSED:
self.Close()
break
elif blocking and event == 'Quit':
break
elif not paused and event == TIMEOUT_EVENT and not blocking:
break
elif event == '-PAUSE-':
if blocking: # if blocking, ignore the pause button entirely
continue
if paused:
self.window['-PAUSE-'].update(text='Pause')
self.quit_button.update(visible=True)
Expand All @@ -17302,7 +17329,6 @@ def Print(self, *args, end=None, sep=None, text_color=None, background_color=Non
self.window['-PAUSE-'].update(text='Resume')
self.quit_button.update(visible=False)
timeout = None
event, values = self.window.read(timeout=timeout)

SUPPRESS_WIDGET_NOT_FINALIZED_WARNINGS = suppress

Expand All @@ -17314,7 +17340,7 @@ def Close(self):


def easy_print(*args, size=(None, None), end=None, sep=None, location=(None, None), relative_location=(None, None), font=None, no_titlebar=False,
no_button=False, grab_anywhere=False, keep_on_top=None, do_not_reroute_stdout=True, echo_stdout=False, text_color=None, background_color=None, colors=None, c=None, erase_all=False, resizable=True, blocking=None):
no_button=False, grab_anywhere=False, keep_on_top=None, do_not_reroute_stdout=True, echo_stdout=False, text_color=None, background_color=None, colors=None, c=None, erase_all=False, resizable=True, blocking=None, wait=None):
"""
Works like a "print" statement but with windowing options. Routes output to the "Debug Window"

Expand Down Expand Up @@ -17367,9 +17393,13 @@ def easy_print(*args, size=(None, None), end=None, sep=None, location=(None, Non
:type erase_all: (bool)
:param blocking: if True, makes the window block instead of returning immediately. The "Quit" button changers to "More"
:type blocking: (bool | None)
:param wait: Same as the "blocking" parm. It's an alias. if True, makes the window block instead of returning immediately. The "Quit" button changers to "More"
:type wait: (bool | None)
:return:
:rtype:
"""

blocking = blocking or wait
if _DebugWin.debug_window is None:
_DebugWin.debug_window = _DebugWin(size=size, location=location, relative_location=relative_location, font=font, no_titlebar=no_titlebar,
no_button=no_button, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top,
Expand Down Expand Up @@ -23916,11 +23946,9 @@ def main_global_pysimplegui_settings():
style.map(style_name, background=[("selected", element.scroll_background_color), ('active', element.scroll_arrow_color), ('background', element.scroll_background_color), ('!focus', element.scroll_background_color)])
style.map(style_name, arrowcolor=[("selected", element.scroll_arrow_color), ('active', element.scroll_background_color), ('background', element.scroll_arrow_color),('!focus', element.scroll_arrow_color)])
"""
# ------------------------- TTK Tab -------------------------
ttk_scrollbar_tab_layout = [[Checkbox('Use TTK Scrollbars', settings.get('-use ttk scrollbars-', True)), T('Default TTK Theme'), Combo(TTK_THEME_LIST, DEFAULT_TTK_THEME, readonly=True, key='-TTK THEME-')]]

# ttk_layout = [[]]
# for key, item in scrollbar_components.items():
# ttk_layout += [[T(key, s=15), Combo(theme_choices, default_value=settings.get('-ttk scroll-'+key, item))]]
t_len = max([len(l) for l in TTK_SCROLLBAR_PART_LIST])
ttk_layout = [[]]
for key, item in ttk_part_mapping_dict.items():
Expand All @@ -23933,14 +23961,18 @@ def main_global_pysimplegui_settings():

ttk_scrollbar_tab_layout += ttk_layout
ttk_scrollbar_tab_layout += [[Button('Reset Scrollbar Settings'), Button('Test Scrollbar Settings')]]
ttk_tab = Tab('TTK Scrollbar', ttk_scrollbar_tab_layout)
ttk_tab = Tab('TTK', ttk_scrollbar_tab_layout)

layout = [[T('Global PySimpleGUI Settings', text_color=theme_button_color()[0], background_color=theme_button_color()[1],font='_ 18', expand_x=True, justification='c')]]

# ------------------------- Interpreter Tab -------------------------


interpreter_tab = Tab('Python Interpreter',
[[T('Normally leave this blank')],
[T('Command to run a python program:'), In(settings.get('-python command-', ''), k='-PYTHON COMMAND-', enable_events=True), FileBrowse()]], font='_ 16', expand_x=True)

# ------------------------- Editor Tab -------------------------

editor_tab = Tab('Editor Settings',
[[T('Command to invoke your editor:'), In(settings.get('-editor program-', ''), k='-EDITOR PROGRAM-', enable_events=True), FileBrowse()],
Expand All @@ -23950,25 +23982,29 @@ def main_global_pysimplegui_settings():
[T('Edit Format String (hover for tooltip)', tooltip=tooltip),
In(settings.get('-editor format string-', '<editor> <file>'), k='-EDITOR FORMAT-', tooltip=tooltip)]], font='_ 16', expand_x=True)

# ------------------------- Explorer Tab -------------------------

explorer_tab = Tab('Explorer Program',
[[In(settings.get('-explorer program-', ''), k='-EXPLORER PROGRAM-', tooltip=tooltip_file_explorer)]], font='_ 16', expand_x=True, tooltip=tooltip_file_explorer)

# ------------------------- Snapshots Tab -------------------------

snapshots_tab = Tab('Window Snapshots',
[[Combo(('',)+key_choices, default_value=settings.get(json.dumps(('-snapshot keysym-', i)), ''), readonly=True, k=('-SNAPSHOT KEYSYM-', i), s=(None, 30)) for i in range(4)],
[T('Manually Entered Bind String:'), Input(settings.get('-snapshot keysym manual-', ''),k='-SNAPSHOT KEYSYM MANUAL-')],
[T('Folder to store screenshots:'), Push(), In(settings.get('-screenshots folder-', ''), k='-SCREENSHOTS FOLDER-'), FolderBrowse()],
[T('Screenshots Filename or Prefix:'), Push(), In(settings.get('-screenshots filename-', ''), k='-SCREENSHOTS FILENAME-'), FileBrowse()],
[Checkbox('Auto-number Images', k='-SCREENSHOTS AUTONUMBER-')]], font='_ 16', expand_x=True,)

# ------------------------- Theme Tab -------------------------

theme_tab = Tab('Theme',
[[T('Leave blank for "official" PySimpleGUI default theme: {}'.format(OFFICIAL_PYSIMPLEGUI_THEME))],
[T('Default Theme For All Programs:'),
Combo([''] + theme_list(), settings.get('-theme-', None), readonly=True, k='-THEME-', tooltip=tooltip_theme), Checkbox('Always use custom Titlebar', default=pysimplegui_user_settings.get('-custom titlebar-',False), k='-CUSTOM TITLEBAR-')]],
font='_ 16', expand_x=True)

settings_tab_group = TabGroup([[theme_tab, interpreter_tab, explorer_tab, editor_tab, ttk_tab, snapshots_tab ]])
settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab ]])
layout += [[settings_tab_group]]
# [T('Buttons (Leave Unchecked To Use Default) NOT YET IMPLEMENTED!', font='_ 16')],
# [Checkbox('Always use TTK buttons'), CBox('Always use TK Buttons')],
Expand Down