From f8aff92c98080959e870dcb55ec0baba716cc604 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sun, 2 Sep 2018 01:01:37 -0400 Subject: [PATCH] Default icon, function hiding, experimental dummy button, MsgBox renaming to Popup, Non-blocking Pop-up, removed legacy LayoutAndShow --- PySimpleGUI.py | 116 ++++++++++++++++++++++++++++++----------------- default_icon.ico | Bin 0 -> 18850 bytes 2 files changed, 75 insertions(+), 41 deletions(-) create mode 100644 default_icon.ico diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 69656f0f..3af22930 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -6,10 +6,17 @@ import tkinter.scrolledtext as tkst import tkinter.font import datetime import sys +import os +import base64 +import tempfile import textwrap +# TODO - Sept 1 2018 - HIGHLY EXPERIMENTAL.... start TK right away with a hidden window +# dummyroot = tk.Tk() +# dummyroot.attributes('-alpha', 0) # hide window while getting info and moving + # ----====----====----==== Constants the user CAN safely change ====----====----====----# -DEFAULT_WINDOW_ICON = '' +DEFAULT_WINDOW_ICON = 'default_icon.ico' DEFAULT_ELEMENT_SIZE = (45,1) # In CHARACTERS DEFAULT_BUTTON_ELEMENT_SIZE = (10,1) # In CHARACTERS DEFAULT_MARGINS = (10,5) # Margins for each LEFT/RIGHT margin is first term @@ -132,6 +139,7 @@ BUTTON_TYPE_BROWSE_FILE = 2 BUTTON_TYPE_BROWSE_FILES = 21 BUTTON_TYPE_SAVEAS_FILE = 3 BUTTON_TYPE_CLOSES_WIN = 5 +BUTTON_TYPE_CLOSES_WIN_ONLY = 6 BUTTON_TYPE_READ_FORM = 7 BUTTON_TYPE_REALTIME = 9 @@ -752,7 +760,7 @@ class Button(Element): if target[0] != None: if target[0] < 0: target = [self.Position[0] + target[0], target[1]] - target_element = self.ParentForm.GetElementAtLocation(target) + target_element = self.ParentForm._GetElementAtLocation(target) try: strvar = target_element.TKStringVar except: pass @@ -795,6 +803,15 @@ class Button(Element): self.ParentForm.LastButtonClicked = self.ButtonText self.ParentForm.FormRemainedOpen = True self.ParentForm.TKroot.quit() # kick the users out of the mainloop + elif self.BType == BUTTON_TYPE_CLOSES_WIN_ONLY: # this is a return type button so GET RESULTS and destroy window + # if the form is tabbed, must collect all form's results and destroy all forms + if self.ParentForm.IsTabbedForm: + self.ParentForm.UberParent._Close() + else: + self.ParentForm._Close() + if self.ParentForm.NonBlocking: + self.ParentForm.TKroot.destroy() + _my_windows.Decrement() return def Update(self, new_text, button_color=(None, None)): @@ -1080,7 +1097,9 @@ class FlexForm: self.Font = font if font else DEFAULT_FONT self.RadioDict = {} self.BorderDepth = border_depth - self.WindowIcon = icon if not _my_windows.user_defined_icon else _my_windows.user_defined_icon + # self.WindowIcon = icon + # self.WindowIcon = icon if icon else icon_tempfile + self.WindowIcon = icon if not None else _my_windows.user_defined_icon self.AutoClose = auto_close self.NonBlocking = False self.TKroot = None @@ -1124,11 +1143,6 @@ class FlexForm: def Layout(self,rows): self.AddRows(rows) - def LayoutAndShow(self,rows, non_blocking=False): - self.AddRows(rows) - self.Show(non_blocking=non_blocking) - return self.ReturnValues - def LayoutAndRead(self,rows, non_blocking=False): self.AddRows(rows) self.Show(non_blocking=non_blocking) @@ -1176,7 +1190,7 @@ class FlexForm: self.TKroot.iconbitmap(icon) except: pass - def GetElementAtLocation(self, location): + def _GetElementAtLocation(self, location): (row_num,col_num) = location row = self.Rows[row_num] element = row[col_num] @@ -1250,7 +1264,7 @@ class FlexForm: return screen_width, screen_height - def KeyboardCallback(self, event ): + def _KeyboardCallback(self, event ): self.LastButtonClicked = None self.FormRemainedOpen = True if event.char != '': @@ -1261,7 +1275,7 @@ class FlexForm: BuildResults(self, False, self) self.TKroot.quit() - def MouseWheelCallback(self, event ): + def _MouseWheelCallback(self, event ): self.LastButtonClicked = None self.FormRemainedOpen = True self.LastKeyboardEvent = 'MouseWheel:Down' if event.delta < 0 else 'MouseWheel:Up' @@ -1463,6 +1477,11 @@ def ReadFormButton(button_text, image_filename=None, image_size=(None, None),ima def RealtimeButton(button_text, image_filename=None, image_size=(None, None),image_subsample=None,border_width=None,scale=(None, None), size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, focus=False, pad=None): return Button(BUTTON_TYPE_REALTIME, image_filename=image_filename, image_size=image_size, image_subsample=image_subsample, border_width=border_width, button_text=button_text, scale=scale, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus, pad=pad) +# ------------------------- GENERIC BUTTON Element lazy function ------------------------- # +# this is the only button that REQUIRES button text field +def DummyButton(button_text, image_filename=None, image_size=(None, None),image_subsample=None,border_width=None,scale=(None, None), size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, focus=False, pad=None): + return Button(BUTTON_TYPE_CLOSES_WIN_ONLY, image_filename=image_filename, image_size=image_size, image_subsample=image_subsample, border_width=border_width, button_text=button_text, scale=scale, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus, pad=pad) + ##################################### ----- RESULTS ------ ################################################## def AddToReturnDictionary(form, element, value): @@ -2105,6 +2124,7 @@ def StartupTK(my_flex_form): ow = _my_windows.NumOpenWindows # print('Starting TK open Windows = {}'.format(ow)) root = tk.Tk() if not ow else tk.Toplevel() + # root = tk.Toplevel() if my_flex_form.BackgroundColor is not None and my_flex_form.BackgroundColor != COLOR_SYSTEM_DEFAULT: root.configure(background=my_flex_form.BackgroundColor) _my_windows.Increment() @@ -2115,11 +2135,11 @@ def StartupTK(my_flex_form): ConvertFlexToTK(my_flex_form) my_flex_form.SetIcon(my_flex_form.WindowIcon) if my_flex_form.ReturnKeyboardEvents and not my_flex_form.NonBlocking: - root.bind("", my_flex_form.KeyboardCallback) - root.bind("", my_flex_form.MouseWheelCallback) + root.bind("", my_flex_form._KeyboardCallback) + root.bind("", my_flex_form._MouseWheelCallback) elif my_flex_form.ReturnKeyboardEvents: - root.bind("", my_flex_form.KeyboardCallback) - root.bind("", my_flex_form.MouseWheelCallback) + root.bind("", my_flex_form._KeyboardCallback) + root.bind("", my_flex_form._MouseWheelCallback) if my_flex_form.AutoClose: duration = DEFAULT_AUTOCLOSE_TIME if my_flex_form.AutoCloseDuration is None else my_flex_form.AutoCloseDuration @@ -2135,7 +2155,6 @@ def StartupTK(my_flex_form): if my_flex_form.RootNeedsDestroying: my_flex_form.TKroot.destroy() my_flex_form.RootNeedsDestroying = False - return # ==============================_GetNumLinesNeeded ==# @@ -2163,7 +2182,7 @@ def _GetNumLinesNeeded(text, max_line_width): # Exits via an OK button2 press # # Returns nothing # # ===================================================# -def MsgBox(*args, button_color=None, button_type=MSG_BOX_OK, auto_close=False, auto_close_duration=None, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None): +def Popup(*args, button_color=None, button_type=MSG_BOX_OK, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None): ''' Show message box. Displays one line per user supplied argument. Takes any Type of variable to display. :param args: @@ -2207,29 +2226,45 @@ def MsgBox(*args, button_color=None, button_type=MSG_BOX_OK, auto_close=False, a pad = max_line_total-15 if max_line_total > 15 else 1 pad =1 + if non_blocking: + PopupButton = DummyButton + else: + PopupButton = SimpleButton # show either an OK or Yes/No depending on paramater if button_type is MSG_BOX_YES_NO: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False), Yes(button_color=button_color, focus=True, bind_return_key=True), No( - button_color=button_color)) - (button_text, values) = form.Show() - return button_text == 'Yes' + form.AddRow(Text('', size=(pad, 1), auto_size_text=False), PopupButton('Yes', button_color=button_color, focus=True, bind_return_key=True), PopupButton('No', button_color=button_color)) elif button_type is MSG_BOX_CANCELLED: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False), SimpleButton('Cancelled', button_color=button_color, focus=True, bind_return_key=True)) + form.AddRow(Text('', size=(pad, 1), auto_size_text=False), PopupButton('Cancelled', button_color=button_color, focus=True, bind_return_key=True)) elif button_type is MSG_BOX_ERROR: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False), SimpleButton('ERROR', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True)) + form.AddRow(Text('', size=(pad, 1), auto_size_text=False), PopupButton('ERROR', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True)) elif button_type is MSG_BOX_OK_CANCEL: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False), SimpleButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True), - SimpleButton('Cancel', size=(5, 1), button_color=button_color)) + form.AddRow(Text('', size=(pad, 1), auto_size_text=False), PopupButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True), + PopupButton('Cancel', size=(5, 1), button_color=button_color)) else: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False), SimpleButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True)) + form.AddRow(Text('', size=(pad, 1), auto_size_text=False), PopupButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True)) + + if non_blocking: + button, values = form.ReadNonBlocking() + else: + button, values = form.Show() - button, values = form.Show() return button -# ============================== PopUp ============# -# Lazy function. Same as calling MsgBox with parms # -# ===================================================# -Popup = MsgBox + + +# ============================== MsgBox============# +# Lazy function. Same as calling Popup with parms # +# ==================================================# +# MsgBox is the legacy call and show not be used any longer +MsgBox = Popup + +# --------------------------- PopupNonBlocking --------------------------- +def PopupoNonBlocking(*args, button_color=None, auto_close=False, auto_close_duration=None, font=None): + Popup(*args, non_blocking=True, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font) + return + +PopupNoWait = PopupoNonBlocking + # ============================== MsgBoxAutoClose====# # Lazy function. Same as calling MsgBox with parms # @@ -2248,7 +2283,7 @@ def MsgBoxAutoClose(*args, button_color=None, auto_close=True, auto_close_durati return PopupTimed = MsgBoxAutoClose - +PopupAutoClose = MsgBoxAutoClose # ============================== MsgBoxError =====# # Like MsgBox but presents RED BUTTONS # @@ -2285,7 +2320,7 @@ def MsgBoxCancel(*args, button_color=None, auto_close=False, auto_close_duration MsgBox(*args, button_type=MSG_BOX_CANCELLED, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font) return -PopupCancel =MsgBoxCancel +PopupCancel = MsgBoxCancel # ============================== MsgBoxOK =====# @@ -2305,7 +2340,6 @@ def MsgBoxOK(*args, button_color=None, auto_close=False, auto_close_duration=Non return PopupOk = MsgBoxOK -PopupOK = MsgBoxOK # ============================== MsgBoxOKCancel ====# @@ -2324,7 +2358,6 @@ def MsgBoxOKCancel(*args, button_color=None, auto_close=False, auto_close_durati result = MsgBox(*args, button_type=MSG_BOX_OK_CANCEL, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font) return result -PopupOKCancel = MsgBoxOKCancel PopupOkCancel = MsgBoxOKCancel @@ -2686,7 +2719,7 @@ def GetPathBox(title, message, default_path='', button_color=None, size=(None, N [InputText(default_text=default_path, size=size), FolderBrowse()], [Submit(), Cancel()]] - (button, input_values) = form.LayoutAndShow(layout) + (button, input_values) = form.LayoutAndRead(layout) if button != 'Submit': return False,None else: @@ -2704,7 +2737,7 @@ def PopupGetFolder(message, default_path='', button_color=None, size=(None, None [InputText(default_text=default_path, size=size), FolderBrowse()], [Ok(), Cancel()]] - (button, input_values) = form.LayoutAndShow(layout) + (button, input_values) = form.LayoutAndRead(layout) if button != 'Ok': return None else: @@ -2720,7 +2753,7 @@ def GetFileBox(title, message, default_path='', file_types=(("ALL Files", "*.*") [InputText(default_text=default_path, size=size), FileBrowse(file_types=file_types)], [Submit(), Cancel()]] - (button, input_values) = form.LayoutAndShow(layout) + (button, input_values) = form.LayoutAndRead(layout) if button != 'Submit': return False,None else: @@ -2737,7 +2770,7 @@ def PopupGetFile(message, default_path='', file_types=(("ALL Files", "*.*"),), b [InputText(default_text=default_path, size=size), FileBrowse(file_types=file_types)], [Ok(), Cancel()]] - (button, input_values) = form.LayoutAndShow(layout) + (button, input_values) = form.LayoutAndRead(layout) if button != 'Ok': return None else: @@ -2753,7 +2786,7 @@ def GetTextBox(title, message, Default='', button_color=None, size=(None, None)) [InputText(default_text=Default, size=size)], [Submit(), Cancel()]] - (button, input_values) = form.LayoutAndShow(layout) + (button, input_values) = form.LayoutAndRead(layout) if button != 'Submit': return False,None else: @@ -2771,7 +2804,7 @@ def PopupGetText(message, Default='', button_color=None, size=(None, None)): [InputText(default_text=Default, size=size)], [Ok(), Cancel()]] - (button, input_values) = form.LayoutAndShow(layout) + (button, input_values) = form.LayoutAndRead(layout) if button != 'Ok': return None else: @@ -3041,6 +3074,7 @@ def main(): button, (source, dest) = form.LayoutAndRead(form_rows) + if __name__ == '__main__': main() exit(69) \ No newline at end of file diff --git a/default_icon.ico b/default_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e5d1c2241275e84a0414f611dcb56568de7f2551 GIT binary patch literal 18850 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