Autosize text now TRUE by default, Remove progress bar target, cleanup how return values made, ChangeLookAndFeel func

This commit is contained in:
MikeTheWatchGuy 2018-08-12 17:45:12 -04:00
parent 148a1049ba
commit d0ab0c42c5
1 changed files with 132 additions and 179 deletions

View File

@ -14,7 +14,7 @@ DEFAULT_WINDOW_ICON = ''
DEFAULT_ELEMENT_SIZE = (45,1) # In CHARACTERS
DEFAULT_MARGINS = (10,5) # Margins for each LEFT/RIGHT margin is first term
DEFAULT_ELEMENT_PADDING = (5,3) # Padding between elements (row, col) in pixels
DEFAULT_AUTOSIZE_TEXT = False
DEFAULT_AUTOSIZE_TEXT = True
DEFAULT_AUTOSIZE_BUTTONS = True
DEFAULT_FONT = ("Helvetica", 10)
DEFAULT_TEXT_JUSTIFICATION = 'left'
@ -603,11 +603,11 @@ class Button(Element):
def ButtonReleaseCallBack(self, parm):
r, c = self.Position
self.ParentForm.Results[r][c] = False # mark this button's location in results
self.ParentForm.LastButtonClicked = None
def ButtonPressCallBack(self, parm):
r, c = self.Position
self.ParentForm.Results[r][c] = True # mark this button's location in results
self.ParentForm.LastButtonClicked = self.ButtonText
# ------- Button Callback ------- #
def ButtonCallBack(self):
@ -642,7 +642,7 @@ class Button(Element):
# first, get the results table built
# modify the Results table in the parent FlexForm object
r,c = self.Position
self.ParentForm.Results[r][c] = True # mark this button's location in results
self.ParentForm.LastButtonClicked = self.ButtonText
# if the form is tabbed, must collect all form's results and destroy all forms
if self.ParentForm.IsTabbedForm:
self.ParentForm.UberParent._Close()
@ -656,7 +656,7 @@ class Button(Element):
# first, get the results table built
# modify the Results table in the parent FlexForm object
r,c = self.Position
self.ParentForm.Results[r][c] = True # mark this button's location in results
self.ParentForm.LastButtonClicked = self.ButtonText
self.ParentForm.TKroot.quit() # kick the users out of the mainloop
return
@ -671,12 +671,11 @@ class Button(Element):
# ProgreessBar #
# ---------------------------------------------------------------------- #
class ProgressBar(Element):
def __init__(self, max_value, orientation=None, target=(None, None), scale=(None, None), size=(None, None), auto_size_text=None, bar_color=(None, None), style=None, border_width=None, relief=None):
def __init__(self, max_value, orientation=None, scale=(None, None), size=(None, None), auto_size_text=None, bar_color=(None, None), style=None, border_width=None, relief=None):
'''
Progress Bar Element
:param max_value:
:param orientation:
:param target:
:param scale: Adds multiplier to size (w,h)
:param size: Size of field in characters
:param auto_size_text: True if should shrink field to fit the default text
@ -692,7 +691,6 @@ class ProgressBar(Element):
self.Orientation = orientation if orientation else DEFAULT_METER_ORIENTATION
self.BarColor = bar_color
self.BarStyle = style if style else DEFAULT_PROGRESS_BAR_STYLE
self.Target = target
self.BorderWidth = border_width if border_width else DEFAULT_PROGRESS_BAR_BORDER_WIDTH
self.Relief = relief if relief else DEFAULT_PROGRESS_BAR_RELIEF
self.BarExpired = False
@ -702,12 +700,6 @@ class ProgressBar(Element):
def UpdateBar(self, current_count):
if self.ParentForm.TKrootDestroyed:
return False
target = self.Target
if target[0] != None: # if there's a target, get it and update the strvar
target_element = self.ParentForm.GetElementAtLocation(target)
strvar = target_element.TKStringVar
rc = strvar.set(self.TextToDisplay)
self.TKProgressBar.Update(current_count)
try:
self.ParentForm.TKroot.update()
@ -806,8 +798,10 @@ class FlexForm:
self.RootNeedsDestroying = False
self.Shown = False
self.ReturnValues = None
self.ReturnValuesDictionary = None
self.ResultsBuilt = False
self.ReturnValuesList = []
self.ReturnValuesDictionary = {}
self.DictionaryKeyCounter = 0
self.LastButtonClicked = None
self.UseDictionary = False
self.UseDefaultFocus = False
@ -911,7 +905,7 @@ class FlexForm:
if self.RootNeedsDestroying:
self.TKroot.destroy()
_my_windows.NumOpenWindows -= 1 * (_my_windows.NumOpenWindows != 0) # decrement if not 0
return BuildResults(self)
return BuildResults(self, False)
def ReadNonBlocking(self, Message=''):
if self.TKrootDestroyed:
@ -925,7 +919,7 @@ class FlexForm:
except:
self.TKrootDestroyed = True
_my_windows.NumOpenWindows -= 1 * (_my_windows.NumOpenWindows != 0) # decrement if not 0
return BuildResults(self)
return BuildResults(self, False)
# LEGACY version of ReadNonBlocking
def Refresh(self, Message=''):
@ -938,14 +932,14 @@ class FlexForm:
except:
self.TKrootDestroyed = True
_my_windows.NumOpenWindows -= 1 * (_my_windows.NumOpenWindows != 0) # decrement if not 0
return BuildResults(self)
return BuildResults(self, False)
def _Close(self):
try:
self.TKroot.update()
except: pass
if not self.NonBlocking:
results = BuildResults(self)
results = BuildResults(self, False)
if self.TKrootDestroyed:
return None
self.TKrootDestroyed = True
@ -1083,53 +1077,23 @@ def ReadFormButton(button_text, image_filename=None, image_size=(None, None),ima
def RealtimeButton(button_text, image_filename=None, image_size=(None, None),image_subsample=None,border_width=None,scale=(None, None), size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, focus=False):
return Button(BUTTON_TYPE_REALTIME, image_filename=image_filename, image_size=image_size, image_subsample=image_subsample, border_width=border_width, button_text=button_text, scale=scale, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus)
#------------------------------------------------------------------------------------------------------#
# ------- FUNCTION InitializeResults. Sets up form results matrix ------- #
##################################### ----- RESULTS ------ ##################################################
def AddToReturnDictionary(form, element, value):
if element.Key is None:
form.ReturnValuesDictionary[form.DictionaryKeyCounter] = value
form.DictionaryKeyCounter += 1
else:
form.ReturnValuesDictionary[element.Key] = value
def AddToReturnList(form, value):
form.ReturnValuesList.append(value)
#----------------------------------------------------------------------------#
# ------- FUNCTION InitializeResults. Sets up form results matrix --------#
def InitializeResults(form):
# initial results for elements are:
# TEXT - None
# INPUT - Initial value
# Button - False
results = []
return_vals = []
for row_num,row in enumerate(form.Rows):
r = []
for element in row:
if element.Type == ELEM_TYPE_TEXT:
r.append(None)
if element.Type == ELEM_TYPE_IMAGE:
r.append(None)
elif element.Type == ELEM_TYPE_INPUT_TEXT:
r.append(element.TextInputDefault)
return_vals.append(None)
elif element.Type == ELEM_TYPE_INPUT_MULTILINE:
r.append(element.TextInputDefault)
return_vals.append(None)
elif element.Type == ELEM_TYPE_BUTTON:
r.append(False)
elif element.Type == ELEM_TYPE_PROGRESS_BAR:
r.append(None)
elif element.Type == ELEM_TYPE_INPUT_CHECKBOX:
r.append(element.InitialState)
return_vals.append(element.InitialState)
elif element.Type == ELEM_TYPE_INPUT_RADIO:
r.append(element.InitialState)
return_vals.append(element.InitialState)
elif element.Type == ELEM_TYPE_INPUT_COMBO:
r.append(element.TextInputDefault)
return_vals.append(None)
elif element.Type == ELEM_TYPE_INPUT_LISTBOX:
r.append(None)
return_vals.append(None)
elif element.Type == ELEM_TYPE_INPUT_SPIN:
r.append(element.DefaultValue)
return_vals.append(None)
elif element.Type == ELEM_TYPE_INPUT_SLIDER:
r.append(element.DefaultValue)
return_vals.append(None)
results.append(r)
form.Results=results
form.ReturnValues = (None, return_vals)
BuildResults(form, True)
return
#===== Radio Button RadVar encoding and decoding =====#
@ -1146,99 +1110,52 @@ def EncodeRadioRowCol(row, col):
# ------- FUNCTION BuildResults. Form exiting so build the results to pass back ------- #
# format of return values is
# (Button Pressed, input_values)
def BuildResults(form):
def BuildResults(form, initialize_only):
# Results for elements are:
# TEXT - Nothing
# INPUT - Read value from TK
# Button - Button Text and position as a Tuple
# Get the initialized results so we don't have to rebuild
results=form.Results
button_pressed_text = None
input_values = []
input_values_dictionary = {}
form.DictionaryKeyCounter = 0
form.ReturnValuesDictionary = {}
form.ReturnValuesList = []
key_counter = 0
for row_num,row in enumerate(form.Rows):
for col_num, element in enumerate(row):
if not initialize_only:
if element.Type == ELEM_TYPE_INPUT_TEXT:
value=element.TKStringVar.get()
results[row_num][col_num] = value
input_values.append(value)
if not form.NonBlocking and not element.do_not_clear:
element.TKStringVar.set('')
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_INPUT_CHECKBOX:
value=element.TKIntVar.get()
results[row_num][col_num] = value
input_values.append(value != 0)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_INPUT_RADIO:
RadVar=element.TKIntVar.get()
this_rowcol = EncodeRadioRowCol(row_num,col_num)
value = RadVar == this_rowcol
results[row_num][col_num] = value
input_values.append(value)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_BUTTON:
if results[row_num][col_num] is True:
button_pressed_text = element.ButtonText
if form.LastButtonClicked == element.ButtonText:
button_pressed_text = form.LastButtonClicked
if element.BType != BUTTON_TYPE_REALTIME: # Do not clear realtime buttons
results[row_num][col_num] = False
form.LastButtonClicked = None
elif element.Type == ELEM_TYPE_INPUT_COMBO:
value=element.TKStringVar.get()
results[row_num][col_num] = value
input_values.append(value)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_INPUT_LISTBOX:
items=element.TKListbox.curselection()
value = [element.Values[int(item)] for item in items]
results[row_num][col_num] = value
input_values.append(value)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_INPUT_SPIN:
try:
value=element.TKStringVar.get()
except:
value = 0
results[row_num][col_num] = value
input_values.append(value)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_INPUT_SLIDER:
try:
value=element.TKIntVar.get()
except:
value = 0
results[row_num][col_num] = value
input_values.append(value)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
elif element.Type == ELEM_TYPE_INPUT_MULTILINE:
try:
value=element.TKText.get(1.0, tk.END)
@ -1246,24 +1163,23 @@ def BuildResults(form):
element.TKText.delete('1.0', tk.END)
except:
value = None
results[row_num][col_num] = value
input_values.append(value)
if element.Key is None:
input_values_dictionary[key_counter] = value
key_counter +=1
else:
input_values_dictionary[element.Key] = value
value = None
# if an input type element, update the results
if element.Type != ELEM_TYPE_BUTTON and element.Type != ELEM_TYPE_TEXT and element.Type != ELEM_TYPE_IMAGE and\
element.Type != ELEM_TYPE_OUTPUT and element.Type != ELEM_TYPE_PROGRESS_BAR:
AddToReturnList(form, value)
AddToReturnDictionary(form, element, value)
try:
input_values_dictionary.pop(None, None) # clean up dictionary include None was included
form.ReturnValuesDictionary.pop(None, None) # clean up dictionary include None was included
except: pass
if not form.UseDictionary:
form.ReturnValues = button_pressed_text, input_values
form.ReturnValues = button_pressed_text, form.ReturnValuesList
else:
form.ReturnValues = button_pressed_text, input_values_dictionary
form.ReturnValuesDictionary = button_pressed_text, input_values_dictionary
form.ResultsBuilt = True
form.ReturnValues = button_pressed_text, form.ReturnValuesDictionary
return form.ReturnValues
@ -1916,7 +1832,7 @@ def ConvertArgsToSingleString(*args):
# ============================== ProgressMeter =====#
# ===================================================#
def ProgressMeter(title, max_value, *args, orientation=None, bar_color=(None,None), button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, scale=(None, None), border_width=None):
def _ProgressMeter(title, max_value, *args, orientation=None, bar_color=(None,None), button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, scale=(None, None), border_width=None):
'''
Create and show a form on tbe caller's behalf.
:param title:
@ -1932,8 +1848,7 @@ def ProgressMeter(title, max_value, *args, orientation=None, bar_color=(None,Non
'''
local_orientation = DEFAULT_METER_ORIENTATION if orientation is None else orientation
local_border_width = DEFAULT_PROGRESS_BAR_BORDER_WIDTH if border_width is None else border_width
target = (0,0) if local_orientation[0].lower() == 'h' else (0,1)
bar2 = ProgressBar(max_value, orientation=local_orientation, size=size, bar_color=bar_color, scale=scale, target=target, border_width=local_border_width, relief=DEFAULT_PROGRESS_BAR_RELIEF)
bar2 = ProgressBar(max_value, orientation=local_orientation, size=size, bar_color=bar_color, scale=scale, border_width=local_border_width, relief=DEFAULT_PROGRESS_BAR_RELIEF)
form = FlexForm(title, auto_size_text=True)
# Form using a horizontal bar
@ -1942,7 +1857,8 @@ def ProgressMeter(title, max_value, *args, orientation=None, bar_color=(None,Non
bar2.TextToDisplay = single_line_message
bar2.MaxValue = max_value
bar2.CurrentValue = 0
form.AddRow(Text(single_line_message, size=(width, height + 3), auto_size_text=True))
bar_text = Text(single_line_message, size=(width, height + 3), auto_size_text=True)
form.AddRow(bar_text)
form.AddRow((bar2))
form.AddRow((Cancel(button_color=button_color)))
else:
@ -1950,15 +1866,16 @@ def ProgressMeter(title, max_value, *args, orientation=None, bar_color=(None,Non
bar2.TextToDisplay = single_line_message
bar2.MaxValue = max_value
bar2.CurrentValue = 0
form.AddRow(bar2, Text(single_line_message, size=(width, height + 3), auto_size_text=True))
bar_text = Text(single_line_message, size=(width, height + 3), auto_size_text=True)
form.AddRow(bar2, bar_text)
form.AddRow((Cancel(button_color=button_color)))
form.NonBlocking = True
form.Show(non_blocking= True)
return bar2
return bar2, bar_text
# ============================== ProgressMeterUpdate =====#
def ProgressMeterUpdate(bar, value, *args):
def _ProgressMeterUpdate(bar, value, text_elem, *args):
'''
Update the progress meter for a form
:param form: class ProgressBar
@ -1969,8 +1886,8 @@ def ProgressMeterUpdate(bar, value, *args):
if bar == None: return False
if bar.BarExpired: return False
message, w, h = ConvertArgsToSingleString(*args)
bar.TextToDisplay = message
text_elem.Update(message)
# bar.TextToDisplay = message
bar.CurrentValue = value
rc = bar.UpdateBar(value)
if value >= bar.MaxValue or not rc:
@ -1998,6 +1915,7 @@ class EasyProgressMeterDataClass():
self.StatMessages = stat_messages
self.ParentForm = None
self.MeterID = None
self.MeterText = None
# =========================== COMPUTE PROGRESS STATS ======================#
def ComputeProgressStats(self):
@ -2059,7 +1977,7 @@ def EasyProgressMeter(title, current_value, max_value, *args, orientation=None,
EasyProgressMeter.EasyProgressMeterData = EasyProgressMeterDataClass(title, 1, int(max_value), datetime.datetime.utcnow(), [])
EasyProgressMeter.EasyProgressMeterData.ComputeProgressStats()
message = "\n".join([line for line in EasyProgressMeter.EasyProgressMeterData.StatMessages])
EasyProgressMeter.EasyProgressMeterData.MeterID = ProgressMeter(title, int(max_value), message, *args, orientation=orientation, bar_color=bar_color, size=size, scale=scale, button_color=button_color, border_width=local_border_width)
EasyProgressMeter.EasyProgressMeterData.MeterID, EasyProgressMeter.EasyProgressMeterData.MeterText= _ProgressMeter(title, int(max_value), message, *args, orientation=orientation, bar_color=bar_color, size=size, scale=scale, button_color=button_color, border_width=local_border_width)
EasyProgressMeter.EasyProgressMeterData.ParentForm = EasyProgressMeter.EasyProgressMeterData.MeterID.ParentForm
return True
# if exactly the same values as before, then ignore.
@ -2079,7 +1997,8 @@ def EasyProgressMeter(title, current_value, max_value, *args, orientation=None,
message = message + str(line) + '\n'
message = "\n".join(EasyProgressMeter.EasyProgressMeterData.StatMessages)
args= args + (message,)
rc = ProgressMeterUpdate(EasyProgressMeter.EasyProgressMeterData.MeterID, current_value, *args)
rc = _ProgressMeterUpdate(EasyProgressMeter.EasyProgressMeterData.MeterID, current_value,
EasyProgressMeter.EasyProgressMeterData.MeterText, *args)
# if counter >= max then the progress meter is all done. Indicate none running
if current_value >= EasyProgressMeter.EasyProgressMeterData.MaxValue or not rc:
EasyProgressMeter.EasyProgressMeterData.MeterID = None
@ -2422,6 +2341,40 @@ def SetOptions(icon=None, button_color=None, element_size=(None,None), margins=(
return True
#################### ChangeLookAndFeel #######################
# Predefined settings that will change the colors and styles #
# of the elements. #
##############################################################
def ChangeLookAndFeel(index):
# look and feel table
look_and_feel = {'GreenTan': {'BACKGROUND' : '#9FB8AD', 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT':'#F7F3EC', 'BUTTON': ('white', '#475841'),
'PROGRESS':DEFAULT_PROGRESS_BAR_COLOR},
'LightGreen' :{'BACKGROUND' : '#B7CECE', 'TEXT': 'black', 'INPUT':'#FDFFF7', 'BUTTON': ('white', '#658268'), 'PROGRESS':('#247BA0','#F8FAF0')},
'BluePurple': {'BACKGROUND' : '#A5CADD', 'TEXT': '#6E266E', 'INPUT':'#E0F5FF', 'BUTTON': ('white', '#303952'),'PROGRESS':DEFAULT_PROGRESS_BAR_COLOR}}
try:
colors = look_and_feel[index]
SetOptions(background_color=colors['BACKGROUND'],
text_element_background_color=colors['BACKGROUND'],
element_background_color=colors['BACKGROUND'],
text_color=colors['TEXT'],
input_elements_background_color=colors['INPUT'],
button_color=colors['BUTTON'],
progress_meter_color=colors['PROGRESS'],
border_width=0,
slider_border_width=0,
progress_meter_border_depth=0,
scrollbar_color=(colors['INPUT']),
element_text_color=colors['TEXT'])
except: # most likely an index out of range
pass
# ============================== sprint ======#
# Is identical to the Scrolled Text Box #
# Provides a crude 'print' mechanism but in a #
@ -2443,12 +2396,12 @@ def ObjToString(obj, extra=' '):
def main():
with FlexForm('Demo form..', auto_size_text=True) as form:
with FlexForm('Demo form..') as form:
form_rows = [[Text('You are running the PySimpleGUI.py file itself')],
[Text('You should be importing it rather than running it\n')],
[Text('Here is your sample input form....')],
[Text('Source Folder', size=(15, 1), auto_size_text=False, justification='right'), InputText('Source', focus=True),FolderBrowse()],
[Text('Destination Folder', size=(15, 1), auto_size_text=False, justification='right'), InputText('Dest'), FolderBrowse()],
[Text('Source Folder', size=(15, 1), justification='right'), InputText('Source', focus=True),FolderBrowse()],
[Text('Destination Folder', size=(15, 1), justification='right'), InputText('Dest'), FolderBrowse()],
[Submit(bind_return_key=True), Cancel()]]
button, (source, dest) = form.LayoutAndRead(form_rows)