Replaced all temp Tk windows with creating the hidden-master-root

This commit is contained in:
PySimpleGUI 2022-03-19 12:46:36 -04:00
parent 92f7cb8a74
commit cfc43679ec
1 changed files with 44 additions and 92 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
from builtins import Exception from builtins import Exception
version = __version__ = "4.57.0.14 Unreleased" version = __version__ = "4.57.0.15 Unreleased"
_change_log = """ _change_log = """
Changelog since 4.57.0 released to PyPI on 13-Feb-2022 Changelog since 4.57.0 released to PyPI on 13-Feb-2022
@ -35,6 +35,10 @@ _change_log = """
Fix docstring for image in the Titlebar element. Incorrectly said an ICO file can be used. Must be PNG or GIF Fix docstring for image in the Titlebar element. Incorrectly said an ICO file can be used. Must be PNG or GIF
4.57.0.14 4.57.0.14
Windows-specific code that enables the PySimpleGUI supplied icon to be shown rather than the python.exe logo (thank you Jason) Windows-specific code that enables the PySimpleGUI supplied icon to be shown rather than the python.exe logo (thank you Jason)
4.57.0.15
Removed all temporary Tk() window creation and instead create the hidden master root. These were required for operations like getting
the list of fonts from tkinter, the screensize, character width and height. This way one and only one Tk window will ever be creeated.
The reason for the change is that the Mac crashes if multiple Tk() objects are created, even if only 1 at a time is active.
""" """
__version__ = version.split()[0] # For PEP 396 and PEP 345 __version__ = version.split()[0] # For PEP 396 and PEP 345
@ -3523,16 +3527,12 @@ class Text(Element):
:return: List of the installed font names :return: List of the installed font names
:rtype: List[str] :rtype: List[str]
""" """
# if no windows have been created (there is no hidden master root to rely on) then temporarily make a window so the measurement can happen # A window must exist before can perform this operation. Create the hidden master root if it doesn't exist
if Window.hidden_master_root is None: _get_hidden_master_root()
root = tk.Tk()
else:
root = Window.hidden_master_root
fonts = list(tkinter.font.families()) fonts = list(tkinter.font.families())
fonts.sort() fonts.sort()
if Window.hidden_master_root is None:
root.destroy()
return fonts return fonts
@ -3550,11 +3550,8 @@ class Text(Element):
:return: Width in pixels of "A" :return: Width in pixels of "A"
:rtype: (int) :rtype: (int)
""" """
# if no windows have been created (there is no hidden master root to rely on) then temporarily make a window so the measurement can happen # A window must exist before can perform this operation. Create the hidden master root if it doesn't exist
if Window.NumOpenWindows == 0: _get_hidden_master_root()
root = tk.Tk()
else:
root = None
size = 0 size = 0
try: try:
@ -3562,9 +3559,6 @@ class Text(Element):
except Exception as e: except Exception as e:
_error_popup_with_traceback('Exception retrieving char width in pixels', e) _error_popup_with_traceback('Exception retrieving char width in pixels', e)
if root is not None:
root.destroy()
return size return size
@classmethod @classmethod
@ -3579,19 +3573,15 @@ class Text(Element):
:rtype: (int) :rtype: (int)
""" """
# if no windows have been created (there is no hidden master root to rely on) then temporarily make a window so the measurement can happen # A window must exist before can perform this operation. Create the hidden master root if it doesn't exist
if Window.NumOpenWindows == 0: _get_hidden_master_root()
root = tk.Tk()
else:
root = None
size = 0 size = 0
try: try:
size = tkinter.font.Font(font=font).metrics('linespace') size = tkinter.font.Font(font=font).metrics('linespace')
except Exception as e: except Exception as e:
_error_popup_with_traceback('Exception retrieving char height in pixels', e) _error_popup_with_traceback('Exception retrieving char height in pixels', e)
if root is not None:
root.destroy()
return size return size
@ -3608,11 +3598,8 @@ class Text(Element):
:rtype: (int) :rtype: (int)
""" """
# if no windows have been created (there is no hidden master root to rely on) then temporarily make a window so the measurement can happen # A window must exist before can perform this operation. Create the hidden master root if it doesn't exist
if Window.NumOpenWindows == 0: _get_hidden_master_root()
root = tk.Tk()
else:
root = None
size = 0 size = 0
try: try:
@ -3620,9 +3607,6 @@ class Text(Element):
except Exception as e: except Exception as e:
_error_popup_with_traceback('Exception retrieving string width in pixels', e) _error_popup_with_traceback('Exception retrieving string width in pixels', e)
if root is not None:
root.destroy()
return size return size
def _print_to_element(self, *args, end=None, sep=None, text_color=None, background_color=None, autoscroll=None, justification=None, font=None, append=None): def _print_to_element(self, *args, end=None, sep=None, text_color=None, background_color=None, autoscroll=None, justification=None, font=None, append=None):
@ -9248,10 +9232,9 @@ class Window:
:return: Size of the screen in pixels as determined by tkinter :return: Size of the screen in pixels as determined by tkinter
:rtype: (int, int) :rtype: (int, int)
""" """
root = tk.Tk() root = _get_hidden_master_root()
screen_width = root.winfo_screenwidth() screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight() screen_height = root.winfo_screenheight()
root.destroy()
return screen_width, screen_height return screen_width, screen_height
@property @property
@ -15932,6 +15915,26 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
return return
def _get_hidden_master_root():
"""
Creates the hidden master root window. This window is never visible and represents the overall "application"
"""
# if one is already made, then skip making another
if Window.hidden_master_root is None:
Window._IncrementOpenCount()
Window.hidden_master_root = tk.Tk()
Window.hidden_master_root.attributes('-alpha', 0) # HIDE this window really really really
# if not running_mac():
try:
Window.hidden_master_root.wm_overrideredirect(True)
except Exception as e:
if not running_mac():
print('* Error performing wm_overrideredirect while hiding the hidden master root*', e)
Window.hidden_master_root.withdraw()
return Window.hidden_master_root
def _no_titlebar_setup(window): def _no_titlebar_setup(window):
""" """
Does the operations required to turn off the titlebar for the window. Does the operations required to turn off the titlebar for the window.
@ -16032,22 +16035,10 @@ def StartupTK(window):
root = tk.Tk() root = tk.Tk()
elif not ow and not window.ForceTopLevel: elif not ow and not window.ForceTopLevel:
# if first window being created, make a throwaway, hidden master root. This stops one user # if first window being created, make a throwaway, hidden master root. This stops one user
# window from becoming the child of another user window. All windows are children of this # window from becoming the child of another user window. All windows are children of this hidden window
# hidden window _get_hidden_master_root()
Window._IncrementOpenCount()
Window.hidden_master_root = tk.Tk()
Window.hidden_master_root.attributes('-alpha', 0) # HIDE this window really really really
# if not running_mac():
try:
Window.hidden_master_root.wm_overrideredirect(True)
except Exception as e:
if not running_mac():
print('* Error performing wm_overrideredirect while hiding the hidden master root*', e)
Window.hidden_master_root.withdraw()
# root = tk.Toplevel(Window.hidden_master_root) # This code caused problems when running with timeout=0 and closed with X
root = tk.Toplevel(class_=window.Title) root = tk.Toplevel(class_=window.Title)
else: else:
# root = tk.Toplevel(Window.hidden_master_root) # This code caused problems when running with timeout=0 and closed with X
root = tk.Toplevel(class_=window.Title) root = tk.Toplevel(class_=window.Title)
if window.DebuggerEnabled: if window.DebuggerEnabled:
root.bind('<Cancel>', window._callback_main_debugger_window_create_keystroke) root.bind('<Cancel>', window._callback_main_debugger_window_create_keystroke)
@ -18270,14 +18261,10 @@ def clipboard_set(new_value):
:param new_value: value to set the clipboard to. Will be converted to a string :param new_value: value to set the clipboard to. Will be converted to a string
:type new_value: (str | bytes) :type new_value: (str | bytes)
""" """
# Create and use a temp window root = _get_hidden_master_root()
root = tk.Tk()
root.withdraw()
root.clipboard_clear() root.clipboard_clear()
root.clipboard_append(str(new_value)) root.clipboard_append(str(new_value))
root.update() root.update()
root.destroy()
def clipboard_get(): def clipboard_get():
""" """
@ -18286,15 +18273,13 @@ def clipboard_get():
:return: The current value of the clipboard :return: The current value of the clipboard
:rtype: (str) :rtype: (str)
""" """
# Create and use a temp window root = _get_hidden_master_root()
root = tk.Tk()
root.withdraw()
try: try:
value = root.clipboard_get() value = root.clipboard_get()
except: except:
value = '' value = ''
root.update() root.update()
root.destroy()
return value return value
@ -19249,21 +19234,7 @@ def popup_get_folder(message, title=None, default_path='', no_window=False, size
# global _my_windows # global _my_windows
if no_window: if no_window:
if not Window.hidden_master_root: _get_hidden_master_root()
# if first window being created, make a throwaway, hidden master root. This stops one user
# window from becoming the child of another user window. All windows are children of this
# hidden window
Window._IncrementOpenCount()
Window.hidden_master_root = tk.Tk()
Window.hidden_master_root.attributes('-alpha', 0) # HIDE this window really really really
# if not running_mac():
try:
Window.hidden_master_root.wm_overrideredirect(True)
except Exception as e:
print('* Error performing wm_overrideredirect while hiding hidden master root in get folder *', e)
Window.hidden_master_root.withdraw()
root = tk.Toplevel() root = tk.Toplevel()
try: try:
@ -19422,19 +19393,7 @@ def popup_get_file(message, title=None, default_path='', default_extension='', s
if icon is None: if icon is None:
icon = Window._user_defined_icon or DEFAULT_BASE64_ICON icon = Window._user_defined_icon or DEFAULT_BASE64_ICON
if no_window: if no_window:
if not Window.hidden_master_root: _get_hidden_master_root()
# if first window being created, make a throwaway, hidden master root. This stops one user
# window from becoming the child of another user window. All windows are children of this
# hidden window
Window._IncrementOpenCount()
Window.hidden_master_root = tk.Tk()
Window.hidden_master_root.attributes('-alpha', 0) # HIDE this window really really really
# if not running_mac():
try:
Window.hidden_master_root.wm_overrideredirect(True)
except Exception as e:
print('* Error performing wm_overrideredirect in get file hiding the master root *', e)
Window.hidden_master_root.withdraw()
root = tk.Toplevel() root = tk.Toplevel()
try: try:
@ -19544,7 +19503,7 @@ def popup_get_file(message, title=None, default_path='', default_extension='', s
history_settings.set('-PSG file list-', list_of_entries) history_settings.set('-PSG file list-', list_of_entries)
break break
window.close(); window.close()
del window del window
if event in ('Cancel', WIN_CLOSED): if event in ('Cancel', WIN_CLOSED):
return None return None
@ -22975,13 +22934,6 @@ def main_get_debug_data(suppress_popup=False):
PySimpleGUI filename: {}""".format(sys.version, tclversion_detailed, ver, __file__) PySimpleGUI filename: {}""".format(sys.version, tclversion_detailed, ver, __file__)
clipboard_set(message) clipboard_set(message)
# create a temp window so that the clipboard can be set
# root = tk.Tk()
# root.withdraw()
# root.clipboard_clear()
# root.clipboard_append(message)
# root.update()
# root.destroy()
if not suppress_popup: if not suppress_popup:
popup_scrolled('*** Version information copied to your clipboard. Paste into your GitHub Issue. ***\n', popup_scrolled('*** Version information copied to your clipboard. Paste into your GitHub Issue. ***\n',