commit
cc8fd65f07
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
layout1 = [[ sg.Text('Window 1') ],
|
||||
[sg.Input(do_not_clear=True)],
|
||||
[ sg.RButton('Read')]]
|
||||
|
||||
window1 = sg.Window('My new window', location=(800,800)).Layout(layout1)
|
||||
|
||||
|
||||
layout2 = [[ sg.Text('Window 2') ],
|
||||
[sg.Input(do_not_clear=False)],
|
||||
[ sg.RButton('Read')]]
|
||||
|
||||
window2 = sg.Window('My new window', location=(800, 925)).Layout(layout2)
|
||||
|
||||
|
||||
layout3 = [[ sg.Text('Window 3') ],
|
||||
[sg.Input(do_not_clear=False)],
|
||||
[ sg.RButton('Read')]]
|
||||
|
||||
window3 = sg.Window('My new window', location=(800,1050)).Layout(layout3)
|
||||
|
||||
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window1.Read(timeout=100)
|
||||
if event is None:
|
||||
break
|
||||
elif event != '__timeout__':
|
||||
print(event, values)
|
||||
|
||||
event, values = window2.Read(timeout=0)
|
||||
if event is None:
|
||||
break
|
||||
elif event != '__timeout__':
|
||||
print(event, values)
|
||||
|
||||
event, values = window3.Read(timeout=0)
|
||||
if event is None:
|
||||
break
|
||||
elif event != '__timeout__':
|
||||
print(event, values)
|
125
PySimpleGUI.py
125
PySimpleGUI.py
|
@ -178,6 +178,9 @@ ThisRow = 555666777 # magic number
|
|||
# DEFAULT_WINDOW_ICON = ''
|
||||
MESSAGE_BOX_LINE_WIDTH = 60
|
||||
|
||||
# Key representing a Read timeout
|
||||
TIMEOUT_KEY = '__timeout__'
|
||||
|
||||
|
||||
# a shameful global variable. This represents the top-level window information. Needed because opening a second window is different than opening the first.
|
||||
class MyWindows():
|
||||
|
@ -380,7 +383,8 @@ class Element():
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = self.DisplayText
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def ReturnKeyHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
|
@ -397,7 +401,8 @@ class Element():
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def ComboboxSelectHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
|
@ -408,7 +413,8 @@ class Element():
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def CheckboxHandler(self):
|
||||
MyForm = self.ParentForm
|
||||
|
@ -417,7 +423,8 @@ class Element():
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit()
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def TabGroupSelectHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
|
@ -426,7 +433,8 @@ class Element():
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit()
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
|
@ -883,7 +891,8 @@ class Spin(Element):
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
|
@ -1225,7 +1234,8 @@ class Button(Element):
|
|||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
self.ParentForm.LastButtonClicked = self.ButtonText
|
||||
self.ParentForm.TKroot.quit() # kick out of loop if read was called
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick out of loop if read was called
|
||||
|
||||
# ------- Button Callback ------- #
|
||||
def ButtonCallBack(self):
|
||||
|
@ -1259,7 +1269,7 @@ class Button(Element):
|
|||
should_submit_window = True
|
||||
except:
|
||||
pass
|
||||
filetypes = [] if self.FileTypes is None else self.FileTypes
|
||||
filetypes = (("ALL Files", "*.*"),) if self.FileTypes is None else self.FileTypes
|
||||
if self.BType == BUTTON_TYPE_BROWSE_FOLDER:
|
||||
folder_name = tk.filedialog.askdirectory(initialdir=self.InitialFolder) # show the 'get folder' dialog box
|
||||
if folder_name != '':
|
||||
|
@ -1269,8 +1279,10 @@ class Button(Element):
|
|||
except:
|
||||
pass
|
||||
elif self.BType == BUTTON_TYPE_BROWSE_FILE:
|
||||
file_name = tk.filedialog.askopenfilename(filetypes=filetypes,
|
||||
initialdir=self.InitialFolder) # show the 'get file' dialog box
|
||||
if sys.platform == 'darwin':
|
||||
file_name = tk.filedialog.askopenfilename(initialdir=self.InitialFolder) # show the 'get file' dialog box
|
||||
else:
|
||||
file_name = tk.filedialog.askopenfilename(filetypes=filetypes, initialdir=self.InitialFolder) # show the 'get file' dialog box
|
||||
if file_name != '':
|
||||
strvar.set(file_name)
|
||||
self.TKStringVar.set(file_name)
|
||||
|
@ -1280,13 +1292,19 @@ class Button(Element):
|
|||
strvar.set(color)
|
||||
self.TKStringVar.set(color)
|
||||
elif self.BType == BUTTON_TYPE_BROWSE_FILES:
|
||||
file_name = tk.filedialog.askopenfilenames(filetypes=filetypes, initialdir=self.InitialFolder)
|
||||
if sys.platform == 'darwin':
|
||||
file_name = tk.filedialog.askopenfilenames(initialdir=self.InitialFolder)
|
||||
else:
|
||||
file_name = tk.filedialog.askopenfilenames(filetypes=filetypes, initialdir=self.InitialFolder)
|
||||
if file_name != '':
|
||||
file_name = ';'.join(file_name)
|
||||
strvar.set(file_name)
|
||||
self.TKStringVar.set(file_name)
|
||||
elif self.BType == BUTTON_TYPE_SAVEAS_FILE:
|
||||
file_name = tk.filedialog.asksaveasfilename(filetypes=filetypes,
|
||||
if sys.platform == 'darwin':
|
||||
file_name = tk.filedialog.asksaveasfilename(initialdir=self.InitialFolder) # show the 'get file' dialog box
|
||||
else:
|
||||
file_name = tk.filedialog.asksaveasfilename(filetypes=filetypes,
|
||||
initialdir=self.InitialFolder) # show the 'get file' dialog box
|
||||
if file_name != '':
|
||||
strvar.set(file_name)
|
||||
|
@ -1300,7 +1318,8 @@ class Button(Element):
|
|||
self.ParentForm.LastButtonClicked = self.ButtonText
|
||||
self.ParentForm.FormRemainedOpen = False
|
||||
self.ParentForm._Close()
|
||||
self.ParentForm.TKroot.quit()
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit()
|
||||
if self.ParentForm.NonBlocking:
|
||||
self.ParentForm.TKroot.destroy()
|
||||
_my_windows.Decrement()
|
||||
|
@ -1312,7 +1331,8 @@ class Button(Element):
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = self.ButtonText
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop: # if this window is running the mainloop, kick out
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
elif self.BType == BUTTON_TYPE_CLOSES_WIN_ONLY: # special kind of button that does not exit main loop
|
||||
self.ParentForm._Close()
|
||||
if self.ParentForm.NonBlocking:
|
||||
|
@ -1329,7 +1349,8 @@ class Button(Element):
|
|||
if should_submit_window:
|
||||
self.ParentForm.LastButtonClicked = target_element.Key
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
return
|
||||
|
||||
|
@ -1984,7 +2005,8 @@ class Slider(Element):
|
|||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
@ -2367,7 +2389,8 @@ class Menu(Element):
|
|||
# print('IN MENU ITEM CALLBACK', item_chosen)
|
||||
self.ParentForm.LastButtonClicked = item_chosen
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
@ -2452,7 +2475,7 @@ class Table(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
class Tree(Element):
|
||||
def __init__(self, data=None, headings=None, visible_column_map=None, col_widths=None, col0_width=10,
|
||||
def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, font=None,
|
||||
def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, show_expanded=False, font=None,
|
||||
justification='right', text_color=None, background_color=None, num_rows=None, pad=None, key=None,
|
||||
tooltip=None):
|
||||
'''
|
||||
|
@ -2485,14 +2508,22 @@ class Tree(Element):
|
|||
self.Justification = justification
|
||||
self.InitialState = None
|
||||
self.SelectMode = select_mode
|
||||
self.ShowExpanded = show_expanded
|
||||
self.NumRows = num_rows
|
||||
self.Col0Width = col0_width
|
||||
self.TKTreeview = None
|
||||
self.SelectedRows = []
|
||||
|
||||
super().__init__(ELEM_TYPE_TREE, text_color=text_color, background_color=background_color, font=font, pad=pad,
|
||||
key=key, tooltip=tooltip)
|
||||
return
|
||||
|
||||
|
||||
def treeview_selected(self, event):
|
||||
selections = self.TKTreeview.selection()
|
||||
self.SelectedRows = [x for x in selections]
|
||||
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
||||
|
@ -2622,6 +2653,7 @@ class Window:
|
|||
self.NonBlocking = False
|
||||
self.TKroot = None
|
||||
self.TKrootDestroyed = False
|
||||
self.CurrentlyRunningMainloop = False
|
||||
self.FormRemainedOpen = False
|
||||
self.TKAfterID = None
|
||||
self.ProgressBarColor = progress_bar_color
|
||||
|
@ -2753,20 +2785,23 @@ class Window:
|
|||
def _TimeoutAlarmCallback(self):
|
||||
# first, get the results table built
|
||||
# modify the Results table in the parent FlexForm object
|
||||
# print('TIMEOUT CALLBACK')
|
||||
if self.TimerCancelled:
|
||||
# print('** timer was cancelled **')
|
||||
return
|
||||
self.LastButtonClicked = self.TimeoutKey
|
||||
self.FormRemainedOpen = True
|
||||
self.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def Read(self, timeout=None, timeout_key='_timeout_'):
|
||||
if timeout == 0:
|
||||
def Read(self, timeout=None, timeout_key=TIMEOUT_KEY):
|
||||
if timeout == 0: # timeout of zero runs the old readnonblocking
|
||||
event, values = self.ReadNonBlocking()
|
||||
if event is None:
|
||||
event = timeout_key
|
||||
if values is None:
|
||||
event = None
|
||||
return event, values
|
||||
return event, values # make event None if values was None and return
|
||||
# Read with a timeout
|
||||
self.Timeout = timeout
|
||||
self.TimeoutKey = timeout_key
|
||||
self.NonBlocking = False
|
||||
|
@ -2775,27 +2810,48 @@ class Window:
|
|||
if not self.Shown:
|
||||
self.Show()
|
||||
else:
|
||||
# if already have a button waiting, the return previously built results
|
||||
if self.LastButtonClicked is not None and not self.LastButtonClickedWasRealtime:
|
||||
# print(f'*** Found previous clicked saved {self.LastButtonClicked}')
|
||||
results = BuildResults(self, False, self)
|
||||
self.LastButtonClicked = None
|
||||
return results
|
||||
InitializeResults(self)
|
||||
# if the last button clicked was realtime, emulate a read non-blocking
|
||||
# the idea is to quickly return realtime buttons without any blocks until released
|
||||
if self.LastButtonClickedWasRealtime:
|
||||
# print(f'RTime down {self.LastButtonClicked}' )
|
||||
try:
|
||||
rc = self.TKroot.update()
|
||||
except:
|
||||
self.TKrootDestroyed = True
|
||||
_my_windows.Decrement()
|
||||
print('ROOT Destroyed')
|
||||
results = BuildResults(self, False, self)
|
||||
if results[0] != None and results[0] != timeout_key:
|
||||
return results
|
||||
else:
|
||||
pass
|
||||
|
||||
# else:
|
||||
# print("** REALTIME PROBLEM FOUND **", results)
|
||||
|
||||
# normal read blocking code....
|
||||
if timeout != None:
|
||||
self.TimerCancelled = False
|
||||
self.TKAfterID = self.TKroot.after(timeout, self._TimeoutAlarmCallback)
|
||||
self.CurrentlyRunningMainloop = True
|
||||
# print(f'In main {self.Title}')
|
||||
self.TKroot.mainloop()
|
||||
# print('Out main')
|
||||
self.CurrentlyRunningMainloop = False
|
||||
# if self.LastButtonClicked != TIMEOUT_KEY:
|
||||
# print(f'Window {self.Title} Last button clicked = {self.LastButtonClicked}')
|
||||
try:
|
||||
self.TKroot.after_cancel(self.TKAfterID)
|
||||
except:
|
||||
pass
|
||||
# print('** tkafter cancel failed **')
|
||||
self.TimerCancelled = True
|
||||
if self.RootNeedsDestroying:
|
||||
self.TKroot.destroy()
|
||||
|
@ -2803,8 +2859,12 @@ class Window:
|
|||
# if form was closed with X
|
||||
if self.LastButtonClicked is None and self.LastKeyboardEvent is None and self.ReturnValues[0] is None:
|
||||
_my_windows.Decrement()
|
||||
# Determine return values
|
||||
if self.LastKeyboardEvent is not None or self.LastButtonClicked is not None:
|
||||
return BuildResults(self, False, self)
|
||||
results = BuildResults(self, False, self)
|
||||
if not self.LastButtonClickedWasRealtime:
|
||||
self.LastButtonClicked = None
|
||||
return results
|
||||
else:
|
||||
return self.ReturnValues
|
||||
|
||||
|
@ -2820,6 +2880,7 @@ class Window:
|
|||
except:
|
||||
self.TKrootDestroyed = True
|
||||
_my_windows.Decrement()
|
||||
# print("read failed")
|
||||
# return None, None
|
||||
return BuildResults(self, False, self)
|
||||
|
||||
|
@ -2928,7 +2989,8 @@ class Window:
|
|||
self.LastKeyboardEvent = str(event.keysym) + ':' + str(event.keycode)
|
||||
if not self.NonBlocking:
|
||||
BuildResults(self, False, self)
|
||||
self.TKroot.quit()
|
||||
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
||||
self.TKroot.quit()
|
||||
|
||||
def _MouseWheelCallback(self, event):
|
||||
self.LastButtonClicked = None
|
||||
|
@ -2936,7 +2998,8 @@ class Window:
|
|||
self.LastKeyboardEvent = 'MouseWheel:Down' if event.delta < 0 else 'MouseWheel:Up'
|
||||
if not self.NonBlocking:
|
||||
BuildResults(self, False, self)
|
||||
self.TKroot.quit()
|
||||
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
||||
self.TKroot.quit()
|
||||
|
||||
def _Close(self):
|
||||
try:
|
||||
|
@ -3004,6 +3067,12 @@ class Window:
|
|||
self._AlphaChannel = alpha
|
||||
self.TKroot.attributes('-alpha', alpha)
|
||||
|
||||
def BringToFront(self):
|
||||
try:
|
||||
self.TKroot.lift()
|
||||
except:
|
||||
pass
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
@ -3412,6 +3481,8 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
|
|||
value = None
|
||||
elif element.Type == ELEM_TYPE_TABLE:
|
||||
value = element.SelectedRows
|
||||
elif element.Type == ELEM_TYPE_TREE:
|
||||
value = element.SelectedRows
|
||||
else:
|
||||
value = None
|
||||
|
||||
|
@ -4399,7 +4470,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
def add_treeview_data(node):
|
||||
# print(f'Inserting {node.key} under parent {node.parent}')
|
||||
if node.key != '':
|
||||
treeview.insert(node.parent, 'end', node.key, text=node.text, values=node.values)
|
||||
treeview.insert(node.parent, 'end', node.key, text=node.text, values=node.values, open=element.ShowExpanded)
|
||||
for node in node.children:
|
||||
add_treeview_data(node)
|
||||
|
||||
|
@ -4411,8 +4482,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
fieldbackground=element.BackgroundColor)
|
||||
if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT:
|
||||
ttk.Style().configure("Treeview", foreground=element.TextColor)
|
||||
|
||||
element.TKTreeview.pack(side=tk.LEFT, expand=True, padx=0, pady=0, fill='both')
|
||||
treeview.bind("<<TreeviewSelect>>", element.treeview_selected)
|
||||
if element.Tooltip is not None: # tooltip
|
||||
element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip,
|
||||
timeout=DEFAULT_TOOLTIP_TIME)
|
||||
|
@ -4531,7 +4602,9 @@ def StartupTK(my_flex_form):
|
|||
# my_flex_form.TKroot.protocol("WM_DELETE_WINDOW", my_flex_form.OnClosingCallback())
|
||||
else: # it's a blocking form
|
||||
# print('..... CALLING MainLoop')
|
||||
my_flex_form.CurrentlyRunningMainloop = True
|
||||
my_flex_form.TKroot.mainloop()
|
||||
my_flex_form.CurrentlyRunningMainloop = False
|
||||
my_flex_form.TimerCancelled = True
|
||||
# print('..... BACK from MainLoop')
|
||||
if not my_flex_form.FormRemainedOpen:
|
||||
|
|
Loading…
Reference in New Issue