From 5af78df079c5a178b50dd60abdc271419cf44be0 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Wed, 2 Jan 2019 11:14:29 -0500 Subject: [PATCH 01/10] System Tray - Ability to change icon, tooltip --- PySimpleGUIWx/PySimpleGUIWx.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/PySimpleGUIWx/PySimpleGUIWx.py b/PySimpleGUIWx/PySimpleGUIWx.py index 9df0724d..3b105ecb 100644 --- a/PySimpleGUIWx/PySimpleGUIWx.py +++ b/PySimpleGUIWx/PySimpleGUIWx.py @@ -2688,7 +2688,6 @@ class SystemTray: self.timer.Start(milliseconds=timeout1, oneShot=wx.TIMER_ONE_SHOT) except: print('*** Got error in Read ***') - Popup(f'*** Read error TaskBarIcon = {self.TaskBarIcon}\n') self.RunningMainLoop = True self.App.MainLoop() self.RunningMainLoop = False @@ -2752,6 +2751,13 @@ class SystemTray: # Menu if menu is not None: self.TaskBarIcon.menu = menu + if filename: + self.icon = wx.Icon(filename, wx.BITMAP_TYPE_ANY) + elif data_base64: + self.icon = PyEmbeddedImage(data_base64).GetIcon() + else: + self.icon = PyEmbeddedImage(DEFAULT_BASE64_ICON).GetIcon() + self.TaskBarIcon.SetIcon(self.icon, tooltip=tooltip or '') # Tooltip # if tooltip is not None: # self.TrayIcon.setToolTip(str(tooltip)) From ce669b1ba02e8f8e35c9f92d69340b46f53c7c27 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Thu, 3 Jan 2019 09:22:28 +0100 Subject: [PATCH 02/10] Allow proper propagation of user defined icon in subwindows --- PySimpleGUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 01542bfd..65195023 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -3412,7 +3412,7 @@ class Window: self.Font = font if font else DEFAULT_FONT self.RadioDict = {} self.BorderDepth = border_depth - self.WindowIcon = icon if icon is not None else Window.user_defined_icon + self.WindowIcon = self.WindowIcon = Window.user_defined_icon if Window.user_defined_icon is not None else icon if icon is not None else DEFAULT_WINDOW_ICON self.AutoClose = auto_close self.NonBlocking = False self.TKroot = None From 5cd4965d2a8ba31493be97ac73da0a05f5fa2b93 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Thu, 3 Jan 2019 09:26:12 +0100 Subject: [PATCH 03/10] Allow to silently skip no found elements --- PySimpleGUI.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 01542bfd..a40d8e73 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -3735,15 +3735,18 @@ class Window: FillFormWithValues(self, values_dict) return self - def FindElement(self, key): + def FindElement(self, key, silent_on_error=None): element = _FindElementFromKeyInSubForm(self, key) if element is None: - print('*** WARNING = FindElement did not find the key. Please check your key\'s spelling ***') - PopupError('Keyword error in FindElement Call', - 'Bad key = {}'.format(key), - 'Your bad line of code may resemble this:', - 'window.FindElement("{}")'.format(key)) - return ErrorElement(key=key) + if not silent_on_error == True: + print('*** WARNING = FindElement did not find the key. Please check your key\'s spelling ***') + PopupError('Keyword error in FindElement Call', + 'Bad key = {}'.format(key), + 'Your bad line of code may resemble this:', + 'window.FindElement("{}")'.format(key)) + return ErrorElement(key=key) + else: + return False return element Element = FindElement # Shortcut function From 8dfaa61d367cac1d3a49a227655d970efc630050 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 08:27:17 -0500 Subject: [PATCH 04/10] Added a few type hints --- PySimpleGUI.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 01542bfd..628d0fc3 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -4641,7 +4641,7 @@ else: # ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ # -def PackFormIntoFrame(form, containing_frame, toplevel_form): +def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): def CharWidthInPixels(): return tkinter.font.Font().measure('A') # single character width @@ -5318,7 +5318,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): else: element.tktext_label = tk.Label(tk_row_frame, width=width, height=height, bd=border_depth) if element.BackgroundColor is not None: - element.tktext_label.config(background=element.BackgroundColor); + element.tktext_label.config(background=element.BackgroundColor) element.tktext_label.image = photo # tktext_label.configure(anchor=tk.NW, image=photo) @@ -5791,7 +5791,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): return -def ConvertFlexToTK(MyFlexForm): +def ConvertFlexToTK(MyFlexForm:Window): master = MyFlexForm.TKroot master.title(MyFlexForm.Title) InitializeResults(MyFlexForm) @@ -5830,9 +5830,8 @@ def ConvertFlexToTK(MyFlexForm): # ----====----====----====----====----==== STARTUP TK ====----====----====----====----====----# -def StartupTK(my_flex_form): +def StartupTK(my_flex_form:Window): # global _my_windows - # ow = _my_windows.NumOpenWindows ow = Window.NumOpenWindows # print('Starting TK open Windows = {}'.format(ow)) From 6a6fcd605461ae79fc1ddc97c859b385a572a586 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 11:18:38 -0500 Subject: [PATCH 05/10] Row colors for Table Element --- PySimpleGUI.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index d58c5d86..fdf546e9 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -3062,7 +3062,7 @@ MenuBar = Menu # another name for Menu to make it clear it's the Menu B # ---------------------------------------------------------------------- # class Table(Element): def __init__(self, values, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, - auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, num_rows=None, row_height=None, font=None, justification='right', text_color=None, background_color=None, alternating_row_color=None, vertical_scroll_only=True, + auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, num_rows=None, row_height=None, font=None, justification='right', text_color=None, background_color=None, alternating_row_color=None, row_colors=None, vertical_scroll_only=True, size=(None, None), change_submits=False, enable_events=False, bind_return_key=False, pad=None, key=None, tooltip=None, right_click_menu=None, visible=True): ''' Table @@ -3116,7 +3116,7 @@ class Table(Element): self.StartingRowNumber = 0 # When displaying row numbers, where to start self.RowHeaderText = 'Row' self.RightClickMenu = right_click_menu - + self.RowColors = row_colors super().__init__(ELEM_TYPE_TABLE, text_color=text_color, background_color=background_color, font=font, size=size, pad=pad, key=key, tooltip=tooltip, visible=visible) @@ -3412,7 +3412,7 @@ class Window: self.Font = font if font else DEFAULT_FONT self.RadioDict = {} self.BorderDepth = border_depth - self.WindowIcon = self.WindowIcon = Window.user_defined_icon if Window.user_defined_icon is not None else icon if icon is not None else DEFAULT_WINDOW_ICON + self.WindowIcon = Window.user_defined_icon if Window.user_defined_icon is not None else icon if icon is not None else DEFAULT_WINDOW_ICON self.AutoClose = auto_close self.NonBlocking = False self.TKroot = None @@ -3738,7 +3738,7 @@ class Window: def FindElement(self, key, silent_on_error=None): element = _FindElementFromKeyInSubForm(self, key) if element is None: - if not silent_on_error == True: + if not silent_on_error: print('*** WARNING = FindElement did not find the key. Please check your key\'s spelling ***') PopupError('Keyword error in FindElement Call', 'Bad key = {}'.format(key), @@ -4973,7 +4973,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): timeout=DEFAULT_TOOLTIP_TIME) - # ------------------------- INPUT (Single Line) element ------------------------- # + # ------------------------- INPUT element ------------------------- # elif element_type == ELEM_TYPE_INPUT_TEXT: default_text = element.DefaultText element.TKStringVar = tk.StringVar() @@ -5010,7 +5010,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): AddMenuItem(top_menu, menu[1], element) element.TKRightClickMenu = top_menu element.TKEntry.bind('', element.RightClickMenuCallback) - # ------------------------- COMBO BOX (Drop Down) element ------------------------- # + # ------------------------- COMBOBOX element ------------------------- # elif element_type == ELEM_TYPE_INPUT_COMBO: max_line_len = max([len(str(l)) for l in element.Values]) if auto_size_text is False: @@ -5079,7 +5079,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): element.TKCombo['state'] = 'disabled' if element.Tooltip is not None: element.TooltipObject = ToolTip(element.TKCombo, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) - # ------------------------- OPTION MENU (Like ComboBox but different) element ------------------------- # + # ------------------------- OPTION MENU Element (Like ComboBox but different) element ------------------------- # elif element_type == ELEM_TYPE_INPUT_OPTION_MENU: max_line_len = max([len(str(l)) for l in element.Values]) if auto_size_text is False: @@ -5178,7 +5178,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): AddMenuItem(top_menu, menu[1], element) element.TKRightClickMenu = top_menu element.TKText.bind('', element.RightClickMenuCallback) - # ------------------------- INPUT CHECKBOX element ------------------------- # + # ------------------------- CHECKBOX element ------------------------- # elif element_type == ELEM_TYPE_INPUT_CHECKBOX: width = 0 if auto_size_text else element_size[0] default_value = element.InitialState @@ -5225,7 +5225,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): element.TKProgressBar.TKProgressBarForReal.pack(side=tk.LEFT, padx=elementpad[0], pady=elementpad[1]) if element.Visible is False: element.TKProgressBar.TKProgressBarForReal.pack_forget() - # ------------------------- INPUT RADIO BUTTON element ------------------------- # + # ------------------------- RADIO BUTTON element ------------------------- # elif element_type == ELEM_TYPE_INPUT_RADIO: width = 0 if auto_size_text else element_size[0] default_value = element.InitialState @@ -5259,7 +5259,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): element.TKRadio.pack_forget() if element.Tooltip is not None: element.TooltipObject = ToolTip(element.TKRadio, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) - # ------------------------- INPUT SPIN Box element ------------------------- # + # ------------------------- SPIN element ------------------------- # elif element_type == ELEM_TYPE_INPUT_SPIN: width, height = element_size width = 0 if auto_size_text else element_size[0] @@ -5615,9 +5615,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): for i, value in enumerate(element.Values): if element.DisplayRowNumbers: value = [i+element.StartingRowNumber] + value - id = treeview.insert('', 'end', text=value, iid=i + 1, values=value, tag=i % 2) + id = treeview.insert('', 'end', text=value, iid=i + 1, values=value, tag=i) if element.AlternatingRowColor is not None: - treeview.tag_configure(1, background=element.AlternatingRowColor) + for row in range(0, len(element.Values), 2): + treeview.tag_configure(row, background=element.AlternatingRowColor) + if element.RowColors is not None: + for row,color in element.RowColors: + treeview.tag_configure(row, background=color) if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: ttk.Style().configure("Treeview", background=element.BackgroundColor, fieldbackground=element.BackgroundColor) From c1ffd5c5ec7928feb8a0aead64271dbe74ceaa25 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 11:38:33 -0500 Subject: [PATCH 06/10] Enable setting text and background colors for rows --- PySimpleGUI.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index fdf546e9..41c544fe 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -5616,12 +5616,16 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): if element.DisplayRowNumbers: value = [i+element.StartingRowNumber] + value id = treeview.insert('', 'end', text=value, iid=i + 1, values=value, tag=i) - if element.AlternatingRowColor is not None: + if element.AlternatingRowColor is not None: # alternating colors for row in range(0, len(element.Values), 2): treeview.tag_configure(row, background=element.AlternatingRowColor) - if element.RowColors is not None: - for row,color in element.RowColors: - treeview.tag_configure(row, background=color) + if element.RowColors is not None: # individual row colors + for row_def in element.RowColors: + if len(row_def) == 2: # only background is specified + treeview.tag_configure(row_def[0], background=row_def[1]) + else: + treeview.tag_configure(row_def[0], background=row_def[2], foreground=row_def[1]) + if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: ttk.Style().configure("Treeview", background=element.BackgroundColor, fieldbackground=element.BackgroundColor) From b16473759af84933e4f5b6a957016236dde26d2e Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 11:41:17 -0500 Subject: [PATCH 07/10] Instructions for creating a Mac App using PyInstaller --- docs/index.md | 15 +++++++++++++-- readme.md | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/index.md b/docs/index.md index a1cb2264..803f6913 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4264,8 +4264,19 @@ ValueError: script '.......\src\tkinter' not found Then try adding **`--hidden-import tkinter`** to your command - - +# Creating a Mac App File + +There are reports that PyInstaller can be used to create App files. It's not been officially tested. + +Run this command on your Mac + +> pyinstaller --onefile --add-binary='/System/Library/Frameworks/Tk.framework/Tk':'tk' --add-binary='/System/Library/Frameworks/Tcl.framework/Tcl':'tcl' your_program.py + + +This info was located on Reddit with the source traced back to: +https://github.com/pyinstaller/pyinstaller/issues/1350 + + ## Fun Stuff Here are some things to try if you're bored or want to further customize diff --git a/readme.md b/readme.md index a1cb2264..803f6913 100644 --- a/readme.md +++ b/readme.md @@ -4264,8 +4264,19 @@ ValueError: script '.......\src\tkinter' not found Then try adding **`--hidden-import tkinter`** to your command - - +# Creating a Mac App File + +There are reports that PyInstaller can be used to create App files. It's not been officially tested. + +Run this command on your Mac + +> pyinstaller --onefile --add-binary='/System/Library/Frameworks/Tk.framework/Tk':'tk' --add-binary='/System/Library/Frameworks/Tcl.framework/Tcl':'tcl' your_program.py + + +This info was located on Reddit with the source traced back to: +https://github.com/pyinstaller/pyinstaller/issues/1350 + + ## Fun Stuff Here are some things to try if you're bored or want to further customize From 59f866e8587f8c748523be153cc8f317cbbf2774 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 12:54:33 -0500 Subject: [PATCH 08/10] Added ability to change button image size in Button.Update when filename is specified --- PySimpleGUI.py | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 41c544fe..f2a6b72b 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1639,10 +1639,15 @@ class Button(Element): self.TKButton.image = image if image_filename is not None: self.TKButton.config(highlightthickness=0) - photo = tk.PhotoImage(file=image_filename) - width, height = photo.width(), photo.height() - self.TKButton.config(image=photo, width=width, height=height) - self.TKButton.image = photo + image = tk.PhotoImage(file=image_filename) + if image_size is not None: + width, height = image_size + else: + width, height = image.width(), image.height() + if image_subsample: + image = image.subsample(image_subsample) + self.TKButton.config(image=image, width=width, height=height) + self.TKButton.image = image if visible is False: self.TKButton.pack_forget() elif visible is True: @@ -1711,6 +1716,7 @@ class ButtonMenu(Element): self.MenuItemChosen = None self.Tearoff = tearoff self.TKButtonMenu = None + self.TKMenu = None # self.temp_size = size if size != (NONE, NONE) else super().__init__(ELEM_TYPE_BUTTONMENU, size=size, font=font, pad=pad, key=key, tooltip=tooltip, text_color=self.TextColor, background_color=self.BackgroundColor, visible=visible) @@ -1731,32 +1737,11 @@ class ButtonMenu(Element): if menu_definition is not None: self.TKMenu = tk.Menu(self.TKButtonMenu, tearoff=self.Tearoff) # create the menubar AddMenuItem(self.TKMenu, menu_definition[1], self) - # for menu_entry in menu_definition: - # # print(f'Adding a Menubar ENTRY {menu_entry}') - # baritem = tk.Menu(menubar, tearoff=self.Tearoff) - # pos = menu_entry[0].find('&') - # # print(pos) - # if pos != -1: - # if pos == 0 or menu_entry[0][pos - 1] != "\\": - # menu_entry[0] = menu_entry[0][:pos] + menu_entry[0][pos + 1:] - # if menu_entry[0][0] == MENU_DISABLED_CHARACTER: - # menubar.add_cascade(label=menu_entry[0][len(MENU_DISABLED_CHARACTER):], menu=baritem, underline=pos) - # menubar.entryconfig(menu_entry[0][len(MENU_DISABLED_CHARACTER):], state='disabled') - # else: - # menubar.add_cascade(label=menu_entry[0], menu=baritem, underline=pos) - # - # if len(menu_entry) > 1: - # AddMenuItem(baritem, menu_entry[1], self) self.TKButtonMenu.configure(menu=self.TKMenu) - - def UpdateQt(self, menu_definition=None, text=None, button_color=(None, None), font=None, visible=None): - if menu_definition is not None: - menu_def = menu_definition - qmenu = QMenu(self.QT_QPushButton) - qmenu.setTitle(menu_def[0]) - AddMenuItem(qmenu, menu_def[1], self) - self.QT_QPushButton.setMenu(qmenu) - super().Update(self.QT_QPushButton, background_color=button_color[1], text_color=button_color[0], font=font, visible=visible) + if visible is False: + self.TKButtonMenu.pack_forget() + elif visible is True: + self.TKButtonMenu.pack() From 9c548021d5266f6bcfb6ed79f2f90baf3ac9d872 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 16:10:37 -0500 Subject: [PATCH 09/10] Output Element - Visible, Invisible supported --- PySimpleGUI.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index f2a6b72b..5e4d7ac7 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -369,7 +369,7 @@ class Element(): self.Tooltip = tooltip self.TooltipObject = None self.Visible = visible - + self.TKRightClickMenu = None def RightClickMenuCallback(self, event): self.TKRightClickMenu.tk_popup(event.x_root, event.y_root, 0) @@ -1404,9 +1404,9 @@ class Output(Element): self._TKOut.output.delete('1.0', tk.END) self._TKOut.output.insert(tk.END, value) if visible is False: - self._TKOut.pack_forget() + self._TKOut.frame.pack_forget() elif visible is True: - self._TKOut.pack() + self._TKOut.frame.pack() def __del__(self): try: @@ -5275,7 +5275,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): pad=elementpad) element._TKOut.pack(side=tk.LEFT, expand=True, fill='both') if element.Visible is False: - element._TKOut.pack_forget() + element._TKOut.frame.pack_forget() if element.Tooltip is not None: element.TooltipObject = ToolTip(element._TKOut, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) if element.RightClickMenu or toplevel_form.RightClickMenu: From b7dfccecd050b5bcd37e3ffb355a28f591636d55 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 3 Jan 2019 19:57:10 -0500 Subject: [PATCH 10/10] Commented out line of code because of Linux compatibility --- PySimpleGUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 5e4d7ac7..22a8ff22 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -5033,7 +5033,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form:Window): 'sticky': 'nswe'})]) # Copy default TCombobox settings - combostyle.configure(style_name, *combostyle.configure("TCombobox")) + # combostyle.configure(style_name, *combostyle.configure("TCombobox")) # Set individual widget options combostyle.configure(style_name, foreground=element.TextColor)