Release 3.17.0
This commit is contained in:
parent
a59dca250d
commit
c371aa68eb
330
PySimpleGUI27.py
330
PySimpleGUI27.py
|
@ -86,6 +86,7 @@ DEFAULT_DEBUG_WINDOW_SIZE = (80, 20)
|
|||
DEFAULT_WINDOW_LOCATION = (None, None)
|
||||
MAX_SCROLLED_TEXT_BOX_HEIGHT = 50
|
||||
DEFAULT_TOOLTIP_TIME = 400
|
||||
DEFAULT_TOOLTIP_OFFSET = (20,-20)
|
||||
#################### COLOR STUFF ####################
|
||||
BLUES = ("#082567", "#0A37A3", "#00345B")
|
||||
PURPLES = ("#480656", "#4F2398", "#380474")
|
||||
|
@ -194,6 +195,10 @@ TIMEOUT_KEY = '__TIMEOUT__'
|
|||
# Key indicating should not create any return values for element
|
||||
WRITE_ONLY_KEY = '__WRITE ONLY__'
|
||||
|
||||
MENU_DISABLED_CHARACTER = '!'
|
||||
MENU_KEY_SEPARATOR = '::'
|
||||
|
||||
|
||||
# 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):
|
||||
|
@ -265,6 +270,7 @@ ELEM_TYPE_TABLE = 'table'
|
|||
ELEM_TYPE_TREE = 'tree'
|
||||
ELEM_TYPE_ERROR = 'error'
|
||||
ELEM_TYPE_SEPARATOR = 'separator'
|
||||
ELEM_TYPE_STATUSBAR = 'statusbar'
|
||||
|
||||
# ------------------------- Popup Buttons Types ------------------------- #
|
||||
POPUP_BUTTONS_YES_NO = 1
|
||||
|
@ -316,11 +322,13 @@ class ToolTip(object):
|
|||
def showtip(self):
|
||||
if self.tipwindow:
|
||||
return
|
||||
x = self.widget.winfo_rootx() + 20
|
||||
y = self.widget.winfo_rooty() + self.widget.winfo_height() - 20
|
||||
x = self.widget.winfo_rootx() + DEFAULT_TOOLTIP_OFFSET[0]
|
||||
y = self.widget.winfo_rooty() + self.widget.winfo_height() + DEFAULT_TOOLTIP_OFFSET[1]
|
||||
self.tipwindow = tk.Toplevel(self.widget)
|
||||
self.tipwindow.wm_overrideredirect(True)
|
||||
self.tipwindow.wm_geometry("+%d+%d" % (x, y))
|
||||
self.tipwindow.wm_attributes("-topmost", 1)
|
||||
|
||||
label = tkinter.ttk.Label(self.tipwindow, text=self.text, justify=tk.LEFT,
|
||||
background="#ffffe0", relief=tk.SOLID, borderwidth=1)
|
||||
label.pack()
|
||||
|
@ -489,7 +497,7 @@ class Element(object):
|
|||
class InputText(Element):
|
||||
def __init__(self, default_text='', size=(None, None), disabled=False, password_char='',
|
||||
justification=None, background_color=None, text_color=None, font=None, tooltip=None,
|
||||
change_submits=False,
|
||||
change_submits=False, enable_events=False,
|
||||
do_not_clear=False, key=None, focus=False, pad=None):
|
||||
'''
|
||||
Input a line of text Element
|
||||
|
@ -506,11 +514,11 @@ class InputText(Element):
|
|||
self.do_not_clear = do_not_clear
|
||||
self.Justification = justification
|
||||
self.Disabled = disabled
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
super().__init__(ELEM_TYPE_INPUT_TEXT, size=size, background_color=bg, text_color=fg, key=key, pad=pad,
|
||||
font=font, tooltip=tooltip)
|
||||
|
||||
def Update(self, value=None, disabled=None):
|
||||
def Update(self, value=None, disabled=None, select=None):
|
||||
if disabled is True:
|
||||
self.TKEntry['state'] = 'disabled'
|
||||
elif disabled is False:
|
||||
|
@ -521,6 +529,9 @@ class InputText(Element):
|
|||
except:
|
||||
pass
|
||||
self.DefaultText = value
|
||||
if select:
|
||||
self.TKEntry.select_range(0, 'end')
|
||||
|
||||
|
||||
def Get(self):
|
||||
try:
|
||||
|
@ -550,7 +561,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,
|
||||
text_color=None, change_submits=False, enable_events=False, disabled=False, key=None, pad=None, tooltip=None,
|
||||
readonly=False, font=None):
|
||||
'''
|
||||
Input Combo Box Element (also called Dropdown box)
|
||||
|
@ -561,7 +572,7 @@ class InputCombo(Element):
|
|||
'''
|
||||
self.Values = values
|
||||
self.DefaultValue = default_value
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.TKCombo = None
|
||||
# self.InitializeAsDisabled = disabled
|
||||
self.Disabled = disabled
|
||||
|
@ -682,9 +693,7 @@ InputOptionMenu = OptionMenu
|
|||
# Listbox #
|
||||
# ---------------------------------------------------------------------- #
|
||||
class Listbox(Element):
|
||||
def __init__(self, values, default_values=None, select_mode=None, change_submits=False, bind_return_key=False,
|
||||
size=(None, None), disabled=False, auto_size_text=None, font=None, background_color=None,
|
||||
text_color=None, key=None, pad=None, tooltip=None):
|
||||
def __init__(self, values, default_values=None, select_mode=None, change_submits=False,enable_events=False, bind_return_key=False, size=(None, None), disabled=False, auto_size_text=None, font=None, background_color=None, text_color=None, key=None, pad=None, tooltip=None):
|
||||
'''
|
||||
Listbox Element
|
||||
:param values:
|
||||
|
@ -705,7 +714,7 @@ class Listbox(Element):
|
|||
self.Values = values
|
||||
self.DefaultValues = default_values
|
||||
self.TKListbox = None
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.BindReturnKey = bind_return_key
|
||||
self.Disabled = disabled
|
||||
if select_mode == LISTBOX_SELECT_MODE_BROWSE:
|
||||
|
@ -724,7 +733,7 @@ class Listbox(Element):
|
|||
super().__init__(ELEM_TYPE_INPUT_LISTBOX, size=size, auto_size_text=auto_size_text, font=font,
|
||||
background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip)
|
||||
|
||||
def Update(self, values=None, disabled=None):
|
||||
def Update(self, values=None, disabled=None, set_to_index=None):
|
||||
if disabled == True:
|
||||
self.TKListbox.configure(state='disabled')
|
||||
elif disabled == False:
|
||||
|
@ -735,6 +744,14 @@ class Listbox(Element):
|
|||
self.TKListbox.insert(tk.END, item)
|
||||
self.TKListbox.selection_set(0, 0)
|
||||
self.Values = values
|
||||
if set_to_index is not None:
|
||||
self.TKListbox.selection_clear(0)
|
||||
try:
|
||||
self.TKListbox.selection_set(set_to_index, set_to_index)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def SetValue(self, values):
|
||||
for index, item in enumerate(self.Values):
|
||||
|
@ -763,7 +780,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, change_submits=False):
|
||||
background_color=None, text_color=None, font=None, key=None, pad=None, tooltip=None, change_submits=False, enable_events=False):
|
||||
'''
|
||||
Radio Button Element
|
||||
:param text:
|
||||
|
@ -787,7 +804,7 @@ class Radio(Element):
|
|||
self.Value = None
|
||||
self.Disabled = disabled
|
||||
self.TextColor = text_color or DEFAULT_TEXT_COLOR
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
|
||||
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,
|
||||
|
@ -819,7 +836,7 @@ class Radio(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
class Checkbox(Element):
|
||||
def __init__(self, text, default=False, size=(None, None), auto_size_text=None, font=None, background_color=None,
|
||||
text_color=None, change_submits=False, disabled=False, key=None, pad=None, tooltip=None):
|
||||
text_color=None, change_submits=False,enable_events=False, disabled=False, key=None, pad=None, tooltip=None):
|
||||
'''
|
||||
Checkbox Element
|
||||
:param text:
|
||||
|
@ -841,7 +858,7 @@ class Checkbox(Element):
|
|||
self.TKCheckbutton = None
|
||||
self.Disabled = disabled
|
||||
self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
|
||||
super().__init__(ELEM_TYPE_INPUT_CHECKBOX, size=size, auto_size_text=auto_size_text, font=font,
|
||||
background_color=background_color, text_color=self.TextColor, key=key, pad=pad,
|
||||
|
@ -879,7 +896,7 @@ Check = Checkbox
|
|||
class Spin(Element):
|
||||
# Values = None
|
||||
# TKSpinBox = None
|
||||
def __init__(self, values, initial_value=None, disabled=False, change_submits=False, size=(None, None),
|
||||
def __init__(self, values, initial_value=None, disabled=False, change_submits=False,enable_events=False , size=(None, None),
|
||||
auto_size_text=None, font=None, background_color=None, text_color=None, key=None, pad=None,
|
||||
tooltip=None):
|
||||
'''
|
||||
|
@ -899,7 +916,7 @@ class Spin(Element):
|
|||
'''
|
||||
self.Values = values
|
||||
self.DefaultValue = initial_value
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.TKSpinBox = None
|
||||
self.Disabled = disabled
|
||||
bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR
|
||||
|
@ -950,8 +967,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,
|
||||
font=None, pad=None, tooltip=None):
|
||||
auto_size_text=None, background_color=None, text_color=None, change_submits=False, enable_events=False,do_not_clear=False, key=None, focus=False, font=None, pad=None, tooltip=None):
|
||||
'''
|
||||
Multiline Element
|
||||
:param default_text:
|
||||
|
@ -962,13 +978,16 @@ class Multiline(Element):
|
|||
:param auto_size_text:
|
||||
:param background_color:
|
||||
:param text_color:
|
||||
:param change_submits:
|
||||
:param enable_events:
|
||||
:param do_not_clear:
|
||||
:param key:
|
||||
:param focus:
|
||||
:param font:
|
||||
:param pad:
|
||||
:param tooltip:
|
||||
:param font:
|
||||
'''
|
||||
|
||||
self.DefaultText = default_text
|
||||
self.EnterSubmits = enter_submits
|
||||
bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR
|
||||
|
@ -977,7 +996,7 @@ class Multiline(Element):
|
|||
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
|
||||
self.Autoscroll = autoscroll
|
||||
self.Disabled = disabled
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
|
||||
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, font=font or DEFAULT_FONT)
|
||||
|
@ -1023,8 +1042,7 @@ class Multiline(Element):
|
|||
# Text #
|
||||
# ---------------------------------------------------------------------- #
|
||||
class Text(Element):
|
||||
def __init__(self, text, size=(None, None), auto_size_text=None, click_submits=None, relief=None, font=None,
|
||||
text_color=None, background_color=None, justification=None, pad=None, key=None, tooltip=None):
|
||||
def __init__(self, text, size=(None, None), auto_size_text=None, click_submits=False, enable_events=False, relief=None, font=None, text_color=None, background_color=None, justification=None, pad=None, key=None, tooltip=None):
|
||||
'''
|
||||
Text Element
|
||||
:param text:
|
||||
|
@ -1044,7 +1062,7 @@ class Text(Element):
|
|||
self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR
|
||||
self.Justification = justification
|
||||
self.Relief = relief
|
||||
self.ClickSubmits = click_submits
|
||||
self.ClickSubmits = click_submits or enable_events
|
||||
if background_color is None:
|
||||
bg = DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR
|
||||
else:
|
||||
|
@ -1074,6 +1092,56 @@ Txt = Text
|
|||
T = Text
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# StatusBar #
|
||||
# ---------------------------------------------------------------------- #
|
||||
class StatusBar(Element):
|
||||
def __init__(self, text, size=(None, None), auto_size_text=None, click_submits=None, enable_events=False, relief=RELIEF_SUNKEN, font=None,
|
||||
text_color=None, background_color=None, justification=None, pad=None, key=None, tooltip=None):
|
||||
'''
|
||||
Text Element
|
||||
:param text:
|
||||
:param size:
|
||||
:param auto_size_text:
|
||||
:param click_submits:
|
||||
:param relief:
|
||||
:param font:
|
||||
:param text_color:
|
||||
:param background_color:
|
||||
:param justification:
|
||||
:param pad:
|
||||
:param key:
|
||||
:param tooltip:
|
||||
'''
|
||||
self.DisplayText = text
|
||||
self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR
|
||||
self.Justification = justification
|
||||
self.Relief = relief
|
||||
self.ClickSubmits = click_submits or enable_events
|
||||
if background_color is None:
|
||||
bg = DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR
|
||||
else:
|
||||
bg = background_color
|
||||
super().__init__(ELEM_TYPE_STATUSBAR, size=size, auto_size_text=auto_size_text, background_color=bg, font=font or DEFAULT_FONT, text_color=self.TextColor, pad=pad, key=key, tooltip=tooltip)
|
||||
return
|
||||
|
||||
def Update(self, value=None, background_color=None, text_color=None, font=None):
|
||||
if value is not None:
|
||||
self.DisplayText = value
|
||||
stringvar = self.TKStringVar
|
||||
stringvar.set(value)
|
||||
if background_color is not None:
|
||||
self.TKText.configure(background=background_color)
|
||||
if text_color is not None:
|
||||
self.TKText.configure(fg=text_color)
|
||||
if font is not None:
|
||||
self.TKText.configure(font=font)
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# TKProgressBar #
|
||||
# Emulate the TK ProgressBar using canvas and rectangles
|
||||
|
@ -1220,11 +1288,8 @@ class Output(Element):
|
|||
|
||||
def Update(self, value=None):
|
||||
if value is not None:
|
||||
# try:
|
||||
self._TKOut.output.delete('1.0', tk.END)
|
||||
self._TKOut.output.insert(tk.END, value)
|
||||
# except:
|
||||
# pass
|
||||
|
||||
|
||||
def __del__(self):
|
||||
|
@ -1240,7 +1305,7 @@ class Output(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
class Button(Element):
|
||||
def __init__(self, button_text='', button_type=BUTTON_TYPE_READ_FORM, target=(None, None), tooltip=None,
|
||||
file_types=(("ALL Files", "*.*"),), initial_folder=None, disabled=False, change_submits=False, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, focus=False, pad=None, key=None):
|
||||
file_types=(("ALL Files", "*.*"),), initial_folder=None, disabled=False, change_submits=False, enable_events=False, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, focus=False, pad=None, key=None):
|
||||
'''
|
||||
Button Element
|
||||
:param button_text:
|
||||
|
@ -1284,7 +1349,7 @@ class Button(Element):
|
|||
self.DefaultDate_M_D_Y = (None, None, None)
|
||||
self.InitialFolder = initial_folder
|
||||
self.Disabled = disabled
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
|
||||
super().__init__(ELEM_TYPE_BUTTON, size=size, font=font, pad=pad, key=key, tooltip=tooltip)
|
||||
return
|
||||
|
@ -1594,7 +1659,7 @@ class Canvas(Element):
|
|||
# Graph #
|
||||
# ---------------------------------------------------------------------- #
|
||||
class Graph(Element):
|
||||
def __init__(self, canvas_size, graph_bottom_left, graph_top_right, background_color=None, pad=None, change_submits=False, drag_submits=False, key=None,
|
||||
def __init__(self, canvas_size, graph_bottom_left, graph_top_right, background_color=None, pad=None, change_submits=False, drag_submits=False, enable_events=False, key=None,
|
||||
tooltip=None):
|
||||
'''
|
||||
Graph Element
|
||||
|
@ -1611,7 +1676,7 @@ class Graph(Element):
|
|||
self.TopRight = graph_top_right
|
||||
self._TKCanvas = None
|
||||
self._TKCanvas2 = None
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.DragSubmits = drag_submits
|
||||
self.ClickPosition = (None, None)
|
||||
self.MouseButtonDown = False
|
||||
|
@ -1991,7 +2056,7 @@ class Tab(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
class TabGroup(Element):
|
||||
def __init__(self, layout, tab_location=None, title_color=None, selected_title_color=None, background_color=None,
|
||||
font=None, change_submits=False, pad=None, border_width=None, theme=None, key=None, tooltip=None):
|
||||
font=None, change_submits=False, enable_events=False,pad=None, border_width=None, theme=None, key=None, tooltip=None):
|
||||
'''
|
||||
TabGroup Element
|
||||
:param layout:
|
||||
|
@ -2020,7 +2085,7 @@ class TabGroup(Element):
|
|||
self.BorderWidth = border_width
|
||||
self.Theme = theme
|
||||
self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.TabLocation = tab_location
|
||||
|
||||
self.Layout(layout)
|
||||
|
@ -2073,7 +2138,7 @@ class TabGroup(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
class Slider(Element):
|
||||
def __init__(self, range=(None, None), default_value=None, resolution=None, tick_interval=None, orientation=None,
|
||||
border_width=None, relief=None, change_submits=False, disabled=False, size=(None, None), font=None,
|
||||
border_width=None, relief=None, change_submits=False, enable_events=False, disabled=False, size=(None, None), font=None,
|
||||
background_color=None, text_color=None, key=None, pad=None, tooltip=None):
|
||||
'''
|
||||
Slider Element
|
||||
|
@ -2100,7 +2165,7 @@ class Slider(Element):
|
|||
self.BorderWidth = border_width if border_width else DEFAULT_SLIDER_BORDER_WIDTH
|
||||
self.Relief = relief if relief else DEFAULT_SLIDER_RELIEF
|
||||
self.Resolution = 1 if resolution is None else resolution
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.Disabled = disabled
|
||||
self.TickInterval = tick_interval
|
||||
temp_size = size
|
||||
|
@ -2523,17 +2588,42 @@ class Menu(Element):
|
|||
self.MenuDefinition = menu_definition
|
||||
self.TKMenu = None
|
||||
self.Tearoff = tearoff
|
||||
self.MenuItemChosen = None
|
||||
|
||||
super().__init__(ELEM_TYPE_MENUBAR, background_color=background_color, size=size, pad=pad, key=key)
|
||||
return
|
||||
|
||||
def MenuItemChosenCallback(self, item_chosen):
|
||||
# print('IN MENU ITEM CALLBACK', item_chosen)
|
||||
self.MenuItemChosen = item_chosen
|
||||
self.ParentForm.LastButtonClicked = item_chosen
|
||||
self.ParentForm.FormRemainedOpen = True
|
||||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
|
||||
|
||||
|
||||
def Update(self, menu_definition):
|
||||
self.MenuDefinition = menu_definition
|
||||
self.TKMenu = tk.Menu(self.ParentForm.TKroot, tearoff=self.Tearoff) # create the menubar
|
||||
menubar = self.TKMenu
|
||||
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.ParentForm.TKroot.configure(menu=self.TKMenu)
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
||||
|
@ -2543,9 +2633,9 @@ class Menu(Element):
|
|||
# ---------------------------------------------------------------------- #
|
||||
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,
|
||||
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,
|
||||
size=(None, None), change_submits=False, bind_return_key=False, pad=None, key=None, tooltip=None):
|
||||
size=(None, None), change_submits=False, enable_events=False, bind_return_key=False, pad=None, key=None, tooltip=None):
|
||||
'''
|
||||
Table Element
|
||||
:param values:
|
||||
|
@ -2557,11 +2647,17 @@ class Table(Element):
|
|||
:param max_col_width:
|
||||
:param select_mode:
|
||||
:param display_row_numbers:
|
||||
:param num_rows:
|
||||
:param row_height:
|
||||
:param font:
|
||||
:param justification:
|
||||
:param text_color:
|
||||
:param background_color:
|
||||
:param alternating_row_color:
|
||||
:param size:
|
||||
:param change_submits:
|
||||
:param enable_events:
|
||||
:param bind_return_key:
|
||||
:param pad:
|
||||
:param key:
|
||||
:param tooltip:
|
||||
|
@ -2580,10 +2676,11 @@ class Table(Element):
|
|||
self.SelectMode = select_mode
|
||||
self.DisplayRowNumbers = display_row_numbers
|
||||
self.NumRows = num_rows if num_rows is not None else size[1]
|
||||
self.RowHeight = row_height
|
||||
self.TKTreeview = None
|
||||
self.AlternatingRowColor = alternating_row_color
|
||||
self.SelectedRows = []
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
self.BindReturnKey = bind_return_key
|
||||
self.StartingRowNumber = 0 # When displaying row numbers, where to start
|
||||
self.RowHeaderText = 'Row'
|
||||
|
@ -2645,7 +2742,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, show_expanded=False, change_submits=False, font=None,
|
||||
def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, show_expanded=False, change_submits=False, enable_events=False, font=None,
|
||||
justification='right', text_color=None, background_color=None, num_rows=None, pad=None, key=None,
|
||||
tooltip=None):
|
||||
'''
|
||||
|
@ -2683,7 +2780,7 @@ class Tree(Element):
|
|||
self.Col0Width = col0_width
|
||||
self.TKTreeview = None
|
||||
self.SelectedRows = []
|
||||
self.ChangeSubmits = change_submits
|
||||
self.ChangeSubmits = change_submits or enable_events
|
||||
|
||||
super().__init__(ELEM_TYPE_TREE, text_color=text_color, background_color=background_color, font=font, pad=pad,
|
||||
key=key, tooltip=tooltip)
|
||||
|
@ -2890,6 +2987,7 @@ class Window(object):
|
|||
self.DisableClose = disable_close
|
||||
self._Hidden = False
|
||||
self._Size = size
|
||||
self.XFound = False
|
||||
|
||||
# ------------------------- Add ONE Row to Form ------------------------- #
|
||||
def AddRow(self, *args):
|
||||
|
@ -2915,12 +3013,13 @@ class Window(object):
|
|||
return self
|
||||
|
||||
def LayoutAndRead(self, rows, non_blocking=False):
|
||||
self.AddRows(rows)
|
||||
self.Show(non_blocking=non_blocking)
|
||||
return self.ReturnValues
|
||||
raise DeprecationWarning('LayoutAndRead is no longer supported... change your call window.Layout(layout).Read()')
|
||||
# self.AddRows(rows)
|
||||
# self.Show(non_blocking=non_blocking)
|
||||
# return self.ReturnValues
|
||||
|
||||
def LayoutAndShow(self, rows):
|
||||
raise DeprecationWarning('LayoutAndShow is no longer supported... change your call to LayoutAndRead')
|
||||
raise DeprecationWarning('LayoutAndShow is no longer supported... ')
|
||||
|
||||
# ------------------------- ShowForm THIS IS IT! ------------------------- #
|
||||
def Show(self, non_blocking=False):
|
||||
|
@ -3036,7 +3135,7 @@ class Window(object):
|
|||
except:
|
||||
self.TKrootDestroyed = True
|
||||
_my_windows.Decrement()
|
||||
print('ROOT Destroyed')
|
||||
# print('ROOT Destroyed')
|
||||
results = BuildResults(self, False, self)
|
||||
if results[0] != None and results[0] != timeout_key:
|
||||
return results
|
||||
|
@ -3088,6 +3187,12 @@ class Window(object):
|
|||
self.LastButtonClicked = None
|
||||
return results
|
||||
else:
|
||||
if not self.XFound and self.Timeout != 0 and self.Timeout is not None and self.ReturnValues[
|
||||
0] is None: # Special Qt case because returning for no reason so fake timeout
|
||||
self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout
|
||||
elif not self.XFound and self.ReturnValues[0] is None: # TODO HIGHLY EXPERIMENTAL... added due to tray icon interaction
|
||||
# print("*** Faking timeout ***")
|
||||
self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout
|
||||
return self.ReturnValues
|
||||
|
||||
def ReadNonBlocking(self):
|
||||
|
@ -3096,7 +3201,8 @@ class Window(object):
|
|||
self.TKroot.quit()
|
||||
self.TKroot.destroy()
|
||||
except:
|
||||
print('DESTROY FAILED')
|
||||
pass
|
||||
# print('DESTROY FAILED')
|
||||
return None, None
|
||||
if not self.Shown:
|
||||
self.Show(non_blocking=True)
|
||||
|
@ -3105,10 +3211,10 @@ class Window(object):
|
|||
except:
|
||||
self.TKrootDestroyed = True
|
||||
_my_windows.Decrement()
|
||||
print("read failed")
|
||||
# print("read failed")
|
||||
# return None, None
|
||||
if self.RootNeedsDestroying:
|
||||
print('*** DESTROYING LATE ***', self.ReturnValues)
|
||||
# print('*** DESTROYING LATE ***', self.ReturnValues)
|
||||
self.TKroot.destroy()
|
||||
_my_windows.Decrement()
|
||||
self.Values = None
|
||||
|
@ -3268,6 +3374,7 @@ class Window(object):
|
|||
# print('Got closing callback', self.DisableClose)
|
||||
if self.DisableClose:
|
||||
return
|
||||
self.XFound = True
|
||||
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
||||
self.TKroot.quit() # kick the users out of the mainloop
|
||||
self.TKroot.destroy() # kick the users out of the mainloop
|
||||
|
@ -3375,45 +3482,45 @@ FlexForm = Window
|
|||
|
||||
# ------------------------- FOLDER BROWSE Element lazy function ------------------------- #
|
||||
def FolderBrowse(button_text='Browse', target=(ThisRow, -1), initial_folder=None, tooltip=None, size=(None, None),
|
||||
auto_size_button=None, button_color=None, disabled=False, change_submits=False, font=None, pad=None, key=None):
|
||||
auto_size_button=None, button_color=None, disabled=False, change_submits=False, enable_events=False,font=None, pad=None, key=None):
|
||||
return Button(button_text=button_text, button_type=BUTTON_TYPE_BROWSE_FOLDER, target=target,
|
||||
initial_folder=initial_folder, tooltip=tooltip, size=size, auto_size_button=auto_size_button,
|
||||
disabled=disabled, button_color=button_color,change_submits=change_submits, font=font, pad=pad, key=key)
|
||||
disabled=disabled, button_color=button_color,change_submits=change_submits, enable_events=enable_events, font=font, pad=pad, key=key)
|
||||
|
||||
|
||||
# ------------------------- FILE BROWSE Element lazy function ------------------------- #
|
||||
def FileBrowse(button_text='Browse', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), initial_folder=None,
|
||||
tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None, disabled=False,
|
||||
tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, enable_events=False, font=None, disabled=False,
|
||||
pad=None, key=None):
|
||||
return Button(button_text=button_text, button_type=BUTTON_TYPE_BROWSE_FILE, target=target, file_types=file_types,
|
||||
initial_folder=initial_folder, tooltip=tooltip, size=size, auto_size_button=auto_size_button, change_submits=change_submits, disabled=disabled, button_color=button_color, font=font, pad=pad, key=key)
|
||||
initial_folder=initial_folder, tooltip=tooltip, size=size, auto_size_button=auto_size_button, change_submits=change_submits, enable_events=enable_events, disabled=disabled, button_color=button_color, font=font, pad=pad, key=key)
|
||||
|
||||
|
||||
# ------------------------- FILES BROWSE Element (Multiple file selection) lazy function ------------------------- #
|
||||
def FilesBrowse(button_text='Browse', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), disabled=False,
|
||||
initial_folder=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False,
|
||||
initial_folder=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False,enable_events=False,
|
||||
font=None, pad=None, key=None):
|
||||
return Button(button_text=button_text, button_type=BUTTON_TYPE_BROWSE_FILES, target=target, file_types=file_types,
|
||||
initial_folder=initial_folder,change_submits=change_submits, tooltip=tooltip, size=size, auto_size_button=auto_size_button,
|
||||
initial_folder=initial_folder,change_submits=change_submits, enable_events=enable_events, tooltip=tooltip, size=size, auto_size_button=auto_size_button,
|
||||
disabled=disabled, button_color=button_color, font=font, pad=pad, key=key)
|
||||
|
||||
|
||||
# ------------------------- FILE BROWSE Element lazy function ------------------------- #
|
||||
def FileSaveAs(button_text='Save As...', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), initial_folder=None,
|
||||
disabled=False, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None,
|
||||
disabled=False, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, enable_events=False, font=None,
|
||||
pad=None, key=None):
|
||||
return Button(button_text=button_text, button_type=BUTTON_TYPE_SAVEAS_FILE, target=target, file_types=file_types,
|
||||
initial_folder=initial_folder, tooltip=tooltip, size=size, disabled=disabled,
|
||||
auto_size_button=auto_size_button, button_color=button_color, change_submits=change_submits, font=font, pad=pad, key=key)
|
||||
auto_size_button=auto_size_button, button_color=button_color, change_submits=change_submits, enable_events=enable_events, font=font, pad=pad, key=key)
|
||||
|
||||
|
||||
# ------------------------- SAVE AS Element lazy function ------------------------- #
|
||||
def SaveAs(button_text='Save As...', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), initial_folder=None,
|
||||
disabled=False, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None,
|
||||
disabled=False, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, enable_events=False, font=None,
|
||||
pad=None, key=None):
|
||||
return Button(button_text=button_text, button_type=BUTTON_TYPE_SAVEAS_FILE, target=target, file_types=file_types,
|
||||
initial_folder=initial_folder, tooltip=tooltip, size=size, disabled=disabled,
|
||||
auto_size_button=auto_size_button, button_color=button_color, change_submits=change_submits, font=font, pad=pad, key=key)
|
||||
auto_size_button=auto_size_button, button_color=button_color, change_submits=change_submits, enable_events=enable_events,font=font, pad=pad, key=key)
|
||||
|
||||
|
||||
# ------------------------- SAVE BUTTON Element lazy function ------------------------- #
|
||||
|
@ -3766,6 +3873,11 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
|
|||
value = element.SelectedRows
|
||||
elif element.Type == ELEM_TYPE_GRAPH:
|
||||
value = element.ClickPosition
|
||||
elif element.Type == ELEM_TYPE_MENUBAR:
|
||||
if element.MenuItemChosen is not None:
|
||||
button_pressed_text = top_level_form.LastButtonClicked = element.MenuItemChosen
|
||||
value = element.MenuItemChosen
|
||||
element.MenuItemChosen = None
|
||||
else:
|
||||
value = None
|
||||
|
||||
|
@ -3919,7 +4031,17 @@ if sys.version_info[0] >= 3:
|
|||
if sub_menu_info == '---':
|
||||
top_menu.add('separator')
|
||||
else:
|
||||
top_menu.add_command(label=sub_menu_info, underline=pos,
|
||||
try:
|
||||
item_without_key = sub_menu_info[:sub_menu_info.index(MENU_KEY_SEPARATOR)]
|
||||
except:
|
||||
item_without_key = sub_menu_info
|
||||
|
||||
if item_without_key[0] == MENU_DISABLED_CHARACTER:
|
||||
top_menu.add_command(label=item_without_key[len(MENU_DISABLED_CHARACTER):], underline=pos,
|
||||
command=lambda: Menu.MenuItemChosenCallback(element, sub_menu_info))
|
||||
top_menu.entryconfig(item_without_key[len(MENU_DISABLED_CHARACTER):], state='disabled')
|
||||
else:
|
||||
top_menu.add_command(label=item_without_key, underline=pos,
|
||||
command=lambda: Menu.MenuItemChosenCallback(element, sub_menu_info))
|
||||
else:
|
||||
i = 0
|
||||
|
@ -3932,7 +4054,10 @@ if sys.version_info[0] >= 3:
|
|||
if pos != -1:
|
||||
if pos == 0 or sub_menu_info[i][pos - 1] != "\\":
|
||||
sub_menu_info[i] = sub_menu_info[i][:pos] + sub_menu_info[i][pos + 1:]
|
||||
top_menu.add_cascade(label=sub_menu_info[i], menu=new_menu, underline=pos)
|
||||
if sub_menu_info[i][0] == MENU_DISABLED_CHARACTER:
|
||||
top_menu.add_cascade(label=sub_menu_info[i][len(MENU_DISABLED_CHARACTER):], menu=new_menu, underline=pos, state='disabled')
|
||||
else:
|
||||
top_menu.add_cascade(label=sub_menu_info[i], menu=new_menu, underline=pos)
|
||||
AddMenuItem(new_menu, sub_menu_info[i + 1], element, is_sub_menu=True)
|
||||
i += 1 # skip the next one
|
||||
else:
|
||||
|
@ -3952,7 +4077,17 @@ else:
|
|||
if sub_menu_info == '---':
|
||||
top_menu.add('separator')
|
||||
else:
|
||||
top_menu.add_command(label=sub_menu_info, underline=pos,
|
||||
try:
|
||||
item_without_key = sub_menu_info[:sub_menu_info.index(MENU_KEY_SEPARATOR)]
|
||||
except:
|
||||
item_without_key = sub_menu_info
|
||||
|
||||
if item_without_key[0] == MENU_DISABLED_CHARACTER:
|
||||
top_menu.add_command(label=item_without_key[len(MENU_DISABLED_CHARACTER):], underline=pos,
|
||||
command=lambda: Menu.MenuItemChosenCallback(element, sub_menu_info))
|
||||
top_menu.entryconfig(item_without_key[len(MENU_DISABLED_CHARACTER):], state='disabled')
|
||||
else:
|
||||
top_menu.add_command(label=item_without_key, underline=pos,
|
||||
command=lambda: Menu.MenuItemChosenCallback(element, sub_menu_info))
|
||||
else:
|
||||
i = 0
|
||||
|
@ -3965,7 +4100,10 @@ else:
|
|||
if pos != -1:
|
||||
if pos == 0 or sub_menu_info[i][pos - 1] != "\\":
|
||||
sub_menu_info[i] = sub_menu_info[i][:pos] + sub_menu_info[i][pos + 1:]
|
||||
top_menu.add_cascade(label=sub_menu_info[i], menu=new_menu, underline=pos)
|
||||
if sub_menu_info[i][0] == MENU_DISABLED_CHARACTER:
|
||||
top_menu.add_cascade(label=sub_menu_info[i][len(MENU_DISABLED_CHARACTER):], menu=new_menu, underline=pos, state='disabled')
|
||||
else:
|
||||
top_menu.add_cascade(label=sub_menu_info[i], menu=new_menu, underline=pos)
|
||||
AddMenuItem(new_menu, sub_menu_info[i + 1], element, is_sub_menu=True)
|
||||
i += 1 # skip the next one
|
||||
else:
|
||||
|
@ -4528,7 +4666,12 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
if pos != -1:
|
||||
if pos == 0 or menu_entry[0][pos - 1] != "\\":
|
||||
menu_entry[0] = menu_entry[0][:pos] + menu_entry[0][pos + 1:]
|
||||
menubar.add_cascade(label=menu_entry[0], menu=baritem, underline=pos)
|
||||
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], element)
|
||||
toplevel_form.TKroot.configure(menu=element.TKMenu)
|
||||
|
@ -4723,6 +4866,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
fieldbackground=element.BackgroundColor)
|
||||
if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT:
|
||||
tkinter.ttk.Style().configure("Treeview", foreground=element.TextColor)
|
||||
if element.RowHeight is not None:
|
||||
tkinter.ttk.Style().configure("Treeview", rowheight=element.RowHeight)
|
||||
# scrollable_frame.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1], expand=True, fill='both')
|
||||
treeview.bind("<<TreeviewSelect>>", element.treeview_selected)
|
||||
if element.BindReturnKey:
|
||||
|
@ -4804,6 +4949,57 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
elif element_type == ELEM_TYPE_SEPARATOR:
|
||||
separator = tkinter.ttk.Separator(tk_row_frame, orient=element.Orientation, )
|
||||
separator.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1], fill='both', expand=True)
|
||||
# ------------------------- StatusBar element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_STATUSBAR:
|
||||
# auto_size_text = element.AutoSizeText
|
||||
display_text = element.DisplayText # text to display
|
||||
if auto_size_text is False:
|
||||
width, height = element_size
|
||||
else:
|
||||
lines = display_text.split('\n')
|
||||
max_line_len = max([len(l) for l in lines])
|
||||
num_lines = len(lines)
|
||||
if max_line_len > element_size[0]: # if text exceeds element size, the will have to wrap
|
||||
width = element_size[0]
|
||||
else:
|
||||
width = max_line_len
|
||||
height = num_lines
|
||||
# ---===--- LABEL widget create and place --- #
|
||||
stringvar = tk.StringVar()
|
||||
element.TKStringVar = stringvar
|
||||
stringvar.set(display_text)
|
||||
if auto_size_text:
|
||||
width = 0
|
||||
if element.Justification is not None:
|
||||
justification = element.Justification
|
||||
elif toplevel_form.TextJustification is not None:
|
||||
justification = toplevel_form.TextJustification
|
||||
else:
|
||||
justification = DEFAULT_TEXT_JUSTIFICATION
|
||||
justify = tk.LEFT if justification == 'left' else tk.CENTER if justification == 'center' else tk.RIGHT
|
||||
anchor = tk.NW if justification == 'left' else tk.N if justification == 'center' else tk.NE
|
||||
# tktext_label = tk.Label(tk_row_frame, textvariable=stringvar, width=width, height=height,
|
||||
# justify=justify, bd=border_depth, font=font)
|
||||
tktext_label = tk.Label(tk_row_frame, textvariable=stringvar, width=width, height=height,
|
||||
justify=justify, bd=border_depth, font=font)
|
||||
# Set wrap-length for text (in PIXELS) == PAIN IN THE ASS
|
||||
wraplen = tktext_label.winfo_reqwidth() + 40 # width of widget in Pixels
|
||||
if not auto_size_text and height == 1:
|
||||
wraplen = 0
|
||||
# print("wraplen, width, height", wraplen, width, height)
|
||||
tktext_label.configure(anchor=anchor, wraplen=wraplen) # set wrap to width of widget
|
||||
if element.Relief is not None:
|
||||
tktext_label.configure(relief=element.Relief)
|
||||
if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT:
|
||||
tktext_label.configure(background=element.BackgroundColor)
|
||||
if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None:
|
||||
tktext_label.configure(fg=element.TextColor)
|
||||
tktext_label.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1],fill=tk.BOTH, expand=True)
|
||||
element.TKText = tktext_label
|
||||
if element.ClickSubmits:
|
||||
tktext_label.bind('<Button-1>', element.TextClickedHandler)
|
||||
if element.Tooltip is not None:
|
||||
element.TooltipObject = ToolTip(element.TKText, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME)
|
||||
|
||||
# ............................DONE WITH ROW pack the row of widgets ..........................#
|
||||
# done with row, pack the row of widgets
|
||||
|
@ -5382,6 +5578,8 @@ def EasyPrintClose():
|
|||
# ======================== Scrolled Text Box =====#
|
||||
# ===================================================#
|
||||
def PopupScrolled(*args, **_3to2kwargs):
|
||||
if 'location' in _3to2kwargs: location = _3to2kwargs['location']; del _3to2kwargs['location']
|
||||
else: location = (None, None)
|
||||
if 'size' in _3to2kwargs: size = _3to2kwargs['size']; del _3to2kwargs['size']
|
||||
else: size = (None, None)
|
||||
if 'auto_close_duration' in _3to2kwargs: auto_close_duration = _3to2kwargs['auto_close_duration']; del _3to2kwargs['auto_close_duration']
|
||||
|
@ -5396,7 +5594,7 @@ def PopupScrolled(*args, **_3to2kwargs):
|
|||
width, height = size
|
||||
width = width if width else MESSAGE_BOX_LINE_WIDTH
|
||||
form = Window(args[0], auto_size_text=True, button_color=button_color, auto_close=auto_close,
|
||||
auto_close_duration=auto_close_duration)
|
||||
auto_close_duration=auto_close_duration, location=location)
|
||||
max_line_total, max_line_width, total_lines, height_computed = 0, 0, 0, 0
|
||||
complete_output = ''
|
||||
for message in args:
|
||||
|
@ -6874,7 +7072,7 @@ def main():
|
|||
[Text('You should be importing it rather than running it', size=(50, 2))],
|
||||
[Text('Here is your sample input window....')],
|
||||
[Text('Source Folder', size=(15, 1), justification='right'), InputText('Source', focus=True),
|
||||
FolderBrowse()],
|
||||
FolderBrowse(tooltip='Browse for a folder')],
|
||||
[Text('Destination Folder', size=(15, 1), justification='right'), InputText('Dest'), FolderBrowse()],
|
||||
[Ok(), Cancel()]]
|
||||
|
||||
|
|
161
docs/index.md
161
docs/index.md
|
@ -26,8 +26,9 @@
|
|||
# NEW for NOV 2018 - Run Qt using PySimpleGUI!
|
||||
|
||||
## Supports both Python 2.7 & 3 when using tkinter
|
||||
## Supports both PySide2 and PyQt5
|
||||
## PySimpleGUI source code can run either on Qt or tkinter with no changes
|
||||
## Supports both PySide2 and PyQt5 (limited support)
|
||||
## PySimpleGUI source code can run either on Qt or tkinter by changing only the import
|
||||
|
||||
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.17.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
@ -280,7 +281,9 @@ Maybe there's no "there there". ***Or*** maybe a simple GUI API will enable Pyt
|
|||
|
||||
|
||||
-----
|
||||
## Getting Started with PySimpleGUI
|
||||
# Getting Started with PySimpleGUI
|
||||
|
||||
## Installing PySimpleGUI
|
||||
|
||||
### Installing Python 3
|
||||
|
||||
|
@ -380,6 +383,12 @@ PySimpleGUI Runs on all Python3 platforms that have tkinter running on them. It
|
|||
If you wish to create an EXE from your PySimpleGUI application, you will need to install `PyInstaller`. There are instructions on how to create an EXE at the bottom of this ReadMe
|
||||
|
||||
|
||||
## Qt Version
|
||||
|
||||
Please see the Qt specific documentation. The readme that contains all you need to know about Qt specific matters is here:
|
||||
https://pysimplegui.readthedocs.io/readmeqt/
|
||||
|
||||
|
||||
## Using - Python 3
|
||||
|
||||
To use in your code, simply import....
|
||||
|
@ -404,7 +413,7 @@ Those using Python 2.7 will import a different module name
|
|||
While all of the code examples you will see in this Readme and the Cookbook assume Python 3 and thus have an `import PySimpleGUI` at the top, you can run ***all*** of this code on Python 2.7 by changing the import statement to `import PySimpleGUI27`
|
||||
|
||||
---
|
||||
## APIs
|
||||
# APIs
|
||||
|
||||
PySimpleGUI can be broken down into 2 types of API's:
|
||||
* High Level single call functions (The `Popup` calls)
|
||||
|
@ -461,7 +470,7 @@ Dictionaries are used by more advanced PySimpleGUI users. You'll know that dict
|
|||
|
||||
---
|
||||
|
||||
## High Level API Calls - Popup's
|
||||
# High Level API Calls - Popup's
|
||||
|
||||
"High level calls" are those that start with "Popup". They are the most basic form of communications with the user. They are named after the type of window they create, a pop-up window. These windows are meant to be short lived while, either delivering information or collecting it, and then quickly disappearing.
|
||||
|
||||
|
@ -698,7 +707,7 @@ This is a typpical call
|
|||
|
||||
|
||||
|
||||
## Progress Meters!
|
||||
# Progress Meters!
|
||||
We all have loops in our code. 'Isn't it joyful waiting, watching a counter scrolling past in a text window? How about one line of code to get a progress meter, that contains statistics about your code?
|
||||
|
||||
|
||||
|
@ -727,7 +736,7 @@ With a little trickery you can provide a way to break out of your loop using the
|
|||
|
||||
***Be sure and add one to your loop counter*** so that your counter goes from 1 to the max value. If you do not add one, your counter will never hit the max value. Instead it will go from 0 to max-1.
|
||||
|
||||
## Debug Output
|
||||
# Debug Output
|
||||
Another call in the 'Easy' families of APIs is `EasyPrint`. It will output to a debug window. If the debug window isn't open, then the first call will open it. No need to do anything but stick a 'print' call in your code. You can even replace your 'print' calls with calls to EasyPrint by simply sticking the statement
|
||||
|
||||
print = sg.EasyPrint
|
||||
|
@ -1006,7 +1015,7 @@ You don't HAVE to write your reads in this way. You can name your variables howe
|
|||
|
||||
## Events
|
||||
|
||||
The first parameter `event` describes **why** the read completed. What was the 'event' that caused us to return from reading the window. Events are one of these:
|
||||
The first parameter `event` describes **why** the read completed. Events are one of these:
|
||||
|
||||
For all Windows:
|
||||
|
||||
|
@ -1048,15 +1057,17 @@ while True:
|
|||
|
||||
By default buttons will always return a click event, or in the case of realtime buttons, a button down event. You don't have to do anything to enable button clicks. To disable the events, disable the button using its Update method.
|
||||
|
||||
You can enable an additional "Button Modified" event by setting `enable_events=True` in the Button call. These events are triggered when something 'writes' to a button, ***usually*** it's because the button is listed as a "target" in another button.
|
||||
|
||||
The button value from a Read call will be one of 2 values:
|
||||
1. The Button's text
|
||||
2. The Button's key
|
||||
1. The Button's text - Default
|
||||
2. The Button's key - If a key is specified
|
||||
|
||||
If a button has a key set for it when it's created, then that key will be returned. If no key is set, then the button text is returned. If no button was clicked, but the window returned anyway, the button value is None.
|
||||
If a button has a key set when it was created, then that key will be returned. If no key is set, then the button text is returned. If no button was clicked, but the window returned anyway, the event value is None.
|
||||
|
||||
None is returned when the user clicks the X to close a window.
|
||||
### **None is returned when the user clicks the X to close a window.**
|
||||
|
||||
If your window has an event loop where it is read over and over, remember to give your user an "out". You should always check for a None value and it's a good practice to provide an Exit button of some kind. Thus design patterns often resemble this Event Loop:
|
||||
If your window has an event loop where it is read over and over, remember to give your user an "out". You should ***always check for a None value*** and it's a good practice to provide an Exit button of some kind. Thus design patterns often resemble this Event Loop:
|
||||
|
||||
while True:
|
||||
event, values = window.Read()
|
||||
|
@ -1097,7 +1108,7 @@ Windows are capable of returning keyboard events. These are returned as either
|
|||
|
||||
If you set a timeout parameter in your read, then the system TIMEOUT_KEY will be returned. If you specified your own timeout key in the Read call then that value will be what's returned instead.
|
||||
|
||||
### The 'values' Variable - Return values as a list
|
||||
### The `values` Variable - Return values as a list
|
||||
|
||||
The second parameter from a Read call is either a list or a dictionary of the input fields on the Window.
|
||||
|
||||
|
@ -1120,9 +1131,9 @@ However, this method isn't good when you have a lot of input fields. If you ins
|
|||
|
||||
The more common / advanced method is to request your values be returned as a dictionary.
|
||||
|
||||
### Return values as a dictionary
|
||||
### `values` Variable - Return values as a dictionary
|
||||
|
||||
For those of you that have not encountered a Python dictionary, don't freak out! Just copy and paste this code and modify it. Follow this design pattern and you'll be fine. And you might learn something along the way.
|
||||
For those of you that have not encountered a Python dictionary, don't freak out! Just copy and paste the sample code and modify it. Follow this design pattern and you'll be fine. And you might learn something along the way.
|
||||
|
||||
For windows longer than 3 or 4 fields you will want to use a dictionary to help you organize your return values. In almost all (if not all) of the demo programs you'll find the return values being passed as a dictionary. It is not a difficult concept to grasp, the syntax is easy to understand, and it makes for very readable code.
|
||||
|
||||
|
@ -1437,12 +1448,13 @@ window = sg.Window('My window title').Layout(layout)
|
|||
```
|
||||
#### Finalize()
|
||||
|
||||
Call to force a window to go through the final stages of initialization. This will cause the tkinter resources to be allocated so that they can then be modified.
|
||||
Call to force a window to go through the final stages of initialization. This will cause the tkinter resources to be allocated so that they can then be modified. This also causes your window to appear. If you do not want your window to appear when Finalize is called, then set the Alpha to 0 in your window's creation parameters.
|
||||
|
||||
#### Read(timeout=None, timeout_key='__timeout_ _ ')
|
||||
#### Read(timeout=None, timeout_key='__TIMEOUT_ _ ')
|
||||
|
||||
Read the Window's input values and button clicks in a blocking-fashion
|
||||
Returns event, values. Adding a timeout can be achieved by setting timeout=number of milliseconds before the Read times out after which a "timeout event" is returned. The value of timeout_key will be returned as the event.
|
||||
|
||||
Returns event, values. Adding a timeout can be achieved by setting timeout=number of milliseconds before the Read times out after which a "timeout event" is returned. The value of timeout_key will be returned as the event. If you do not specify a timeout key, then the value `TIMEOUT_KEY` will be returned.
|
||||
|
||||
If you set the timeout = 0, then the Read will immediately return rather than waiting for input or for a timeout. This is the same as the old ReadNonBlocking call.
|
||||
|
||||
|
@ -1450,7 +1462,7 @@ If you set the timeout = 0, then the Read will immediately return rather than wa
|
|||
|
||||
While this call will technically still work, it is being removed. If you want to get the same result, call Read with timeout = 0.
|
||||
|
||||
Read the Window's input values and button clicks but without blocking. It will immediately return. **Consider using Read with timeout instead!**
|
||||
Read the Window's input values and button clicks but without blocking. It will immediately return. **Consider using Read with non-zero timeout instead!**
|
||||
|
||||
Will consume 100% of your CPU if you do not have other blocking calls in your event loop.
|
||||
|
||||
|
@ -1484,6 +1496,9 @@ Fills in a window's fields based on previously saved file
|
|||
|
||||
Returns the size (w,h) of the screen in pixels
|
||||
|
||||
#### CurrentLocation()
|
||||
Returns current screen position (x,y)
|
||||
|
||||
#### Move(x, y)
|
||||
Move window to (x,y) position on the screen
|
||||
|
||||
|
@ -2820,26 +2835,62 @@ MoveFigure - moves an individual figure
|
|||
|
||||
## Table Element
|
||||
|
||||
Let me say up front that the Table Element has Beta status. The reason is that some of the parameters are not quite right and will change. Be warned one or two parameters may change. The `size` parameter in particular is gong to change. Currently the number of rows to allocate for the table is set by the height parameter of size. The problem is that the width is not used. The plan is to instead have a parameter named `number_of_rows` or something like it.
|
||||
Out of all of the Elements, it's the Table and the Tree that are the most "problematic" in the tkinter inter and Qt implementations. They're hard is my only defense.
|
||||
|
||||
def Table(values - Your table's array
|
||||
headings - list of strings representing your headings, if you have any
|
||||
visible_column_map - list of bools. If True, column in that position is shown. Defaults to all columns
|
||||
col_widths - list of column widths
|
||||
def_col_width - default column width. defaults to 10
|
||||
auto_size_columns - bool. If True column widths are determined by table contents
|
||||
max_col_width - maximum width of a column. defaults to 25
|
||||
select_mode - table rows can be selected, but doesn't currently do anything
|
||||
display_row_numbers - bool. If True shows numbers next to rows
|
||||
scrollable - if True table will be scrolled
|
||||
font - font for table entries
|
||||
justification - left, right, center
|
||||
text_color - color of text
|
||||
background_color - cell background color
|
||||
size - (None, number of rows).
|
||||
pad - element padding for packing
|
||||
key - key used to lookup element
|
||||
tooltip - tooltip text
|
||||
### Known visualization problem....
|
||||
|
||||
If you click on the header, it can go into spasms for some tables. I don't understand what's causing it and it's been there evidently since the first release of Tables.
|
||||
|
||||
```python
|
||||
Table( 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,
|
||||
size=(None,None),
|
||||
change_submits=False,
|
||||
enable_events=False,
|
||||
bind_return_key=False,
|
||||
pad=None,
|
||||
key=None,
|
||||
tooltip=None):
|
||||
|
||||
```
|
||||
|
||||
values - Your table's array
|
||||
headings - list of strings representing your headings, if you have any
|
||||
visible_column_map - list of bools. If True, column in that position is shown. Defaults to all columns
|
||||
col_widths - list of column widths
|
||||
def_col_width - default column width. defaults to 10
|
||||
auto_size_columns - bool. If True column widths are determined by table contents
|
||||
max_col_width - maximum width of a column. defaults to 25
|
||||
select_mode - table rows can be selected, but doesn't currently do anything
|
||||
display_row_numbers - bool. If True shows numbers next to rows
|
||||
num_rows = the number of rows to display at a time (same as size[0])
|
||||
row_height = number of pixels high a row should be. Normally left as default value
|
||||
font - font for table entries
|
||||
justification - left, right, center
|
||||
text_color - color of text
|
||||
alternating row color - if set will change background color for alternating rows
|
||||
background_color - cell background color
|
||||
size - (None, number of rows) - don't use, use num_rows instead
|
||||
enable_events - will return a 'row selected' event when row is selected
|
||||
change_submits - the old way of indicating enable_events
|
||||
bind_return_key - returns event if a double click or a return key is pressed while row is highlighted
|
||||
pad - element padding for packing
|
||||
key - key used to lookup element
|
||||
tooltip - tooltip text
|
||||
|
||||
### Read return values from Table Element
|
||||
|
||||
|
@ -3428,7 +3479,8 @@ Use realtime keyboard capture by calling
|
|||
|
||||
# Menus
|
||||
|
||||
Beginning in version 3.01 you can add a menubar to your window. You specify the menus in much the same way as you do window layouts, with lists. Menu selections are returned as button clicks, so be aware of your overall naming conventions. If you have an Exit button and also an Exit menu option, then you won't be able to tell the difference when your window.Read returns. Hopefully will not be a problem.
|
||||
Beginning in version 3.01 you can add a menubar to your window. You specify the menus in much the same way as you do window layouts, with lists. Menu selections are returned as events and as of 3.17, also as values. The value returned will be the entire menu entry, including the key if you specified one.
|
||||
|
||||
|
||||
This definition:
|
||||
|
||||
|
@ -3443,6 +3495,7 @@ They menu_def layout produced this window:
|
|||
![menu](https://user-images.githubusercontent.com/13696193/45306723-56b7cb00-b4eb-11e8-8cbd-faef0c90f8b4.jpg)
|
||||
|
||||
|
||||
## Menu Shortcut keys
|
||||
You have used ALT-key in other Windows programs to navigate menus. For example Alt-F+X exits the program. The Alt-F pulls down the File menu. The X selects the entry marked Exit.
|
||||
|
||||
The good news is that PySimpleGUI allows you to create the same kind of menus! Your program can play with the big-boys. And, it's trivial to do.
|
||||
|
@ -3463,10 +3516,30 @@ menu_def = [['&File', ['&Open', '&Save', '---', 'Properties', 'E&xit' ]],
|
|||
![menus with shortcuts](https://user-images.githubusercontent.com/13696193/46251674-f5b74f00-c427-11e8-95c6-547adc59041b.jpg)
|
||||
|
||||
|
||||
## Disabled Menu Entries
|
||||
|
||||
If you want one of your menu items to be disabled, then place a '!' in front of the menu entry. To disable the Paste menu entry in the previous examples, the entry would be:
|
||||
`['!&Edit', ['Paste', ['Special', 'Normal',], 'Undo'],]`
|
||||
|
||||
If your want to change the disabled menu item flag / character from '!' to something else, change the variable `MENU_DISABLED_CHARACTER`
|
||||
|
||||
## Keys for Menus
|
||||
|
||||
Beginning in version 3.17 you can add a `key` to your menu entries. The `key` value will be removed prior to be inserted into the menu. When you receive Menu events, the entire menu entry, including the `key` is returned. A key is indicated by adding `::` after a menu entry, followed by the key.
|
||||
|
||||
To add the `key` `_MY_KEY_` to the Special menu entry, the code would be:
|
||||
|
||||
`['&Edit', ['Paste', ['Special::_MY_KEY_', 'Normal',], 'Undo'],]`
|
||||
|
||||
If you want to change the characters that indicate a key follows from '::' to something else, change the variable `MENU_KEY_SEPARATOR`
|
||||
|
||||
|
||||
# Sample Applications
|
||||
|
||||
There are too many to list!!
|
||||
|
||||
There are over 130 sample programs to give you a jump start.
|
||||
|
||||
Use the example programs as a starting basis for your GUI. Copy, paste, modify and run! The demo files are:
|
||||
|
||||
| Source File| Description |
|
||||
|
@ -3986,12 +4059,11 @@ New `Element` shortcut function for `FindElement`
|
|||
Dummy Stretch Element made for backwards compatibility with Qt
|
||||
Timer function prints in milliseconds now, was seconds
|
||||
|
||||
### 3.17.0 &1.17.0 1-Dec-2018
|
||||
### 3.17.0 &1.17.0 2-Dec-2018
|
||||
Tooltip offset now programmable. Set variable DEFAULT_TOOLTIP_OFFSET. Defaults to (20,-20)
|
||||
Tooltips are always on top now
|
||||
Disable menu items
|
||||
Menu items can have keys
|
||||
StatusBar Element (preparing for a real status bar in Qt)
|
||||
enable_events parameter added to ALL Elements capable of generating events
|
||||
select parameter to InputText.Update will select the input text
|
||||
Listbox.Update - set_to_index parameter will select a single items
|
||||
|
@ -4000,7 +4072,10 @@ Menus have an entry in the return values
|
|||
LayoutAndRead depricated
|
||||
Multi-window support continues (X detection)
|
||||
PopupScrolled now has a location parameter
|
||||
|
||||
row_height parameter to Table Element
|
||||
Stretch Element (DUMMY) so that can be source code compatible with Qt
|
||||
ButtonMenu Element (DUMMY) so can be source code compatible with Qt. Will implement eventually
|
||||
StatusBar Element (preparing for a real status bar in Qt) based on Text Element
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
|
161
readme.md
161
readme.md
|
@ -26,8 +26,9 @@
|
|||
# NEW for NOV 2018 - Run Qt using PySimpleGUI!
|
||||
|
||||
## Supports both Python 2.7 & 3 when using tkinter
|
||||
## Supports both PySide2 and PyQt5
|
||||
## PySimpleGUI source code can run either on Qt or tkinter with no changes
|
||||
## Supports both PySide2 and PyQt5 (limited support)
|
||||
## PySimpleGUI source code can run either on Qt or tkinter by changing only the import
|
||||
|
||||
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.17.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
@ -280,7 +281,9 @@ Maybe there's no "there there". ***Or*** maybe a simple GUI API will enable Pyt
|
|||
|
||||
|
||||
-----
|
||||
## Getting Started with PySimpleGUI
|
||||
# Getting Started with PySimpleGUI
|
||||
|
||||
## Installing PySimpleGUI
|
||||
|
||||
### Installing Python 3
|
||||
|
||||
|
@ -380,6 +383,12 @@ PySimpleGUI Runs on all Python3 platforms that have tkinter running on them. It
|
|||
If you wish to create an EXE from your PySimpleGUI application, you will need to install `PyInstaller`. There are instructions on how to create an EXE at the bottom of this ReadMe
|
||||
|
||||
|
||||
## Qt Version
|
||||
|
||||
Please see the Qt specific documentation. The readme that contains all you need to know about Qt specific matters is here:
|
||||
https://pysimplegui.readthedocs.io/readmeqt/
|
||||
|
||||
|
||||
## Using - Python 3
|
||||
|
||||
To use in your code, simply import....
|
||||
|
@ -404,7 +413,7 @@ Those using Python 2.7 will import a different module name
|
|||
While all of the code examples you will see in this Readme and the Cookbook assume Python 3 and thus have an `import PySimpleGUI` at the top, you can run ***all*** of this code on Python 2.7 by changing the import statement to `import PySimpleGUI27`
|
||||
|
||||
---
|
||||
## APIs
|
||||
# APIs
|
||||
|
||||
PySimpleGUI can be broken down into 2 types of API's:
|
||||
* High Level single call functions (The `Popup` calls)
|
||||
|
@ -461,7 +470,7 @@ Dictionaries are used by more advanced PySimpleGUI users. You'll know that dict
|
|||
|
||||
---
|
||||
|
||||
## High Level API Calls - Popup's
|
||||
# High Level API Calls - Popup's
|
||||
|
||||
"High level calls" are those that start with "Popup". They are the most basic form of communications with the user. They are named after the type of window they create, a pop-up window. These windows are meant to be short lived while, either delivering information or collecting it, and then quickly disappearing.
|
||||
|
||||
|
@ -698,7 +707,7 @@ This is a typpical call
|
|||
|
||||
|
||||
|
||||
## Progress Meters!
|
||||
# Progress Meters!
|
||||
We all have loops in our code. 'Isn't it joyful waiting, watching a counter scrolling past in a text window? How about one line of code to get a progress meter, that contains statistics about your code?
|
||||
|
||||
|
||||
|
@ -727,7 +736,7 @@ With a little trickery you can provide a way to break out of your loop using the
|
|||
|
||||
***Be sure and add one to your loop counter*** so that your counter goes from 1 to the max value. If you do not add one, your counter will never hit the max value. Instead it will go from 0 to max-1.
|
||||
|
||||
## Debug Output
|
||||
# Debug Output
|
||||
Another call in the 'Easy' families of APIs is `EasyPrint`. It will output to a debug window. If the debug window isn't open, then the first call will open it. No need to do anything but stick a 'print' call in your code. You can even replace your 'print' calls with calls to EasyPrint by simply sticking the statement
|
||||
|
||||
print = sg.EasyPrint
|
||||
|
@ -1006,7 +1015,7 @@ You don't HAVE to write your reads in this way. You can name your variables howe
|
|||
|
||||
## Events
|
||||
|
||||
The first parameter `event` describes **why** the read completed. What was the 'event' that caused us to return from reading the window. Events are one of these:
|
||||
The first parameter `event` describes **why** the read completed. Events are one of these:
|
||||
|
||||
For all Windows:
|
||||
|
||||
|
@ -1048,15 +1057,17 @@ while True:
|
|||
|
||||
By default buttons will always return a click event, or in the case of realtime buttons, a button down event. You don't have to do anything to enable button clicks. To disable the events, disable the button using its Update method.
|
||||
|
||||
You can enable an additional "Button Modified" event by setting `enable_events=True` in the Button call. These events are triggered when something 'writes' to a button, ***usually*** it's because the button is listed as a "target" in another button.
|
||||
|
||||
The button value from a Read call will be one of 2 values:
|
||||
1. The Button's text
|
||||
2. The Button's key
|
||||
1. The Button's text - Default
|
||||
2. The Button's key - If a key is specified
|
||||
|
||||
If a button has a key set for it when it's created, then that key will be returned. If no key is set, then the button text is returned. If no button was clicked, but the window returned anyway, the button value is None.
|
||||
If a button has a key set when it was created, then that key will be returned. If no key is set, then the button text is returned. If no button was clicked, but the window returned anyway, the event value is None.
|
||||
|
||||
None is returned when the user clicks the X to close a window.
|
||||
### **None is returned when the user clicks the X to close a window.**
|
||||
|
||||
If your window has an event loop where it is read over and over, remember to give your user an "out". You should always check for a None value and it's a good practice to provide an Exit button of some kind. Thus design patterns often resemble this Event Loop:
|
||||
If your window has an event loop where it is read over and over, remember to give your user an "out". You should ***always check for a None value*** and it's a good practice to provide an Exit button of some kind. Thus design patterns often resemble this Event Loop:
|
||||
|
||||
while True:
|
||||
event, values = window.Read()
|
||||
|
@ -1097,7 +1108,7 @@ Windows are capable of returning keyboard events. These are returned as either
|
|||
|
||||
If you set a timeout parameter in your read, then the system TIMEOUT_KEY will be returned. If you specified your own timeout key in the Read call then that value will be what's returned instead.
|
||||
|
||||
### The 'values' Variable - Return values as a list
|
||||
### The `values` Variable - Return values as a list
|
||||
|
||||
The second parameter from a Read call is either a list or a dictionary of the input fields on the Window.
|
||||
|
||||
|
@ -1120,9 +1131,9 @@ However, this method isn't good when you have a lot of input fields. If you ins
|
|||
|
||||
The more common / advanced method is to request your values be returned as a dictionary.
|
||||
|
||||
### Return values as a dictionary
|
||||
### `values` Variable - Return values as a dictionary
|
||||
|
||||
For those of you that have not encountered a Python dictionary, don't freak out! Just copy and paste this code and modify it. Follow this design pattern and you'll be fine. And you might learn something along the way.
|
||||
For those of you that have not encountered a Python dictionary, don't freak out! Just copy and paste the sample code and modify it. Follow this design pattern and you'll be fine. And you might learn something along the way.
|
||||
|
||||
For windows longer than 3 or 4 fields you will want to use a dictionary to help you organize your return values. In almost all (if not all) of the demo programs you'll find the return values being passed as a dictionary. It is not a difficult concept to grasp, the syntax is easy to understand, and it makes for very readable code.
|
||||
|
||||
|
@ -1437,12 +1448,13 @@ window = sg.Window('My window title').Layout(layout)
|
|||
```
|
||||
#### Finalize()
|
||||
|
||||
Call to force a window to go through the final stages of initialization. This will cause the tkinter resources to be allocated so that they can then be modified.
|
||||
Call to force a window to go through the final stages of initialization. This will cause the tkinter resources to be allocated so that they can then be modified. This also causes your window to appear. If you do not want your window to appear when Finalize is called, then set the Alpha to 0 in your window's creation parameters.
|
||||
|
||||
#### Read(timeout=None, timeout_key='__timeout_ _ ')
|
||||
#### Read(timeout=None, timeout_key='__TIMEOUT_ _ ')
|
||||
|
||||
Read the Window's input values and button clicks in a blocking-fashion
|
||||
Returns event, values. Adding a timeout can be achieved by setting timeout=number of milliseconds before the Read times out after which a "timeout event" is returned. The value of timeout_key will be returned as the event.
|
||||
|
||||
Returns event, values. Adding a timeout can be achieved by setting timeout=number of milliseconds before the Read times out after which a "timeout event" is returned. The value of timeout_key will be returned as the event. If you do not specify a timeout key, then the value `TIMEOUT_KEY` will be returned.
|
||||
|
||||
If you set the timeout = 0, then the Read will immediately return rather than waiting for input or for a timeout. This is the same as the old ReadNonBlocking call.
|
||||
|
||||
|
@ -1450,7 +1462,7 @@ If you set the timeout = 0, then the Read will immediately return rather than wa
|
|||
|
||||
While this call will technically still work, it is being removed. If you want to get the same result, call Read with timeout = 0.
|
||||
|
||||
Read the Window's input values and button clicks but without blocking. It will immediately return. **Consider using Read with timeout instead!**
|
||||
Read the Window's input values and button clicks but without blocking. It will immediately return. **Consider using Read with non-zero timeout instead!**
|
||||
|
||||
Will consume 100% of your CPU if you do not have other blocking calls in your event loop.
|
||||
|
||||
|
@ -1484,6 +1496,9 @@ Fills in a window's fields based on previously saved file
|
|||
|
||||
Returns the size (w,h) of the screen in pixels
|
||||
|
||||
#### CurrentLocation()
|
||||
Returns current screen position (x,y)
|
||||
|
||||
#### Move(x, y)
|
||||
Move window to (x,y) position on the screen
|
||||
|
||||
|
@ -2820,26 +2835,62 @@ MoveFigure - moves an individual figure
|
|||
|
||||
## Table Element
|
||||
|
||||
Let me say up front that the Table Element has Beta status. The reason is that some of the parameters are not quite right and will change. Be warned one or two parameters may change. The `size` parameter in particular is gong to change. Currently the number of rows to allocate for the table is set by the height parameter of size. The problem is that the width is not used. The plan is to instead have a parameter named `number_of_rows` or something like it.
|
||||
Out of all of the Elements, it's the Table and the Tree that are the most "problematic" in the tkinter inter and Qt implementations. They're hard is my only defense.
|
||||
|
||||
def Table(values - Your table's array
|
||||
headings - list of strings representing your headings, if you have any
|
||||
visible_column_map - list of bools. If True, column in that position is shown. Defaults to all columns
|
||||
col_widths - list of column widths
|
||||
def_col_width - default column width. defaults to 10
|
||||
auto_size_columns - bool. If True column widths are determined by table contents
|
||||
max_col_width - maximum width of a column. defaults to 25
|
||||
select_mode - table rows can be selected, but doesn't currently do anything
|
||||
display_row_numbers - bool. If True shows numbers next to rows
|
||||
scrollable - if True table will be scrolled
|
||||
font - font for table entries
|
||||
justification - left, right, center
|
||||
text_color - color of text
|
||||
background_color - cell background color
|
||||
size - (None, number of rows).
|
||||
pad - element padding for packing
|
||||
key - key used to lookup element
|
||||
tooltip - tooltip text
|
||||
### Known visualization problem....
|
||||
|
||||
If you click on the header, it can go into spasms for some tables. I don't understand what's causing it and it's been there evidently since the first release of Tables.
|
||||
|
||||
```python
|
||||
Table( 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,
|
||||
size=(None,None),
|
||||
change_submits=False,
|
||||
enable_events=False,
|
||||
bind_return_key=False,
|
||||
pad=None,
|
||||
key=None,
|
||||
tooltip=None):
|
||||
|
||||
```
|
||||
|
||||
values - Your table's array
|
||||
headings - list of strings representing your headings, if you have any
|
||||
visible_column_map - list of bools. If True, column in that position is shown. Defaults to all columns
|
||||
col_widths - list of column widths
|
||||
def_col_width - default column width. defaults to 10
|
||||
auto_size_columns - bool. If True column widths are determined by table contents
|
||||
max_col_width - maximum width of a column. defaults to 25
|
||||
select_mode - table rows can be selected, but doesn't currently do anything
|
||||
display_row_numbers - bool. If True shows numbers next to rows
|
||||
num_rows = the number of rows to display at a time (same as size[0])
|
||||
row_height = number of pixels high a row should be. Normally left as default value
|
||||
font - font for table entries
|
||||
justification - left, right, center
|
||||
text_color - color of text
|
||||
alternating row color - if set will change background color for alternating rows
|
||||
background_color - cell background color
|
||||
size - (None, number of rows) - don't use, use num_rows instead
|
||||
enable_events - will return a 'row selected' event when row is selected
|
||||
change_submits - the old way of indicating enable_events
|
||||
bind_return_key - returns event if a double click or a return key is pressed while row is highlighted
|
||||
pad - element padding for packing
|
||||
key - key used to lookup element
|
||||
tooltip - tooltip text
|
||||
|
||||
### Read return values from Table Element
|
||||
|
||||
|
@ -3428,7 +3479,8 @@ Use realtime keyboard capture by calling
|
|||
|
||||
# Menus
|
||||
|
||||
Beginning in version 3.01 you can add a menubar to your window. You specify the menus in much the same way as you do window layouts, with lists. Menu selections are returned as button clicks, so be aware of your overall naming conventions. If you have an Exit button and also an Exit menu option, then you won't be able to tell the difference when your window.Read returns. Hopefully will not be a problem.
|
||||
Beginning in version 3.01 you can add a menubar to your window. You specify the menus in much the same way as you do window layouts, with lists. Menu selections are returned as events and as of 3.17, also as values. The value returned will be the entire menu entry, including the key if you specified one.
|
||||
|
||||
|
||||
This definition:
|
||||
|
||||
|
@ -3443,6 +3495,7 @@ They menu_def layout produced this window:
|
|||
![menu](https://user-images.githubusercontent.com/13696193/45306723-56b7cb00-b4eb-11e8-8cbd-faef0c90f8b4.jpg)
|
||||
|
||||
|
||||
## Menu Shortcut keys
|
||||
You have used ALT-key in other Windows programs to navigate menus. For example Alt-F+X exits the program. The Alt-F pulls down the File menu. The X selects the entry marked Exit.
|
||||
|
||||
The good news is that PySimpleGUI allows you to create the same kind of menus! Your program can play with the big-boys. And, it's trivial to do.
|
||||
|
@ -3463,10 +3516,30 @@ menu_def = [['&File', ['&Open', '&Save', '---', 'Properties', 'E&xit' ]],
|
|||
![menus with shortcuts](https://user-images.githubusercontent.com/13696193/46251674-f5b74f00-c427-11e8-95c6-547adc59041b.jpg)
|
||||
|
||||
|
||||
## Disabled Menu Entries
|
||||
|
||||
If you want one of your menu items to be disabled, then place a '!' in front of the menu entry. To disable the Paste menu entry in the previous examples, the entry would be:
|
||||
`['!&Edit', ['Paste', ['Special', 'Normal',], 'Undo'],]`
|
||||
|
||||
If your want to change the disabled menu item flag / character from '!' to something else, change the variable `MENU_DISABLED_CHARACTER`
|
||||
|
||||
## Keys for Menus
|
||||
|
||||
Beginning in version 3.17 you can add a `key` to your menu entries. The `key` value will be removed prior to be inserted into the menu. When you receive Menu events, the entire menu entry, including the `key` is returned. A key is indicated by adding `::` after a menu entry, followed by the key.
|
||||
|
||||
To add the `key` `_MY_KEY_` to the Special menu entry, the code would be:
|
||||
|
||||
`['&Edit', ['Paste', ['Special::_MY_KEY_', 'Normal',], 'Undo'],]`
|
||||
|
||||
If you want to change the characters that indicate a key follows from '::' to something else, change the variable `MENU_KEY_SEPARATOR`
|
||||
|
||||
|
||||
# Sample Applications
|
||||
|
||||
There are too many to list!!
|
||||
|
||||
There are over 130 sample programs to give you a jump start.
|
||||
|
||||
Use the example programs as a starting basis for your GUI. Copy, paste, modify and run! The demo files are:
|
||||
|
||||
| Source File| Description |
|
||||
|
@ -3986,12 +4059,11 @@ New `Element` shortcut function for `FindElement`
|
|||
Dummy Stretch Element made for backwards compatibility with Qt
|
||||
Timer function prints in milliseconds now, was seconds
|
||||
|
||||
### 3.17.0 &1.17.0 1-Dec-2018
|
||||
### 3.17.0 &1.17.0 2-Dec-2018
|
||||
Tooltip offset now programmable. Set variable DEFAULT_TOOLTIP_OFFSET. Defaults to (20,-20)
|
||||
Tooltips are always on top now
|
||||
Disable menu items
|
||||
Menu items can have keys
|
||||
StatusBar Element (preparing for a real status bar in Qt)
|
||||
enable_events parameter added to ALL Elements capable of generating events
|
||||
select parameter to InputText.Update will select the input text
|
||||
Listbox.Update - set_to_index parameter will select a single items
|
||||
|
@ -4000,7 +4072,10 @@ Menus have an entry in the return values
|
|||
LayoutAndRead depricated
|
||||
Multi-window support continues (X detection)
|
||||
PopupScrolled now has a location parameter
|
||||
|
||||
row_height parameter to Table Element
|
||||
Stretch Element (DUMMY) so that can be source code compatible with Qt
|
||||
ButtonMenu Element (DUMMY) so can be source code compatible with Qt. Will implement eventually
|
||||
StatusBar Element (preparing for a real status bar in Qt) based on Text Element
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
|
Loading…
Reference in New Issue