Release 3.14.0, 1.14.0
This commit is contained in:
parent
090bc5d479
commit
cc5ca4d814
346
PySimpleGUI27.py
346
PySimpleGUI27.py
|
@ -190,15 +190,18 @@ ThisRow = 555666777 # magic number
|
|||
# DEFAULT_WINDOW_ICON = ''
|
||||
MESSAGE_BOX_LINE_WIDTH = 60
|
||||
|
||||
# "Special" Key Values.. reserved
|
||||
# Key representing a Read timeout
|
||||
TIMEOUT_KEY = '__timeout__'
|
||||
|
||||
TIMEOUT_KEY = '__TIMEOUT__'
|
||||
# Key indicating should not create any return values for element
|
||||
WRITE_ONLY_KEY = '__WRITE ONLY__'
|
||||
|
||||
# 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(object):
|
||||
def __init__(self):
|
||||
self.NumOpenWindows = 0
|
||||
self.user_defined_icon = None
|
||||
self.hidden_master_root = None
|
||||
|
||||
def Decrement(self):
|
||||
self.NumOpenWindows -= 1 * (self.NumOpenWindows != 0) # decrement if not 0
|
||||
|
@ -405,7 +408,6 @@ class Element(object):
|
|||
button_element.ButtonCallBack()
|
||||
|
||||
def ListboxSelectHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
# first, get the results table built
|
||||
# modify the Results table in the parent FlexForm object
|
||||
if self.Key is not None:
|
||||
|
@ -417,7 +419,6 @@ class Element(object):
|
|||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def ComboboxSelectHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
# first, get the results table built
|
||||
# modify the Results table in the parent FlexForm object
|
||||
if self.Key is not None:
|
||||
|
@ -428,8 +429,16 @@ class Element(object):
|
|||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
def RadioHandler(self):
|
||||
if self.Key is not None:
|
||||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
self.ParentForm.LastButtonClicked = ''
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def CheckboxHandler(self):
|
||||
MyForm = self.ParentForm
|
||||
if self.Key is not None:
|
||||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
|
@ -439,7 +448,6 @@ class Element(object):
|
|||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def TabGroupSelectHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
if self.Key is not None:
|
||||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
|
@ -449,7 +457,6 @@ class Element(object):
|
|||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def KeyboardHandler(self, event):
|
||||
MyForm = self.ParentForm
|
||||
if self.Key is not None:
|
||||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
|
@ -520,6 +527,13 @@ class InputText(Element):
|
|||
def Get(self):
|
||||
return self.TKStringVar.get()
|
||||
|
||||
|
||||
def SetFocus(self):
|
||||
try:
|
||||
self.TKEntry.focus_set()
|
||||
except:
|
||||
pass
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
||||
|
@ -535,7 +549,7 @@ Input = InputText
|
|||
class InputCombo(Element):
|
||||
def __init__(self, values, default_value=None, size=(None, None), auto_size_text=None, background_color=None,
|
||||
text_color=None, change_submits=False, disabled=False, key=None, pad=None, tooltip=None,
|
||||
readonly=False):
|
||||
readonly=False, font=None):
|
||||
'''
|
||||
Input Combo Box Element (also called Dropdown box)
|
||||
:param values:
|
||||
|
@ -554,9 +568,9 @@ class InputCombo(Element):
|
|||
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
|
||||
|
||||
super().__init__(ELEM_TYPE_INPUT_COMBO, size=size, auto_size_text=auto_size_text, background_color=bg,
|
||||
text_color=fg, key=key, pad=pad, tooltip=tooltip)
|
||||
text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT)
|
||||
|
||||
def Update(self, value=None, values=None, set_to_index=None, disabled=None, readonly=None):
|
||||
def Update(self, value=None, values=None, set_to_index=None, disabled=None, readonly=None, font=None):
|
||||
if values is not None:
|
||||
try:
|
||||
self.TKCombo['values'] = values
|
||||
|
@ -587,6 +601,8 @@ class InputCombo(Element):
|
|||
self.Readonly = readonly
|
||||
if self.Readonly:
|
||||
self.TKCombo['state'] = 'readonly'
|
||||
if font is not None:
|
||||
self.TKText.configure(font=font)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
|
@ -745,7 +761,7 @@ class Listbox(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
class Radio(Element):
|
||||
def __init__(self, text, group_id, default=False, disabled=False, size=(None, None), auto_size_text=None,
|
||||
background_color=None, text_color=None, font=None, key=None, pad=None, tooltip=None):
|
||||
background_color=None, text_color=None, font=None, key=None, pad=None, tooltip=None, change_submits=False):
|
||||
'''
|
||||
Radio Button Element
|
||||
:param text:
|
||||
|
@ -760,6 +776,7 @@ class Radio(Element):
|
|||
:param key:
|
||||
:param pad:
|
||||
:param tooltip:
|
||||
:param change_submits:
|
||||
'''
|
||||
self.InitialState = default
|
||||
self.Text = text
|
||||
|
@ -767,7 +784,8 @@ class Radio(Element):
|
|||
self.GroupID = group_id
|
||||
self.Value = None
|
||||
self.Disabled = disabled
|
||||
self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR
|
||||
self.TextColor = text_color or DEFAULT_TEXT_COLOR
|
||||
self.ChangeSubmits = change_submits
|
||||
|
||||
super().__init__(ELEM_TYPE_INPUT_RADIO, size=size, auto_size_text=auto_size_text, font=font,
|
||||
background_color=background_color, text_color=self.TextColor, key=key, pad=pad,
|
||||
|
@ -931,7 +949,7 @@ class Spin(Element):
|
|||
class Multiline(Element):
|
||||
def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, size=(None, None),
|
||||
auto_size_text=None, background_color=None, text_color=None, change_submits=False, do_not_clear=False, key=None, focus=False,
|
||||
pad=None, tooltip=None):
|
||||
font=None, pad=None, tooltip=None):
|
||||
'''
|
||||
Multiline Element
|
||||
:param default_text:
|
||||
|
@ -947,6 +965,7 @@ class Multiline(Element):
|
|||
:param focus:
|
||||
:param pad:
|
||||
:param tooltip:
|
||||
:param font:
|
||||
'''
|
||||
self.DefaultText = default_text
|
||||
self.EnterSubmits = enter_submits
|
||||
|
@ -959,10 +978,10 @@ class Multiline(Element):
|
|||
self.ChangeSubmits = change_submits
|
||||
|
||||
super().__init__(ELEM_TYPE_INPUT_MULTILINE, size=size, auto_size_text=auto_size_text, background_color=bg,
|
||||
text_color=fg, key=key, pad=pad, tooltip=tooltip)
|
||||
text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT)
|
||||
return
|
||||
|
||||
def Update(self, value=None, disabled=None, append=False):
|
||||
def Update(self, value=None, disabled=None, append=False, font=None):
|
||||
if value is not None:
|
||||
try:
|
||||
if not append:
|
||||
|
@ -977,10 +996,19 @@ class Multiline(Element):
|
|||
self.TKText.configure(state='disabled')
|
||||
elif disabled == False:
|
||||
self.TKText.configure(state='normal')
|
||||
if font is not None:
|
||||
self.TKText.configure(font=font)
|
||||
|
||||
def Get(self):
|
||||
return self.TKText.get(1.0, tk.END)
|
||||
|
||||
|
||||
def SetFocus(self):
|
||||
try:
|
||||
self.TKText.focus_set()
|
||||
except:
|
||||
pass
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
||||
|
@ -1240,6 +1268,7 @@ class Button(Element):
|
|||
self.Focus = focus
|
||||
self.TKCal = None
|
||||
self.CalendarCloseWhenChosen = None
|
||||
self.DefaultDate_M_D_Y = (None, None, None)
|
||||
self.InitialFolder = initial_folder
|
||||
self.Disabled = disabled
|
||||
|
||||
|
@ -1369,7 +1398,7 @@ class Button(Element):
|
|||
should_submit_window = False
|
||||
root = tk.Toplevel()
|
||||
root.title('Calendar Chooser')
|
||||
self.TKCal = TKCalendar(master=root, firstweekday=calendar.SUNDAY, target_element=target_element, close_when_chosen=self.CalendarCloseWhenChosen )
|
||||
self.TKCal = TKCalendar(master=root, firstweekday=calendar.SUNDAY, target_element=target_element, close_when_chosen=self.CalendarCloseWhenChosen, default_date=self.DefaultDate_M_D_Y )
|
||||
self.TKCal.pack(expand=1, fill='both')
|
||||
root.update()
|
||||
|
||||
|
@ -2067,6 +2096,12 @@ class TkScrollableFrame(tk.Frame):
|
|||
self.TKFrame.config(borderwidth=0, highlightthickness=0)
|
||||
self.config(borderwidth=0, highlightthickness=0)
|
||||
|
||||
# scrollbar = tk.Scrollbar(frame)
|
||||
# scrollbar.pack(side=tk.RIGHT, fill='y')
|
||||
# scrollbar.config(command=treeview.yview)
|
||||
# self.vscrollbar.config(command=self.TKFrame.yview)
|
||||
# self.TKFrame.configure(yscrollcommand=self.vscrollbar.set)
|
||||
|
||||
self.bind('<Configure>', self.set_scrollregion)
|
||||
|
||||
self.bind_mouse_scroll(self.canvas, self.yscroll)
|
||||
|
@ -2182,7 +2217,7 @@ class TKCalendar(tkinter.ttk.Frame):
|
|||
datetime = calendar.datetime.datetime
|
||||
timedelta = calendar.datetime.timedelta
|
||||
|
||||
def __init__(self, master=None, target_element=None, close_when_chosen=True, **kw):
|
||||
def __init__(self, master=None, target_element=None, close_when_chosen=True, default_date=(None, None, None), **kw):
|
||||
"""
|
||||
WIDGET-SPECIFIC OPTIONS
|
||||
|
||||
|
@ -2190,15 +2225,16 @@ class TKCalendar(tkinter.ttk.Frame):
|
|||
selectforeground
|
||||
"""
|
||||
self._TargetElement = target_element
|
||||
default_mon, default_day, default_year = default_date
|
||||
# remove custom options from kw before initializating ttk.Frame
|
||||
fwday = kw.pop('firstweekday', calendar.MONDAY)
|
||||
year = kw.pop('year', self.datetime.now().year)
|
||||
month = kw.pop('month', self.datetime.now().month)
|
||||
year = kw.pop('year', default_year or self.datetime.now().year)
|
||||
month = kw.pop('month', default_mon or self.datetime.now().month)
|
||||
locale = kw.pop('locale', None)
|
||||
sel_bg = kw.pop('selectbackground', '#ecffc4')
|
||||
sel_fg = kw.pop('selectforeground', '#05640e')
|
||||
|
||||
self._date = self.datetime(year, month, 1)
|
||||
self._date = self.datetime(year, month, default_day or 1)
|
||||
self._selection = None # no date selected
|
||||
self._master = master
|
||||
self.close_when_chosen = close_when_chosen
|
||||
|
@ -2582,17 +2618,25 @@ class Tree(Element):
|
|||
self.add_treeview_data(node)
|
||||
|
||||
|
||||
def Update(self, values=None):
|
||||
if values is None:
|
||||
return
|
||||
children = self.TKTreeview.get_children()
|
||||
for i in children:
|
||||
self.TKTreeview.detach(i)
|
||||
self.TKTreeview.delete(i)
|
||||
children = self.TKTreeview.get_children()
|
||||
self.TreeData = values
|
||||
self.add_treeview_data(self.TreeData.root_node)
|
||||
self.SelectedRows = []
|
||||
def Update(self, values=None, key=None, value=None, text=None):
|
||||
if values is not None:
|
||||
children = self.TKTreeview.get_children()
|
||||
for i in children:
|
||||
self.TKTreeview.detach(i)
|
||||
self.TKTreeview.delete(i)
|
||||
children = self.TKTreeview.get_children()
|
||||
self.TreeData = values
|
||||
self.add_treeview_data(self.TreeData.root_node)
|
||||
self.SelectedRows = []
|
||||
if key is not None:
|
||||
item = self.TKTreeview.item(key)
|
||||
if value is not None:
|
||||
self.TKTreeview.item(key, values=value)
|
||||
if text is not None:
|
||||
self.TKTreeview.item(key, text=text)
|
||||
item = self.TKTreeview.item(key)
|
||||
return self
|
||||
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
@ -2624,11 +2668,6 @@ class TreeData(object):
|
|||
parent_node = self.tree_dict[parent]
|
||||
parent_node._Add(node)
|
||||
|
||||
# def _print_node(self, node):
|
||||
# # print(f'Node: {node.text}')
|
||||
# # print(f'Children = {[c.text for c in node.children]}')
|
||||
# for node in node.children:
|
||||
# self._print_node(node)
|
||||
|
||||
def __repr__(self):
|
||||
return self._NodeStr(self.root_node, 1)
|
||||
|
@ -2940,13 +2979,11 @@ class Window(object):
|
|||
else:
|
||||
return self.ReturnValues
|
||||
|
||||
def ReadNonBlocking(self, Message=''):
|
||||
def ReadNonBlocking(self):
|
||||
if self.TKrootDestroyed:
|
||||
return None, None
|
||||
if not self.Shown:
|
||||
self.Show(non_blocking=True)
|
||||
if Message:
|
||||
print(Message)
|
||||
try:
|
||||
rc = self.TKroot.update()
|
||||
except:
|
||||
|
@ -3086,7 +3123,8 @@ class Window(object):
|
|||
self.RootNeedsDestroying = True
|
||||
return None
|
||||
|
||||
def CloseNonBlocking(self):
|
||||
|
||||
def Close(self):
|
||||
if self.TKrootDestroyed:
|
||||
return
|
||||
try:
|
||||
|
@ -3095,16 +3133,16 @@ class Window(object):
|
|||
except:
|
||||
pass
|
||||
|
||||
CloseNonBlockingForm = CloseNonBlocking
|
||||
Close = CloseNonBlockingForm
|
||||
|
||||
CloseNonBlockingForm = Close
|
||||
CloseNonBlocking = Close
|
||||
|
||||
# IT FINALLY WORKED! 29-Oct-2018 was the first time this damned thing got called
|
||||
def OnClosingCallback(self):
|
||||
print('Got closing callback')
|
||||
# print('Got closing callback')
|
||||
self.TKroot.quit() # kick the users out of the mainloop
|
||||
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
||||
self.TKroot.destroy() # kick the users out of the mainloop
|
||||
self.TKrootDestroyed = True
|
||||
|
||||
return
|
||||
|
||||
|
@ -3150,6 +3188,10 @@ class Window(object):
|
|||
except:
|
||||
pass
|
||||
|
||||
def CurrentLocation(self):
|
||||
return int(self.TKroot.winfo_x()), int(self.TKroot.winfo_y())
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
@ -3161,10 +3203,7 @@ class Window(object):
|
|||
for row in self.Rows:
|
||||
for element in row:
|
||||
element.__del__()
|
||||
# try:
|
||||
# del(self.TKroot)
|
||||
# except:
|
||||
# pass
|
||||
|
||||
|
||||
|
||||
FlexForm = Window
|
||||
|
@ -3370,7 +3409,7 @@ def DummyButton(button_text, image_filename=None, image_data=None, image_size=(N
|
|||
|
||||
|
||||
# ------------------------- Calendar Chooser Button lazy function ------------------------- #
|
||||
def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True, image_filename=None, image_data=None, image_size=(None, None),
|
||||
def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True, default_date_m_d_y=(None,None,None), image_filename=None, image_data=None, image_size=(None, None),
|
||||
image_subsample=None, tooltip=None, border_width=None, size=(None, None), auto_size_button=None,
|
||||
button_color=None, disabled=False, font=None, bind_return_key=False, focus=False, pad=None,
|
||||
key=None):
|
||||
|
@ -3380,6 +3419,7 @@ def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True
|
|||
auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled,
|
||||
bind_return_key=bind_return_key, focus=focus, pad=pad, key=key)
|
||||
button.CalendarCloseWhenChosen = close_when_date_chosen
|
||||
button.DefaultDate_M_D_Y = default_date_m_d_y
|
||||
return button
|
||||
|
||||
|
||||
|
@ -3453,6 +3493,8 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
|
|||
button_pressed_text = top_level_form.LastButtonClicked
|
||||
for row_num, row in enumerate(form.Rows):
|
||||
for col_num, element in enumerate(row):
|
||||
if element.Key is not None and WRITE_ONLY_KEY in str(element.Key):
|
||||
continue
|
||||
value = None
|
||||
if element.Type == ELEM_TYPE_COLUMN:
|
||||
element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter
|
||||
|
@ -4199,8 +4241,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
element.TKIntVar = RadVar # store the RadVar in Radio object
|
||||
if default_value: # if this radio is the one selected, set RadVar to match
|
||||
element.TKIntVar.set(value)
|
||||
element.TKRadio = tk.Radiobutton(tk_row_frame, anchor=tk.NW, text=element.Text, width=width,
|
||||
variable=element.TKIntVar, value=value, bd=border_depth, font=font)
|
||||
if element.ChangeSubmits:
|
||||
element.TKRadio = tk.Radiobutton(tk_row_frame, anchor=tk.NW, text=element.Text, width=width,
|
||||
variable=element.TKIntVar, value=value, bd=border_depth, font=font,
|
||||
command=element.RadioHandler)
|
||||
else:
|
||||
element.TKRadio = tk.Radiobutton(tk_row_frame, anchor=tk.NW, text=element.Text, width=width,
|
||||
variable=element.TKIntVar, value=value, bd=border_depth, font=font)
|
||||
if not element.BackgroundColor in (None, COLOR_SYSTEM_DEFAULT):
|
||||
element.TKRadio.configure(background=element.BackgroundColor)
|
||||
element.TKRadio.configure(selectcolor=element.BackgroundColor)
|
||||
|
@ -4643,7 +4690,16 @@ def StartupTK(my_flex_form):
|
|||
|
||||
# print('Starting TK open Windows = {}'.format(ow))
|
||||
if not ow and not my_flex_form.ForceTopLevel:
|
||||
root = tk.Tk()
|
||||
# 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
|
||||
_my_windows.Increment()
|
||||
_my_windows.hidden_master_root = tk.Tk()
|
||||
_my_windows.hidden_master_root.attributes('-alpha', 0) # hide window while building it. makes for smoother 'paint'
|
||||
_my_windows.hidden_master_root.wm_overrideredirect(True)
|
||||
|
||||
# root = tk.Tk() # users windows are no longer using tk.Tk. They are all Toplevel windows
|
||||
root = tk.Toplevel()
|
||||
else:
|
||||
root = tk.Toplevel()
|
||||
|
||||
|
@ -5061,16 +5117,20 @@ _easy_print_data = None # global variable... I'm cheating
|
|||
|
||||
|
||||
class DebugWin(object):
|
||||
def __init__(self, size=(None, None)):
|
||||
def __init__(self, size=(None, None), location=(None, None), font=None, no_titlebar=False, no_button=False, grab_anywhere=False, keep_on_top=False):
|
||||
# Show a form that's a running counter
|
||||
win_size = size if size != (None, None) else DEFAULT_DEBUG_WINDOW_SIZE
|
||||
self.form = Window('Debug Window', auto_size_text=True, font=('Courier New', 12))
|
||||
self.window = Window('Debug Window', no_titlebar=no_titlebar, auto_size_text=True, location=location, font=font or ('Courier New', 10), grab_anywhere=grab_anywhere, keep_on_top=keep_on_top)
|
||||
self.output_element = Output(size=win_size)
|
||||
self.form_rows = [[Text('EasyPrint Output')],
|
||||
[self.output_element],
|
||||
[DummyButton('Quit')]]
|
||||
self.form.AddRows(self.form_rows)
|
||||
self.form.Show(non_blocking=True) # Show a ;non-blocking form, returns immediately
|
||||
if no_button:
|
||||
self.layout = [[self.output_element]]
|
||||
else:
|
||||
self.layout = [
|
||||
[self.output_element],
|
||||
[DummyButton('Quit')]
|
||||
]
|
||||
self.window.AddRows(self.layout)
|
||||
self.window.Read(timeout=0) # Show a non-blocking form, returns immediately
|
||||
return
|
||||
|
||||
def Print(self, *args, **_3to2kwargs):
|
||||
|
@ -5080,45 +5140,43 @@ class DebugWin(object):
|
|||
else: end = None
|
||||
sepchar = sep if sep is not None else ' '
|
||||
endchar = end if end is not None else '\n'
|
||||
|
||||
if self.window is None: # if window was destroyed already, just print
|
||||
print(*args, sep=sepchar, end=endchar)
|
||||
return
|
||||
|
||||
event, values = self.window.Read(timeout=0)
|
||||
if event == 'Quit' or event is None:
|
||||
self.Close()
|
||||
print(*args, sep=sepchar, end=endchar)
|
||||
# for a in args:
|
||||
# msg = str(a)
|
||||
# print(msg, end="", sep=sepchar)
|
||||
# print(1, 2, 3, sep='-')
|
||||
# if end is None:
|
||||
# print("")
|
||||
self.form.ReadNonBlocking()
|
||||
# Add extra check to see if the window was closed... if closed by X sometimes am not told
|
||||
try:
|
||||
state = self.window.TKroot.state()
|
||||
except:
|
||||
self.Close()
|
||||
|
||||
def Close(self):
|
||||
self.form.CloseNonBlockingForm()
|
||||
self.form.__del__()
|
||||
|
||||
|
||||
def Print(*args, **_3to2kwargs):
|
||||
if 'sep' in _3to2kwargs: sep = _3to2kwargs['sep']; del _3to2kwargs['sep']
|
||||
else: sep = None
|
||||
if 'end' in _3to2kwargs: end = _3to2kwargs['end']; del _3to2kwargs['end']
|
||||
else: end = None
|
||||
if 'size' in _3to2kwargs: size = _3to2kwargs['size']; del _3to2kwargs['size']
|
||||
else: size = (None, None)
|
||||
EasyPrint(*args, size=size, end=end, sep=sep)
|
||||
|
||||
self.window.Close()
|
||||
self.window.__del__()
|
||||
self.window = None
|
||||
|
||||
def PrintClose():
|
||||
EasyPrintClose()
|
||||
|
||||
|
||||
def eprint(*args, **_3to2kwargs):
|
||||
if 'sep' in _3to2kwargs: sep = _3to2kwargs['sep']; del _3to2kwargs['sep']
|
||||
else: sep = None
|
||||
if 'end' in _3to2kwargs: end = _3to2kwargs['end']; del _3to2kwargs['end']
|
||||
else: end = None
|
||||
if 'size' in _3to2kwargs: size = _3to2kwargs['size']; del _3to2kwargs['size']
|
||||
else: size = (None, None)
|
||||
EasyPrint(*args, size=size, end=end, sep=sep)
|
||||
|
||||
|
||||
def EasyPrint(*args, **_3to2kwargs):
|
||||
if 'keep_on_top' in _3to2kwargs: keep_on_top = _3to2kwargs['keep_on_top']; del _3to2kwargs['keep_on_top']
|
||||
else: keep_on_top = False
|
||||
if 'grab_anywhere' in _3to2kwargs: grab_anywhere = _3to2kwargs['grab_anywhere']; del _3to2kwargs['grab_anywhere']
|
||||
else: grab_anywhere = False
|
||||
if 'no_button' in _3to2kwargs: no_button = _3to2kwargs['no_button']; del _3to2kwargs['no_button']
|
||||
else: no_button = False
|
||||
if 'no_titlebar' in _3to2kwargs: no_titlebar = _3to2kwargs['no_titlebar']; del _3to2kwargs['no_titlebar']
|
||||
else: no_titlebar = False
|
||||
if 'font' in _3to2kwargs: font = _3to2kwargs['font']; del _3to2kwargs['font']
|
||||
else: font = None
|
||||
if 'location' in _3to2kwargs: location = _3to2kwargs['location']; del _3to2kwargs['location']
|
||||
else: location = (None, None)
|
||||
if 'sep' in _3to2kwargs: sep = _3to2kwargs['sep']; del _3to2kwargs['sep']
|
||||
else: sep = None
|
||||
if 'end' in _3to2kwargs: end = _3to2kwargs['end']; del _3to2kwargs['end']
|
||||
|
@ -5128,30 +5186,18 @@ def EasyPrint(*args, **_3to2kwargs):
|
|||
global _easy_print_data
|
||||
|
||||
if _easy_print_data is None:
|
||||
_easy_print_data = DebugWin(size=size)
|
||||
_easy_print_data = DebugWin(size=size, location=location, font=font, no_titlebar=no_titlebar, no_button=no_button, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top)
|
||||
_easy_print_data.Print(*args, end=end, sep=sep)
|
||||
|
||||
|
||||
def EasyPrintold(*args, **_3to2kwargs):
|
||||
if 'sep' in _3to2kwargs: sep = _3to2kwargs['sep']; del _3to2kwargs['sep']
|
||||
else: sep = None
|
||||
if 'end' in _3to2kwargs: end = _3to2kwargs['end']; del _3to2kwargs['end']
|
||||
else: end = None
|
||||
if 'size' in _3to2kwargs: size = _3to2kwargs['size']; del _3to2kwargs['size']
|
||||
else: size = (None, None)
|
||||
if 'easy_print_data' not in EasyPrint.__dict__: # use a function property to save DebugWin object (static variable)
|
||||
EasyPrint.easy_print_data = DebugWin(size=size)
|
||||
if EasyPrint.easy_print_data is None:
|
||||
EasyPrint.easy_print_data = DebugWin(size=size)
|
||||
EasyPrint.easy_print_data.Print(*args, end=end, sep=sep)
|
||||
Print = EasyPrint
|
||||
eprint = EasyPrint
|
||||
|
||||
|
||||
def EasyPrintClose():
|
||||
if 'easy_print_data' in EasyPrint.__dict__:
|
||||
if EasyPrint.easy_print_data is not None:
|
||||
EasyPrint.easy_print_data._Close()
|
||||
EasyPrint.easy_print_data = None
|
||||
# del EasyPrint.easy_print_data
|
||||
global _easy_print_data
|
||||
if _easy_print_data is not None:
|
||||
_easy_print_data.Close()
|
||||
_easy_print_data = None
|
||||
|
||||
|
||||
# ======================== Scrolled Text Box =====#
|
||||
|
@ -5825,7 +5871,7 @@ def Popup(*args, **_3to2kwargs):
|
|||
pad=((20, 0), 3)))
|
||||
|
||||
if non_blocking:
|
||||
button, values = window.ReadNonBlocking()
|
||||
button, values = window.Read(timeout=0)
|
||||
else:
|
||||
button, values = window.Read()
|
||||
|
||||
|
@ -5972,7 +6018,7 @@ def PopupQuick(*args, **_3to2kwargs):
|
|||
if 'non_blocking' in _3to2kwargs: non_blocking = _3to2kwargs['non_blocking']; del _3to2kwargs['non_blocking']
|
||||
else: non_blocking = True
|
||||
if 'auto_close_duration' in _3to2kwargs: auto_close_duration = _3to2kwargs['auto_close_duration']; del _3to2kwargs['auto_close_duration']
|
||||
else: auto_close_duration = 1
|
||||
else: auto_close_duration = 2
|
||||
if 'auto_close' in _3to2kwargs: auto_close = _3to2kwargs['auto_close']; del _3to2kwargs['auto_close']
|
||||
else: auto_close = True
|
||||
if 'text_color' in _3to2kwargs: text_color = _3to2kwargs['text_color']; del _3to2kwargs['text_color']
|
||||
|
@ -6009,6 +6055,62 @@ def PopupQuick(*args, **_3to2kwargs):
|
|||
font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location)
|
||||
|
||||
|
||||
# --------------------------- PopupQuick - a NonBlocking, Self-closing Popup with no titlebar and no buttons ---------------------------
|
||||
def PopupQuickMessage(*args, **_3to2kwargs):
|
||||
if 'location' in _3to2kwargs: location = _3to2kwargs['location']; del _3to2kwargs['location']
|
||||
else: location = (None, None)
|
||||
if 'keep_on_top' in _3to2kwargs: keep_on_top = _3to2kwargs['keep_on_top']; del _3to2kwargs['keep_on_top']
|
||||
else: keep_on_top = False
|
||||
if 'grab_anywhere' in _3to2kwargs: grab_anywhere = _3to2kwargs['grab_anywhere']; del _3to2kwargs['grab_anywhere']
|
||||
else: grab_anywhere = False
|
||||
if 'no_titlebar' in _3to2kwargs: no_titlebar = _3to2kwargs['no_titlebar']; del _3to2kwargs['no_titlebar']
|
||||
else: no_titlebar = True
|
||||
if 'font' in _3to2kwargs: font = _3to2kwargs['font']; del _3to2kwargs['font']
|
||||
else: font = None
|
||||
if 'line_width' in _3to2kwargs: line_width = _3to2kwargs['line_width']; del _3to2kwargs['line_width']
|
||||
else: line_width = None
|
||||
if 'icon' in _3to2kwargs: icon = _3to2kwargs['icon']; del _3to2kwargs['icon']
|
||||
else: icon = DEFAULT_WINDOW_ICON
|
||||
if 'non_blocking' in _3to2kwargs: non_blocking = _3to2kwargs['non_blocking']; del _3to2kwargs['non_blocking']
|
||||
else: non_blocking = True
|
||||
if 'auto_close_duration' in _3to2kwargs: auto_close_duration = _3to2kwargs['auto_close_duration']; del _3to2kwargs['auto_close_duration']
|
||||
else: auto_close_duration = 2
|
||||
if 'auto_close' in _3to2kwargs: auto_close = _3to2kwargs['auto_close']; del _3to2kwargs['auto_close']
|
||||
else: auto_close = True
|
||||
if 'text_color' in _3to2kwargs: text_color = _3to2kwargs['text_color']; del _3to2kwargs['text_color']
|
||||
else: text_color = None
|
||||
if 'background_color' in _3to2kwargs: background_color = _3to2kwargs['background_color']; del _3to2kwargs['background_color']
|
||||
else: background_color = None
|
||||
if 'button_color' in _3to2kwargs: button_color = _3to2kwargs['button_color']; del _3to2kwargs['button_color']
|
||||
else: button_color = None
|
||||
if 'button_type' in _3to2kwargs: button_type = _3to2kwargs['button_type']; del _3to2kwargs['button_type']
|
||||
else: button_type = POPUP_BUTTONS_NO_BUTTONS
|
||||
"""
|
||||
Show Popup box that doesn't block and closes itself
|
||||
:param args:
|
||||
:param button_type:
|
||||
:param button_color:
|
||||
:param background_color:
|
||||
:param text_color:
|
||||
:param auto_close:
|
||||
:param auto_close_duration:
|
||||
:param non_blocking:
|
||||
:param icon:
|
||||
:param line_width:
|
||||
:param font:
|
||||
:param no_titlebar:
|
||||
:param grab_anywhere:
|
||||
:param keep_on_top:
|
||||
:param location:
|
||||
:return:
|
||||
"""
|
||||
Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color,
|
||||
button_type=button_type,
|
||||
auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon,
|
||||
line_width=line_width,
|
||||
font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location)
|
||||
|
||||
|
||||
# --------------------------- PopupNoTitlebar ---------------------------
|
||||
def PopupNoTitlebar(*args, **_3to2kwargs):
|
||||
if 'location' in _3to2kwargs: location = _3to2kwargs['location']; del _3to2kwargs['location']
|
||||
|
@ -6395,7 +6497,7 @@ def PopupYesNo(*args, **_3to2kwargs):
|
|||
|
||||
def PopupGetFolder(message, default_path='', no_window=False, size=(None, None), button_color=None,
|
||||
background_color=None, text_color=None, icon=DEFAULT_WINDOW_ICON, font=None, no_titlebar=False,
|
||||
grab_anywhere=False, keep_on_top=False, location=(None, None)):
|
||||
grab_anywhere=False, keep_on_top=False, location=(None, None), initial_folder=None):
|
||||
"""
|
||||
Display popup with text entry field and browse button. Browse for folder
|
||||
:param message:
|
||||
|
@ -6413,8 +6515,14 @@ def PopupGetFolder(message, default_path='', no_window=False, size=(None, None),
|
|||
:param location:
|
||||
:return: Contents of text field. None if closed using X or cancelled
|
||||
"""
|
||||
|
||||
global _my_windows
|
||||
|
||||
if no_window:
|
||||
root = tk.Tk()
|
||||
if _my_windows.NumOpenWindows:
|
||||
root = tk.Toplevel()
|
||||
else:
|
||||
root = tk.Tk()
|
||||
try:
|
||||
root.attributes('-alpha', 0) # hide window while building it. makes for smoother 'paint'
|
||||
except:
|
||||
|
@ -6424,7 +6532,7 @@ def PopupGetFolder(message, default_path='', no_window=False, size=(None, None),
|
|||
return folder_name
|
||||
|
||||
layout = [[Text(message, auto_size_text=True, text_color=text_color, background_color=background_color)],
|
||||
[InputText(default_text=default_path, size=size), FolderBrowse()],
|
||||
[InputText(default_text=default_path, size=size), FolderBrowse(initial_folder=initial_folder)],
|
||||
[CloseButton('Ok', size=(5, 1), bind_return_key=True), CloseButton('Cancel', size=(5, 1))]]
|
||||
|
||||
window = Window(title=message, icon=icon, auto_size_text=True, button_color=button_color,
|
||||
|
@ -6446,7 +6554,7 @@ def PopupGetFolder(message, default_path='', no_window=False, size=(None, None),
|
|||
def PopupGetFile(message, default_path='', default_extension='', save_as=False, file_types=(("ALL Files", "*.*"),),
|
||||
no_window=False, size=(None, None), button_color=None, background_color=None, text_color=None,
|
||||
icon=DEFAULT_WINDOW_ICON, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False,
|
||||
location=(None, None)):
|
||||
location=(None, None), initial_folder=None):
|
||||
"""
|
||||
Display popup with text entry field and browse button. Browse for file
|
||||
:param message:
|
||||
|
@ -6467,8 +6575,14 @@ def PopupGetFile(message, default_path='', default_extension='', save_as=False,
|
|||
:param location:
|
||||
:return: string representing the path chosen, None if cancelled or window closed with X
|
||||
"""
|
||||
|
||||
global _my_windows
|
||||
|
||||
if no_window:
|
||||
root = tk.Tk()
|
||||
if _my_windows.NumOpenWindows:
|
||||
root = tk.Toplevel()
|
||||
else:
|
||||
root = tk.Tk()
|
||||
try:
|
||||
root.attributes('-alpha', 0) # hide window while building it. makes for smoother 'paint'
|
||||
except:
|
||||
|
@ -6482,7 +6596,7 @@ def PopupGetFile(message, default_path='', default_extension='', save_as=False,
|
|||
root.destroy()
|
||||
return filename
|
||||
|
||||
browse_button = SaveAs(file_types=file_types) if save_as else FileBrowse(file_types=file_types)
|
||||
browse_button = SaveAs(file_types=file_types, initial_folder=initial_folder) if save_as else FileBrowse(file_types=file_types, initial_folder=initial_folder)
|
||||
|
||||
layout = [[Text(message, auto_size_text=True, text_color=text_color, background_color=background_color)],
|
||||
[InputText(default_text=default_path, size=size), browse_button],
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
|
||||
## Now supports both Python 2.7 & 3
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.13.0-red.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.14.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.13.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.14.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
||||
|
||||
|
@ -3569,6 +3569,8 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it
|
|||
| 3.11.0 & 1.11.0 | Oct 28, 2018
|
||||
| 3.12.0 & 1.12.0 | Oct 28, 2018
|
||||
| 3.13.0 & 1.13.0 | Oct 29, 2018
|
||||
| 3.14.0 & 1.14.0 | Nov 2, 2018
|
||||
|
||||
|
||||
## Release Notes
|
||||
2.3 - Sliders, Listbox's and Image elements (oh my!)
|
||||
|
@ -3797,7 +3799,7 @@ Emergency patch release... going out same day as previous release
|
|||
* Progress meter uses new CloseButton
|
||||
* Popups use new CloseButton
|
||||
|
||||
## 3.13.0 & 1.13.0
|
||||
### 3.13.0 & 1.13.0
|
||||
* Improved multiple window handling of Popups when the X is used to close
|
||||
* Change submits added for:
|
||||
* Multiline
|
||||
|
@ -3808,7 +3810,40 @@ Emergency patch release... going out same day as previous release
|
|||
* Update for Tree Element
|
||||
* Scroll bars for Trees
|
||||
|
||||
|
||||
|
||||
### 3.14.0 & 1.14.0
|
||||
|
||||
- More windowing changes...
|
||||
using a hidden root windowing (Tk())
|
||||
all children are Toplevel() windows
|
||||
Read only setting for:
|
||||
Input Text
|
||||
Multiline
|
||||
Font setting for InputCombo, Multiline
|
||||
change_submits settinf for Radio Element
|
||||
SetFocus for multiline, input elements
|
||||
Default mon, day, year for calendar chooser button
|
||||
Tree element update, added ability to change a single key
|
||||
Message parm removed from ReadNonBlocking
|
||||
Fix for closing windows using X
|
||||
CurrentLocation method for Windows
|
||||
Debug Window options
|
||||
location
|
||||
font
|
||||
no_button
|
||||
no_titlebar
|
||||
grab_anywhere
|
||||
keep_on_top
|
||||
New Print / EasyPrint options
|
||||
location
|
||||
font
|
||||
no_button
|
||||
no_titlebar
|
||||
grab_anywhere
|
||||
keep_on_top
|
||||
New popup, PopupQuickMessage
|
||||
PopupGetFolder, PopupGetFile new initial_folder parm
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
||||
|
@ -3885,6 +3920,8 @@ GNU Lesser General Public License (LGPL 3) +
|
|||
* Tony Crewe (anthony.crewe@gmail.com) Generously provided his classroom materials that he has written to teach a GUI course. If you're an educator and want to trade materials with Tony, he would like to hear from you.
|
||||
* [spectre6000](https://github.com/spectre6000) - Readme updates
|
||||
* [jackyOO7](https://github.com/jackyOO7) - Demo programs. OpenCV with realtime image processing, popup keyboard, input Combo read only option.
|
||||
* [AltoRetrato](https://github.com/AltoRetrato) - Fonts for multiline and combo
|
||||
|
||||
|
||||
## How Do I
|
||||
Finally, I must thank the fine folks at How Do I.
|
||||
|
|
45
readme.md
45
readme.md
|
@ -24,9 +24,9 @@
|
|||
|
||||
## Now supports both Python 2.7 & 3
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.13.0-red.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.14.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.13.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.14.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
||||
|
||||
|
@ -3569,6 +3569,8 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it
|
|||
| 3.11.0 & 1.11.0 | Oct 28, 2018
|
||||
| 3.12.0 & 1.12.0 | Oct 28, 2018
|
||||
| 3.13.0 & 1.13.0 | Oct 29, 2018
|
||||
| 3.14.0 & 1.14.0 | Nov 2, 2018
|
||||
|
||||
|
||||
## Release Notes
|
||||
2.3 - Sliders, Listbox's and Image elements (oh my!)
|
||||
|
@ -3797,7 +3799,7 @@ Emergency patch release... going out same day as previous release
|
|||
* Progress meter uses new CloseButton
|
||||
* Popups use new CloseButton
|
||||
|
||||
## 3.13.0 & 1.13.0
|
||||
### 3.13.0 & 1.13.0
|
||||
* Improved multiple window handling of Popups when the X is used to close
|
||||
* Change submits added for:
|
||||
* Multiline
|
||||
|
@ -3808,7 +3810,40 @@ Emergency patch release... going out same day as previous release
|
|||
* Update for Tree Element
|
||||
* Scroll bars for Trees
|
||||
|
||||
|
||||
|
||||
### 3.14.0 & 1.14.0
|
||||
|
||||
- More windowing changes...
|
||||
using a hidden root windowing (Tk())
|
||||
all children are Toplevel() windows
|
||||
Read only setting for:
|
||||
Input Text
|
||||
Multiline
|
||||
Font setting for InputCombo, Multiline
|
||||
change_submits settinf for Radio Element
|
||||
SetFocus for multiline, input elements
|
||||
Default mon, day, year for calendar chooser button
|
||||
Tree element update, added ability to change a single key
|
||||
Message parm removed from ReadNonBlocking
|
||||
Fix for closing windows using X
|
||||
CurrentLocation method for Windows
|
||||
Debug Window options
|
||||
location
|
||||
font
|
||||
no_button
|
||||
no_titlebar
|
||||
grab_anywhere
|
||||
keep_on_top
|
||||
New Print / EasyPrint options
|
||||
location
|
||||
font
|
||||
no_button
|
||||
no_titlebar
|
||||
grab_anywhere
|
||||
keep_on_top
|
||||
New popup, PopupQuickMessage
|
||||
PopupGetFolder, PopupGetFile new initial_folder parm
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
||||
|
@ -3885,6 +3920,8 @@ GNU Lesser General Public License (LGPL 3) +
|
|||
* Tony Crewe (anthony.crewe@gmail.com) Generously provided his classroom materials that he has written to teach a GUI course. If you're an educator and want to trade materials with Tony, he would like to hear from you.
|
||||
* [spectre6000](https://github.com/spectre6000) - Readme updates
|
||||
* [jackyOO7](https://github.com/jackyOO7) - Demo programs. OpenCV with realtime image processing, popup keyboard, input Combo read only option.
|
||||
* [AltoRetrato](https://github.com/AltoRetrato) - Fonts for multiline and combo
|
||||
|
||||
|
||||
## How Do I
|
||||
Finally, I must thank the fine folks at How Do I.
|
||||
|
|
Loading…
Reference in New Issue