commit
4b476d7d19
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
import PySimpleGUIQt as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
|
@ -683,13 +683,19 @@ layout = [[sg.Text('Hover mouse to see RGB value, click for white & black text',
|
|||
background_color='light green',
|
||||
pad=(0,(0,20))),]]
|
||||
|
||||
# -- Create primary color viewer window by building rows and appending to layout --
|
||||
# -- Create primary color viewer window --
|
||||
color_list = [key for key in color_map]
|
||||
for rows in range(40):
|
||||
|
||||
row = []
|
||||
for i, color in enumerate(color_map):
|
||||
row.append(sg.Button(color, button_color=('black', color), key=color, tooltip=color_map[color]))
|
||||
if (i+1) % 15 == 0: # every 15 buttons make a new row
|
||||
for i in range(12):
|
||||
try:
|
||||
color = color_list[rows+40*i]
|
||||
row.append(sg.Button(color, button_color=('black', color), key=color))
|
||||
except:
|
||||
pass
|
||||
layout.append(row)
|
||||
row = []
|
||||
|
||||
|
||||
window = sg.Window('Color Viewer', grab_anywhere=False, font=('any 9')).Layout(layout)
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ else:
|
|||
Once large window is shown, you can click on any color and another window will popup
|
||||
showing both white and black text on that color
|
||||
"""
|
||||
|
||||
|
||||
|
||||
COLORS = ['snow', 'ghost white', 'white smoke', 'gainsboro', 'floral white', 'old lace',
|
||||
'linen', 'antique white', 'papaya whip', 'blanched almond', 'bisque', 'peach puff',
|
||||
'navajo white', 'lemon chiffon', 'mint cream', 'azure', 'alice blue', 'lavender',
|
||||
|
@ -90,16 +93,32 @@ COLORS = ['snow', 'ghost white', 'white smoke', 'gainsboro', 'floral white', 'ol
|
|||
'grey84', 'grey85', 'grey86', 'grey87', 'grey88', 'grey89', 'grey90', 'grey91', 'grey92',
|
||||
'grey93', 'grey94', 'grey95', 'grey97', 'grey98', 'grey99']
|
||||
|
||||
|
||||
|
||||
|
||||
sg.SetOptions(button_element_size=(12,1), element_padding=(0,0), auto_size_buttons=False, border_width=0)
|
||||
|
||||
layout = [[sg.Text('Click on a color square to see both white and black text on that color', text_color='blue', font='Any 15')]]
|
||||
row = []
|
||||
layout = []
|
||||
# -- Create primary color viewer window --
|
||||
for i, color in enumerate(COLORS):
|
||||
row.append(sg.Button(color, button_color=('black', color), key=color))
|
||||
if (i+1) % 12 == 0:
|
||||
layout.append(row)
|
||||
for rows in range(40):
|
||||
|
||||
row = []
|
||||
for i in range(12):
|
||||
try:
|
||||
color = COLORS[rows+40*i]
|
||||
row.append(sg.Button(color, button_color=('black', color), key=color))
|
||||
except:
|
||||
pass
|
||||
layout.append(row)
|
||||
|
||||
|
||||
# for i, color in enumerate(COLORS):
|
||||
# row.append(sg.Button(color, button_color=('black', color), key=color))
|
||||
# if (i+1) % 12 == 0:
|
||||
# layout.append(row)
|
||||
# row = []
|
||||
|
||||
window = sg.Window('Color Viewer', grab_anywhere=False, font=('any 9')).Layout(layout)
|
||||
|
||||
|
|
448
PySimpleGUI.py
448
PySimpleGUI.py
|
@ -103,7 +103,6 @@ DEFAULT_ELEMENT_TEXT_COLOR = COLOR_SYSTEM_DEFAULT
|
|||
DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR = None
|
||||
DEFAULT_TEXT_COLOR = COLOR_SYSTEM_DEFAULT
|
||||
DEFAULT_INPUT_ELEMENTS_COLOR = COLOR_SYSTEM_DEFAULT
|
||||
DEFAULT_INPUT_ELEMENTS_COLOR = COLOR_SYSTEM_DEFAULT
|
||||
DEFAULT_INPUT_TEXT_COLOR = COLOR_SYSTEM_DEFAULT
|
||||
DEFAULT_SCROLLBAR_COLOR = None
|
||||
# DEFAULT_BUTTON_COLOR = (YELLOWS[0], PURPLES[0]) # (Text, Background) or (Color "on", Color) as a way to remember
|
||||
|
@ -128,7 +127,7 @@ RELIEF_GROOVE = 'groove'
|
|||
RELIEF_SOLID = 'solid'
|
||||
|
||||
DEFAULT_PROGRESS_BAR_COLOR = (GREENS[0], '#D0D0D0') # a nice green progress bar
|
||||
DEFAULT_PROGRESS_BAR_SIZE = (25, 20) # Size of Progress Bar (characters for length, pixels for width)
|
||||
DEFAULT_PROGRESS_BAR_SIZE = (20, 20) # Size of Progress Bar (characters for length, pixels for width)
|
||||
DEFAULT_PROGRESS_BAR_BORDER_WIDTH = 1
|
||||
DEFAULT_PROGRESS_BAR_RELIEF = RELIEF_GROOVE
|
||||
PROGRESS_BAR_STYLES = ('default', 'winnative', 'clam', 'alt', 'classic', 'vista', 'xpnative')
|
||||
|
@ -1156,6 +1155,10 @@ class StatusBar(Element):
|
|||
self.TKText.configure(fg=text_color)
|
||||
if font is not None:
|
||||
self.TKText.configure(font=font)
|
||||
if visible is False:
|
||||
self.TKText.pack_forget()
|
||||
elif visible is True:
|
||||
self.TKText.pack()
|
||||
|
||||
def __del__(self):
|
||||
super().__del__()
|
||||
|
@ -1169,7 +1172,7 @@ class StatusBar(Element):
|
|||
class TKProgressBar():
|
||||
def __init__(self, root, max, length=400, width=DEFAULT_PROGRESS_BAR_SIZE[1], style=DEFAULT_PROGRESS_BAR_STYLE,
|
||||
relief=DEFAULT_PROGRESS_BAR_RELIEF, border_width=DEFAULT_PROGRESS_BAR_BORDER_WIDTH,
|
||||
orientation='horizontal', BarColor=(None, None), key=None, visible=True):
|
||||
orientation='horizontal', BarColor=(None, None), key=None):
|
||||
self.Length = length
|
||||
self.Width = width
|
||||
self.Max = max
|
||||
|
@ -1295,7 +1298,7 @@ class Output(Element):
|
|||
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
|
||||
|
||||
super().__init__(ELEM_TYPE_OUTPUT, size=size, background_color=bg, text_color=fg, pad=pad, font=font,
|
||||
tooltip=tooltip, key=key)
|
||||
tooltip=tooltip, key=key, visible=visible)
|
||||
|
||||
@property
|
||||
def TKOut(self):
|
||||
|
@ -5362,273 +5365,120 @@ def ConvertArgsToSingleString(*args):
|
|||
return single_line_message, width_used, total_lines
|
||||
|
||||
|
||||
# ============================== ProgressMeter =====#
|
||||
# ===================================================#
|
||||
def _ProgressMeter(title, max_value, *args, orientation=None, bar_color=(None, None), button_color=None,
|
||||
size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False):
|
||||
'''
|
||||
Create and show a form on tbe caller's behalf.
|
||||
:param title:
|
||||
:param max_value:
|
||||
:param args: ANY number of arguments the caller wants to display
|
||||
:param orientation:
|
||||
:param bar_color:
|
||||
:param size:
|
||||
:param Style:
|
||||
:param StyleOffset:
|
||||
:return: ProgressBar object that is in the form
|
||||
'''
|
||||
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
|
||||
bar2 = ProgressBar(max_value, orientation=local_orientation, size=size, bar_color=bar_color,
|
||||
border_width=local_border_width, relief=DEFAULT_PROGRESS_BAR_RELIEF)
|
||||
form = Window(title, auto_size_text=True, grab_anywhere=grab_anywhere)
|
||||
METER_REASON_CANCELLED = 'cancelled'
|
||||
METER_REASON_CLOSED = 'closed'
|
||||
METER_REASON_REACHED_MAX = 'finished'
|
||||
METER_OK = True
|
||||
METER_STOPPED = False
|
||||
|
||||
# Form using a horizontal bar
|
||||
if local_orientation[0].lower() == 'h':
|
||||
single_line_message, width, height = ConvertArgsToSingleString(*args)
|
||||
bar2.TextToDisplay = single_line_message
|
||||
bar2.MaxValue = max_value
|
||||
bar2.CurrentValue = 0
|
||||
bar_text = Text(single_line_message, size=(width, height + 3), auto_size_text=True)
|
||||
form.AddRow(bar_text)
|
||||
form.AddRow((bar2))
|
||||
form.AddRow((CloseButton('Cancel', button_color=button_color)))
|
||||
class QuickMeter(object):
|
||||
active_meters = {}
|
||||
exit_reasons = {}
|
||||
|
||||
def __init__(self, title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None),
|
||||
button_color=(None, None), size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False):
|
||||
self.start_time = datetime.datetime.utcnow()
|
||||
self.key = key
|
||||
self.orientation = orientation
|
||||
self.bar_color = bar_color
|
||||
self.size = size
|
||||
self.grab_anywhere = grab_anywhere
|
||||
self.button_color = button_color
|
||||
self.border_width = border_width
|
||||
self.title = title
|
||||
self.current_value = current_value
|
||||
self.max_value = max_value
|
||||
self.close_reason = None
|
||||
self.window = self.BuildWindow(*args)
|
||||
|
||||
def BuildWindow(self, *args):
|
||||
layout = []
|
||||
if self.orientation.lower().startswith('h'):
|
||||
col = []
|
||||
for arg in args:
|
||||
col.append([T(arg)])
|
||||
col.append([T('', size=(30,10), key='_STATS_')])
|
||||
col.append([ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size)])
|
||||
col.append([Cancel(button_color=self.button_color), Stretch()])
|
||||
layout += [Column(col)]
|
||||
else:
|
||||
single_line_message, width, height = ConvertArgsToSingleString(*args)
|
||||
bar2.TextToDisplay = single_line_message
|
||||
bar2.MaxValue = max_value
|
||||
bar2.CurrentValue = 0
|
||||
bar_text = Text(single_line_message, size=(width, height + 3), auto_size_text=True)
|
||||
form.AddRow(bar2, bar_text)
|
||||
form.AddRow((CloseButton('Cancel', button_color=button_color)))
|
||||
col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size)]]
|
||||
col2 = []
|
||||
for arg in args:
|
||||
col2.append([T(arg)])
|
||||
col2.append([T('', size=(30,10), key='_STATS_')])
|
||||
col2.append([Cancel(button_color=self.button_color), Stretch()])
|
||||
layout += [Column(col), Column(col2)]
|
||||
self.window = Window(self.title, grab_anywhere=self.grab_anywhere, border_depth=self.border_width)
|
||||
self.window.Layout([layout]).Finalize()
|
||||
|
||||
form.NonBlocking = True
|
||||
form.Show(non_blocking=True)
|
||||
return bar2, bar_text
|
||||
return self.window
|
||||
|
||||
def UpdateMeter(self, current_value, max_value):
|
||||
self.current_value = current_value
|
||||
self.max_value = max_value
|
||||
self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value)
|
||||
self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats()))
|
||||
event, values = self.window.Read(timeout=0)
|
||||
if event in('Cancel', None) or current_value >= max_value:
|
||||
self.window.Close()
|
||||
del(QuickMeter.active_meters[self.key])
|
||||
QuickMeter.exit_reasons[self.key] = METER_REASON_CANCELLED if event == 'Cancel' else METER_REASON_CLOSED if event is None else METER_REASON_REACHED_MAX
|
||||
return QuickMeter.exit_reasons[self.key]
|
||||
return METER_OK
|
||||
|
||||
|
||||
# ============================== ProgressMeterUpdate =====#
|
||||
def _ProgressMeterUpdate(bar, value, text_elem, *args):
|
||||
'''
|
||||
Update the progress meter for a form
|
||||
:param form: class ProgressBar
|
||||
:param value: int
|
||||
:return: True if not cancelled, OK....False if Error
|
||||
'''
|
||||
# global _my_windows
|
||||
if bar == None: return False
|
||||
if bar.BarExpired: return False
|
||||
message, w, h = ConvertArgsToSingleString(*args)
|
||||
text_elem.Update(message)
|
||||
# bar.TextToDisplay = message
|
||||
bar.CurrentValue = value
|
||||
rc = bar.UpdateBar(value)
|
||||
if value >= bar.MaxValue or not rc:
|
||||
bar.BarExpired = True
|
||||
bar.ParentForm._Close()
|
||||
if rc: # if update was OK but bar expired, decrement num windows
|
||||
# _my_windows.Decrement()
|
||||
Window.DecrementOpenCount()
|
||||
if bar.ParentForm.RootNeedsDestroying:
|
||||
try:
|
||||
bar.ParentForm.TKroot.destroy()
|
||||
# there is a bug with progress meters not decrementing the number of windows
|
||||
# correctly when the X is used to close the window
|
||||
# uncommenting this line fixes that problem, but causes a double-decrement when
|
||||
# the cancel button is used... damned if you do, damned if you don't, so I'm choosing
|
||||
# don't, as in don't decrement too many times. It's OK now to have a mismatch in
|
||||
# number of windows because of the "hidden" master window. This ensures all windows
|
||||
# will be toplevel. Sorry about the bug, but the user never sees any problems as a result
|
||||
# _my_windows.Decrement()
|
||||
except:
|
||||
pass
|
||||
bar.ParentForm.RootNeedsDestroying = False
|
||||
bar.ParentForm.__del__()
|
||||
return False
|
||||
|
||||
return rc
|
||||
|
||||
|
||||
# ============================== EASY PROGRESS METER ========================================== #
|
||||
# class to hold the easy meter info (a global variable essentialy)
|
||||
class EasyProgressMeterDataClass():
|
||||
def __init__(self, title='', current_value=1, max_value=10, start_time=None, stat_messages=()):
|
||||
self.Title = title
|
||||
self.CurrentValue = current_value
|
||||
self.MaxValue = max_value
|
||||
self.StartTime = start_time
|
||||
self.StatMessages = stat_messages
|
||||
self.ParentForm = None
|
||||
self.MeterID = None
|
||||
self.MeterText = None
|
||||
|
||||
# =========================== COMPUTE PROGRESS STATS ======================#
|
||||
def ComputeProgressStats(self):
|
||||
utc = datetime.datetime.utcnow()
|
||||
time_delta = utc - self.StartTime
|
||||
time_delta = utc - self.start_time
|
||||
total_seconds = time_delta.total_seconds()
|
||||
if not total_seconds:
|
||||
total_seconds = 1
|
||||
try:
|
||||
time_per_item = total_seconds / self.CurrentValue
|
||||
time_per_item = total_seconds / self.current_value
|
||||
except:
|
||||
time_per_item = 1
|
||||
seconds_remaining = (self.MaxValue - self.CurrentValue) * time_per_item
|
||||
seconds_remaining = (self.max_value - self.current_value) * time_per_item
|
||||
time_remaining = str(datetime.timedelta(seconds=seconds_remaining))
|
||||
time_remaining_short = (time_remaining).split(".")[0]
|
||||
time_delta_short = str(time_delta).split(".")[0]
|
||||
total_time = time_delta + datetime.timedelta(seconds=seconds_remaining)
|
||||
total_time_short = str(total_time).split(".")[0]
|
||||
self.StatMessages = [
|
||||
'{} of {}'.format(self.CurrentValue, self.MaxValue),
|
||||
'{} %'.format(100 * self.CurrentValue // self.MaxValue),
|
||||
self.stat_messages = [
|
||||
'{} of {}'.format(self.current_value, self.max_value),
|
||||
'{} %'.format(100 * self.current_value // self.max_value),
|
||||
'',
|
||||
' {:6.2f} Iterations per Second'.format(self.CurrentValue / total_seconds),
|
||||
' {:6.2f} Seconds per Iteration'.format(total_seconds / (self.CurrentValue if self.CurrentValue else 1)),
|
||||
' {:6.2f} Iterations per Second'.format(self.current_value / total_seconds),
|
||||
' {:6.2f} Seconds per Iteration'.format(total_seconds / (self.current_value if self.current_value else 1)),
|
||||
'',
|
||||
'{} Elapsed Time'.format(time_delta_short),
|
||||
'{} Time Remaining'.format(time_remaining_short),
|
||||
'{} Estimated Total Time'.format(total_time_short)]
|
||||
return
|
||||
return self.stat_messages
|
||||
|
||||
|
||||
# ============================== EasyProgressMeter =====#
|
||||
def EasyProgressMeter(title, current_value, max_value, *args, orientation=None, bar_color=(None, None),
|
||||
button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None):
|
||||
'''
|
||||
A ONE-LINE progress meter. Add to your code where ever you need a meter. No need for a second
|
||||
function call before your loop. You've got enough code to write!
|
||||
:param title: Title will be shown on the window
|
||||
:param current_value: Current count of your items
|
||||
:param max_value: Max value your count will ever reach. This indicates it should be closed
|
||||
:param args: VARIABLE number of arguements... you request it, we'll print it no matter what the item!
|
||||
:param orientation:
|
||||
:param bar_color:
|
||||
:param size:
|
||||
:param Style:
|
||||
:param StyleOffset:
|
||||
:return: False if should stop the meter
|
||||
'''
|
||||
local_border_width = DEFAULT_PROGRESS_BAR_BORDER_WIDTH if not border_width else border_width
|
||||
# STATIC VARIABLE!
|
||||
# This is a very clever form of static variable using a function attribute
|
||||
# If the variable doesn't yet exist, then it will create it and initialize with the 3rd parameter
|
||||
EasyProgressMeter.Data = getattr(EasyProgressMeter, 'Data', EasyProgressMeterDataClass())
|
||||
# if no meter currently running
|
||||
if EasyProgressMeter.Data.MeterID is None: # Starting a new meter
|
||||
print(
|
||||
"Please change your call of EasyProgressMeter to use OneLineProgressMeter. EasyProgressMeter will be removed soon")
|
||||
if int(current_value) >= int(max_value):
|
||||
return False
|
||||
del (EasyProgressMeter.Data)
|
||||
EasyProgressMeter.Data = EasyProgressMeterDataClass(title, 1, int(max_value), datetime.datetime.utcnow(), [])
|
||||
EasyProgressMeter.Data.ComputeProgressStats()
|
||||
message = "\n".join([line for line in EasyProgressMeter.Data.StatMessages])
|
||||
EasyProgressMeter.Data.MeterID, EasyProgressMeter.Data.MeterText = _ProgressMeter(title, int(max_value),
|
||||
message, *args,
|
||||
orientation=orientation,
|
||||
bar_color=bar_color,
|
||||
size=size,
|
||||
button_color=button_color,
|
||||
border_width=local_border_width)
|
||||
EasyProgressMeter.Data.ParentForm = EasyProgressMeter.Data.MeterID.ParentForm
|
||||
return True
|
||||
# if exactly the same values as before, then ignore.
|
||||
if EasyProgressMeter.Data.MaxValue == max_value and EasyProgressMeter.Data.CurrentValue == current_value:
|
||||
return True
|
||||
if EasyProgressMeter.Data.MaxValue != int(max_value):
|
||||
EasyProgressMeter.Data.MeterID = None
|
||||
EasyProgressMeter.Data.ParentForm = None
|
||||
del (EasyProgressMeter.Data)
|
||||
EasyProgressMeter.Data = EasyProgressMeterDataClass() # setup a new progress meter
|
||||
return True # HAVE to return TRUE or else the new meter will thing IT is failing when it hasn't
|
||||
EasyProgressMeter.Data.CurrentValue = int(current_value)
|
||||
EasyProgressMeter.Data.MaxValue = int(max_value)
|
||||
EasyProgressMeter.Data.ComputeProgressStats()
|
||||
message = ''
|
||||
for line in EasyProgressMeter.Data.StatMessages:
|
||||
message = message + str(line) + '\n'
|
||||
message = "\n".join(EasyProgressMeter.Data.StatMessages)
|
||||
args = args + (message,)
|
||||
rc = _ProgressMeterUpdate(EasyProgressMeter.Data.MeterID, current_value,
|
||||
EasyProgressMeter.Data.MeterText, *args)
|
||||
# if counter >= max then the progress meter is all done. Indicate none running
|
||||
if current_value >= EasyProgressMeter.Data.MaxValue or not rc:
|
||||
EasyProgressMeter.Data.MeterID = None
|
||||
del (EasyProgressMeter.Data)
|
||||
EasyProgressMeter.Data = EasyProgressMeterDataClass() # setup a new progress meter
|
||||
return False # even though at the end, return True so don't cause error with the app
|
||||
return rc # return whatever the update told us
|
||||
|
||||
|
||||
def EasyProgressMeterCancel(title, *args):
|
||||
EasyProgressMeter.EasyProgressMeterData = getattr(EasyProgressMeter, 'EasyProgressMeterData',
|
||||
EasyProgressMeterDataClass())
|
||||
if EasyProgressMeter.EasyProgressMeterData.MeterID is not None:
|
||||
# tell the normal meter update that we're at max value which will close the meter
|
||||
rc = EasyProgressMeter(title, EasyProgressMeter.EasyProgressMeterData.MaxValue,
|
||||
EasyProgressMeter.EasyProgressMeterData.MaxValue, ' *** CANCELLING ***',
|
||||
'Caller requested a cancel', *args)
|
||||
return rc
|
||||
return True
|
||||
|
||||
|
||||
# global variable containing dictionary will all currently running one-line progress meters.
|
||||
_one_line_progress_meters = {}
|
||||
|
||||
|
||||
# ============================== OneLineProgressMeter =====#
|
||||
def OneLineProgressMeter(title, current_value, max_value, key, *args, orientation=None, bar_color=(None, None),
|
||||
def OneLineProgressMeter(title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None),
|
||||
button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False):
|
||||
global _one_line_progress_meters
|
||||
|
||||
local_border_width = DEFAULT_PROGRESS_BAR_BORDER_WIDTH if border_width is not None else border_width
|
||||
try:
|
||||
meter_data = _one_line_progress_meters[key]
|
||||
except: # a new meater is starting
|
||||
if int(current_value) >= int(max_value): # if already expired then it's an old meter, ignore
|
||||
return False
|
||||
meter_data = EasyProgressMeterDataClass(title, 1, int(max_value), datetime.datetime.utcnow(), [])
|
||||
_one_line_progress_meters[key] = meter_data
|
||||
meter_data.ComputeProgressStats()
|
||||
message = "\n".join([line for line in meter_data.StatMessages])
|
||||
meter_data.MeterID, meter_data.MeterText = _ProgressMeter(title, int(max_value), message, *args,
|
||||
orientation=orientation, bar_color=bar_color,
|
||||
size=size, button_color=button_color,
|
||||
border_width=local_border_width,
|
||||
grab_anywhere=grab_anywhere)
|
||||
meter_data.ParentForm = meter_data.MeterID.ParentForm
|
||||
return True
|
||||
|
||||
# if exactly the same values as before, then ignore, return success.
|
||||
if meter_data.MaxValue == max_value and meter_data.CurrentValue == current_value:
|
||||
return True
|
||||
meter_data.CurrentValue = int(current_value)
|
||||
meter_data.MaxValue = int(max_value)
|
||||
meter_data.ComputeProgressStats()
|
||||
message = ''
|
||||
for line in meter_data.StatMessages:
|
||||
message = message + str(line) + '\n'
|
||||
message = "\n".join(meter_data.StatMessages)
|
||||
args = args + (message,)
|
||||
rc = _ProgressMeterUpdate(meter_data.MeterID, current_value,
|
||||
meter_data.MeterText, *args)
|
||||
# if counter >= max then the progress meter is all done. Indicate none running
|
||||
if current_value >= meter_data.MaxValue or not rc:
|
||||
del _one_line_progress_meters[key]
|
||||
return False
|
||||
return rc # return whatever the update told us
|
||||
if key not in QuickMeter.active_meters:
|
||||
meter = QuickMeter(title, current_value, max_value, key, *args, orientation=orientation, bar_color=bar_color,
|
||||
button_color=button_color, size=size, border_width=border_width, grab_anywhere=grab_anywhere)
|
||||
QuickMeter.active_meters[key] = meter
|
||||
else:
|
||||
meter = QuickMeter.active_meters[key]
|
||||
|
||||
rc = meter.UpdateMeter(current_value, max_value)
|
||||
OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons)
|
||||
return rc == METER_OK
|
||||
|
||||
def OneLineProgressMeterCancel(key):
|
||||
global _one_line_progress_meters
|
||||
|
||||
try:
|
||||
meter_data = _one_line_progress_meters[key]
|
||||
meter = QuickMeter.active_meters[key]
|
||||
meter.window.Close()
|
||||
del(QuickMeter.active_meters[key])
|
||||
QuickMeter.exit_reasons[key] = METER_REASON_CANCELLED
|
||||
except: # meter is already deleted
|
||||
return
|
||||
OneLineProgressMeter('', meter_data.MaxValue, meter_data.MaxValue, key=key)
|
||||
|
||||
|
||||
|
||||
# input is #RRGGBB
|
||||
|
@ -6885,18 +6735,120 @@ def PopupGetText(message, title=None, default_text='', password_char='', size=(N
|
|||
|
||||
|
||||
def main():
|
||||
layout = [[Text('You are running the PySimpleGUI.py file itself')],
|
||||
[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(tooltip='Browse for a folder')],
|
||||
[Text('Destination Folder', size=(15, 1), justification='right'), InputText('Dest'), FolderBrowse()],
|
||||
[Ok(bind_return_key=True), Cancel()]]
|
||||
from random import randint
|
||||
|
||||
window = Window('Demo window..').Layout(layout)
|
||||
event, values = window.Read()
|
||||
ChangeLookAndFeel('GreenTan')
|
||||
# ------ Menu Definition ------ #
|
||||
menu_def = [['&File', ['!&Open', '&Save::savekey', '---', '&Properties', 'E&xit']],
|
||||
['!&Edit', ['!&Paste', ['Special', 'Normal', ], 'Undo'], ],
|
||||
['&Toolbar', ['Command &1', 'Command &2', 'Command &3', 'Command &4']],
|
||||
['&Help', '&About...'], ]
|
||||
|
||||
treedata = TreeData()
|
||||
|
||||
treedata.Insert("", '_A_', 'Tree Item 1', [1, 2, 3], )
|
||||
treedata.Insert("", '_B_', 'B', [4, 5, 6], )
|
||||
treedata.Insert("_A_", '_A1_', 'Sub Item 1', ['can', 'be', 'anything'], )
|
||||
treedata.Insert("", '_C_', 'C', [], )
|
||||
treedata.Insert("_C_", '_C1_', 'C1', ['or'], )
|
||||
treedata.Insert("_A_", '_A2_', 'Sub Item 2', [None, None])
|
||||
treedata.Insert("_A1_", '_A3_', 'A30', ['getting deep'])
|
||||
treedata.Insert("_C_", '_C2_', 'C2', ['nothing', 'at', 'all'])
|
||||
|
||||
for i in range(100):
|
||||
treedata.Insert('_C_', i, i, [])
|
||||
|
||||
frame1 = [
|
||||
[Input('Input Text', size=(25, 1)), ],
|
||||
[Multiline(size=(30, 5), default_text='Multiline Input')],
|
||||
]
|
||||
|
||||
frame2 = [
|
||||
[Listbox(['Listbox 1', 'Listbox 2', 'Listbox 3'], size=(20, 5))],
|
||||
[Combo(['Combo item 1', ], size=(20, 3))],
|
||||
[Spin([1, 2, 3], size=(4, 3))],
|
||||
]
|
||||
|
||||
frame3 = [
|
||||
[Checkbox('Checkbox1', True), Checkbox('Checkbox1')],
|
||||
[Radio('Radio Button1', 1), Radio('Radio Button2', 1, default=True)],
|
||||
[T('', size=(1, 4))],
|
||||
]
|
||||
|
||||
frame4 = [
|
||||
[Slider(range=(0, 100), orientation='v', size=(7, 15), default_value=40),
|
||||
Slider(range=(0, 100), orientation='h', size=(11, 15), default_value=40), ],
|
||||
]
|
||||
matrix = [[str(x * y) for x in range(4)] for y in range(8)]
|
||||
|
||||
frame5 = [
|
||||
[Table(values=matrix, headings=matrix[0],
|
||||
auto_size_columns=False, display_row_numbers=True, change_submits=False, justification='right',
|
||||
num_rows=10, alternating_row_color='lightblue', key='_table_', text_color='black',
|
||||
col_widths=[5, 5, 5, 5], size=(400, 200)), T(' '),
|
||||
Tree(data=treedata, headings=['col1', 'col2', 'col3'], change_submits=True, auto_size_columns=True,
|
||||
num_rows=10, col0_width=10, key='_TREE_', show_expanded=True, )],
|
||||
]
|
||||
|
||||
graph_elem = Graph((800, 150), (0, 0), (800, 300), key='+GRAPH+')
|
||||
|
||||
frame6 = [
|
||||
[graph_elem],
|
||||
]
|
||||
|
||||
tab1 = Tab('Graph Number 1', frame6)
|
||||
tab2 = Tab('Graph Number 2', [[]])
|
||||
|
||||
layout = [
|
||||
[Menu(menu_def)],
|
||||
[Text('You are running the PySimpleGUI.py file itself', font='ANY 15')],
|
||||
[Text('You should be importing it rather than running it', font='ANY 15')],
|
||||
[Frame('Input Text Group', frame1, title_color='red'), ],
|
||||
[Frame('Multiple Choice Group', frame2, title_color='green'),
|
||||
Frame('Binary Choice Group', frame3, title_color='purple'),
|
||||
Frame('Variable Choice Group', frame4, title_color='blue')],
|
||||
[Frame('Structured Data Group', frame5, title_color='red'), ],
|
||||
# [Frame('Graphing Group', frame6)],
|
||||
[TabGroup([[tab1, tab2]])],
|
||||
[ProgressBar(max_value=800, size=(60, 25), key='+PROGRESS+'), Button('Button'), Button('Exit')],
|
||||
]
|
||||
|
||||
window = Window('Window Title',
|
||||
font=('Helvetica', 13)).Layout(layout).Finalize()
|
||||
graph_elem.DrawCircle((200, 200), 50, 'blue')
|
||||
i = 0
|
||||
while True: # Event Loop
|
||||
# TimerStart()
|
||||
event, values = window.Read(timeout=0)
|
||||
if event != TIMEOUT_KEY:
|
||||
print(event, values)
|
||||
if event is None or event == 'Exit':
|
||||
break
|
||||
if i < 800:
|
||||
graph_elem.DrawLine((i, 0), (i, randint(0, 300)), width=1, color='#{:06x}'.format(randint(0, 0xffffff)))
|
||||
else:
|
||||
graph_elem.Move(-1, 0)
|
||||
graph_elem.DrawLine((i, 0), (i, randint(0, 300)), width=1, color='#{:06x}'.format(randint(0, 0xffffff)))
|
||||
|
||||
window.FindElement('+PROGRESS+').UpdateBar(i % 800)
|
||||
|
||||
i += 1
|
||||
# TimerStop()
|
||||
window.Close()
|
||||
|
||||
|
||||
# layout = [[Text('You are running the PySimpleGUI.py file itself')],
|
||||
# [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(tooltip='Browse for a folder')],
|
||||
# [Text('Destination Folder', size=(15, 1), justification='right'), InputText('Dest'), FolderBrowse()],
|
||||
# [Ok(bind_return_key=True), Cancel()]]
|
||||
#
|
||||
# window = Window('Demo window..').Layout(layout)
|
||||
# event, values = window.Read()
|
||||
# window.Close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
exit(69)
|
||||
|
|
1040
PySimpleGUI27.py
1040
PySimpleGUI27.py
File diff suppressed because it is too large
Load Diff
|
@ -16,7 +16,7 @@
|
|||
|
||||
![Python Version](https://img.shields.io/badge/Python-3.x-yellow.svg)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-00.21.0-orange.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-00.19.0-orange.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
|||
"Qt without the ugly"
|
||||
|
||||
|
||||
## The Alpha Release Version 0.21.0
|
||||
## The Alpha Release Version 0.18.0
|
||||
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ Welcome to the Alpha Release of PySimpleGUI for Qt!
|
|||
|
||||
You can use the exact same code that you are running on the older, tkinter, version of PySimpleGUI.
|
||||
|
||||
PySimpleGUIQt uses **PySide2** OR **PyQt5** for access to Qt. **PyQt5 has been having a number of problems recently however so tread lightly.**
|
||||
PySimpleGUIQt uses **PySide2** OR **PyQt5** for access to Qt. PyQt5 has been having a number of problems recently however so tread lightly.
|
||||
|
||||
## Porting your PySimpleGUI code to PySimpleGUIQt
|
||||
|
||||
|
@ -153,14 +153,13 @@ These Elements are "complete" (a relative term... more are more complete than ot
|
|||
Notable MISSING features at the moment include:
|
||||
* Graphs Element Methods - erasing, draw arc, etc
|
||||
|
||||
# New PySimpleGUI Features only in Qt (or first introduced in Qt)
|
||||
# New PySimpleGUI Features only in Qt
|
||||
|
||||
There are a number of new features that are only available in PySimpleGUIQt. These include:
|
||||
* ButtonMenu Element
|
||||
* Dial Element
|
||||
* Stretcher Element
|
||||
* SystemTray feature
|
||||
* "Dynamic" windows that grow and shrink (uses invisible elements)
|
||||
|
||||
## SystemTray
|
||||
|
||||
|
@ -219,7 +218,7 @@ You will find 3 parameters used to specify these 3 options on both the initializ
|
|||
|
||||
## Menu Definition
|
||||
```python
|
||||
menu_def = ['BLANK', ['&Open', '&Save', ['1', '2', ['a', 'b']], '!&Properties', 'E&xit']]
|
||||
menu_def = ['BLANK', ['&Open', '&Save', ['1', '2', ['a', 'b']], '&Properties', 'E&xit']]
|
||||
```
|
||||
|
||||
A menu is defined using a list. A "Menu entry" is a string that specifies:
|
||||
|
@ -227,7 +226,7 @@ A menu is defined using a list. A "Menu entry" is a string that specifies:
|
|||
* keyboard shortcut
|
||||
* key
|
||||
|
||||
See section on Menu Keys for more information on using keys with menus.
|
||||
See section on Menu Keys for more informatoin on using keys with menus.
|
||||
|
||||
An entry without a key and keyboard shortcut is a simple string
|
||||
`'Menu Item'`
|
||||
|
@ -244,10 +243,6 @@ The first entry can be ignored.`'BLANK`' was chosen for this example. It's this
|
|||
**Separators**
|
||||
If you want a separator between 2 items, add the entry `'---'` and it will add a separator item at that place in your menu.
|
||||
|
||||
**Disabled menu entries**
|
||||
|
||||
If you want to disable a menu entry, place a `!` before the menu entry
|
||||
|
||||
|
||||
## SystemTray Methods
|
||||
|
||||
|
@ -365,18 +360,6 @@ If you want to change the separator characters from :: top something else,change
|
|||
When a menu item has a key and it is chosen, then entire string is returned. If Hide were selected, then Hide::key would be returned from the Read. Note that the shortcut character & is NOT returned from Reads.
|
||||
|
||||
|
||||
## Dynamic Windows (Element Visibility)
|
||||
|
||||
Finally, the ability to grow and shrink has been added as of release 0.20.0
|
||||
|
||||
While the window **appears** to be dynamic, the reality is that the elements are created up front, when you define the window layout. You will create these "extra" elements with the flag `visible=False`. Then, when you wish to show those elements, call the element's `Update` method setting `visible=True`.
|
||||
|
||||
After you call the `Update` method, it's important to call `window.VisibilityChanged()` so that your window can change sizes. Without that call your window will not shrink. It will grow properly, but it will not shrink. While this could have been done by PySimpleGUI on the user's behalf, the thought was that perhaps the user wants the window size to remain the same and the element simply appears and disappears, leaving a blank spot. If the window automatically grew and shrank, this would not be possible. Just buck-up and make the call to `VisibilityChanged`.
|
||||
|
||||
## `enable_events` Parameter
|
||||
|
||||
All elements that are capable of producing events now have a parameter `enable_events`. This is *identical* to the old parameter `change_submits` or `click_submits`. The idea is to standardize on 1 name that all elements use. The old parameters will continue to work, but the documentation and sample programs will steer you away from them and towards enable_events.
|
||||
|
||||
# Release Notes:
|
||||
|
||||
### 0.12.0 - 20-Nov-2018
|
||||
|
@ -503,111 +486,6 @@ Window - Get screen dimensions
|
|||
Slider - disable
|
||||
Dial - disable
|
||||
|
||||
### 0.20.0 6-Dec-2018
|
||||
|
||||
* Ability to change calculations between characters and pixels
|
||||
* size_px added to ALL elements that have a size parameter
|
||||
* General Element.Update(widget, background_color, text_color, font, visible)
|
||||
* visible parameter added to ALL elements
|
||||
* enable_events flag
|
||||
* Input text - enable events, visibility, size_px
|
||||
* Input text update added capabilities
|
||||
* ability to highlight the input string
|
||||
* background, text colors and font
|
||||
* Combo - enable events, visibility, size_px
|
||||
* Combo - auto complete feature
|
||||
* Combo - added to Update - background color, text color, font, visible
|
||||
* Listbox - enable events, visibility, size_px
|
||||
* Listbox - better scaling from characters to pixels
|
||||
* Listbox - ability to Update with set to index, text color, font, visibility
|
||||
* Radio - enable events, visibility, size_px
|
||||
* Radio - Update additions - background_color, text_color, font, visibility
|
||||
* Checkbox - enable events, visibility, size_px
|
||||
* Checkbox - Update additions - background_color, text_color, font, visibility
|
||||
* Spin - enable events, visibility, size_px
|
||||
* Spin - Update additions - background_color, text_color, font, visibility
|
||||
* Multiline input - enable events, visibility, size_px
|
||||
* Multiline input - Update additions - background_color, text_color, font, visibility
|
||||
* Multiline input better character to pixel scaling
|
||||
* Multiline output - enable events, visibility, size_px
|
||||
* Multiline output - Update additions - background_color, text_color, visibility
|
||||
* Text - enable events, size in pixels
|
||||
* Text - Update addition of visibility
|
||||
* Output - visible, size_px
|
||||
* Output - added update capability with new value, background_color, text_color, font, visibility
|
||||
* Button - enable events, visible, size_px
|
||||
* Button - Color Chooser feature completed
|
||||
* Button - Color Chooser can target (None, None) which will store the value to be returned with the values from Read()
|
||||
* Button - fixed bug in SaveAs button code. Bad filter variable
|
||||
* Button - Updated added font, visibility
|
||||
* Button - new SetFocus() method will set the focus onto the button
|
||||
* ButtonMenu - Update method implemented that includes menu definition changes, text, button color, font, visibility
|
||||
* ProgressBar - added visibility, size_px
|
||||
* ProgressBar - added Update method for changing the visibility
|
||||
* Images - events, size_pix, visibility
|
||||
* Images - can now get click events for images!
|
||||
* Images - Update added visibility
|
||||
* Graph - visibility, size_px
|
||||
* Graph - Update method for changing visibility
|
||||
* Frame - visibility, size_px
|
||||
* Frame - Update method added that controls visibility
|
||||
* ALL elements inside of a Frame that's invisible will also be invisible
|
||||
* Tab - visible parameter added, however not yet functional!
|
||||
* TabGroup - enable events, visibility
|
||||
* TabGroup - Update for controlling visibility
|
||||
* Slider - enable events, size_px
|
||||
* Slider - Update method now includes visibility
|
||||
* Dial - enable events, size_px, visibility
|
||||
* Dial - Update method added visibilty control
|
||||
* Column - visibility added
|
||||
* Column - Added Update method to control visibility
|
||||
* ALL elements inside of an invisible Column Element will also be invisible
|
||||
* MenuBar - added visibility
|
||||
* MenuBar - Update can now change menu definitions at runtime, and control visibility
|
||||
* Table - enable events, size_px, visibility
|
||||
* Table - Update method can control visibility
|
||||
* Tree - enable events, size_px, visibility
|
||||
* Tree - Update method can control visibility
|
||||
* VisibilityChanged() function that must be called when using Qt so that the window will shrink or grow
|
||||
* window.GetScreenDimensions can now be called prior to window creation
|
||||
* window.Size property
|
||||
* enable_events added to all of the shortcut buttons and browse buttons
|
||||
* Ability to set a button image from a file
|
||||
* Combo - ability to set a default value
|
||||
* Combo - Read only setting. Allows for user editing of value
|
||||
* Menus - Ability to disable / enable any part of a menu by adding a ! before the entry name
|
||||
* Tabs - ability to set tab text color, background color, background color of selected tab
|
||||
* Tabs - ability to set widget area's background color
|
||||
* Sliders - paging works properly (using page-up page-down or slider slider area to advance slider)
|
||||
* Tree - Setting number of visible rows implemented
|
||||
* Added 5 pixels to every window. Have been having issues with text being cutoff on the right side
|
||||
* SetOptions - ability to change default error button color for popups
|
||||
|
||||
### 0.21.0 - 9-Dec-2018
|
||||
|
||||
* Removed use of global variabels - using static class variabels instead
|
||||
* Listbox.Get() will return current listbox value
|
||||
* Progressbar now has color support
|
||||
* Progressbar can be vertical now
|
||||
* Can change bar or back and background color
|
||||
* (barcolor, background color - None if use default)
|
||||
* Table num_rows parameter implemented
|
||||
* Table.Update - can change number of visible rows
|
||||
* Window resizable parm - implemented, default changed from False to True
|
||||
* Window.Move - implemented
|
||||
* Window.Minimize - implemented
|
||||
* Window.Disable - implemented
|
||||
* Window.Enable - implemented
|
||||
* Window.CurrentLocation - implemented
|
||||
* Fixed too small scrollbar in Combobox
|
||||
* Fixed too small scrollbar in Listbox
|
||||
* Changed "text" window to a complex one for quick regression testing (try running PySimpleGUIQt.py by itself)
|
||||
|
||||
### 0.22.0 - 9-Dec-2018
|
||||
|
||||
* Spin.Get method - get the current spinner value
|
||||
|
||||
|
||||
# Design
|
||||
## Author
|
||||
Mike B.
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
|
||||
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.17.0-red.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.18.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.17.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.18.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-0.19.0-orange.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
|
@ -4194,6 +4194,54 @@ Emergency patch release... going out same day as previous release
|
|||
* Stretch Element (DUMMY) so that can be source code compatible with Qt
|
||||
* ButtonMenu Element (DUMMY) so can be source code compat with Qt. Will implement eventually
|
||||
|
||||
## 3.18.0 11-Dec-2018
|
||||
|
||||
NOTE - **Menus are broken** on version 2.7. Don't know how long they've been this way. Please get off legacy Python if that's what you're running.
|
||||
|
||||
* Default progress bar length changed to shorter
|
||||
* Master window and tracking of num open windows moved from global to Window class variable
|
||||
* Element visibility setting (when created and when Updating element)
|
||||
* Input text visiblity
|
||||
* Combo visiblity
|
||||
* Combo replaces InputCombo as the primary class name
|
||||
* Option menu visibility
|
||||
* Listbox visiblity
|
||||
* Listbox new SetFocus method
|
||||
* Radio visibility
|
||||
* Checkbox visibility
|
||||
* Spin visiblity
|
||||
* Spin new Get method returns current value
|
||||
* Multiline visiblity
|
||||
* Text visibility
|
||||
* StatusBar visiblity
|
||||
* Output visibility
|
||||
* Button visibility
|
||||
* Button SetFocus
|
||||
* ProgressBar - New Update method (used only for visibility)
|
||||
* Image - clickable images! enable_events parameter
|
||||
* Image visibility
|
||||
* Canvas visibility
|
||||
* Graph visibility
|
||||
* Graph - new DrawImage capability (finally)
|
||||
* Frame visibility
|
||||
* Tab visibility (may not be fully functional)
|
||||
* TabGroup visibility
|
||||
* Slider visibility
|
||||
* Slider - new disable_number_display parameter
|
||||
* Column visibilty
|
||||
* Menu visibility - Not functional
|
||||
* Table visibility
|
||||
* Table - new num_rows parm for Update - changes number of visible rows
|
||||
* Tree visiblity
|
||||
* Window - New element_padding parameter will get padding for entire window
|
||||
* OneLineProgressMeter - Completely REPLACED the implementation
|
||||
* OneLineProgressMeter - can get reason for the cancellation (cancel button versus X)
|
||||
* EasyProgressMeter - completely removed. Use OneLineProgressMeter instead
|
||||
* Debug window, EasyPrint, Print - debug window will re-open if printed to after being closed
|
||||
* SetOptions - can change the error button color
|
||||
* Much bigger window created when running PySimpleGUI.py by itself. Meant to help with regression testing
|
||||
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
||||
|
|
52
readme.md
52
readme.md
|
@ -31,9 +31,9 @@
|
|||
|
||||
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.17.0-red.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.18.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.17.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.18.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-0.19.0-orange.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
|
@ -4194,6 +4194,54 @@ Emergency patch release... going out same day as previous release
|
|||
* Stretch Element (DUMMY) so that can be source code compatible with Qt
|
||||
* ButtonMenu Element (DUMMY) so can be source code compat with Qt. Will implement eventually
|
||||
|
||||
## 3.18.0 11-Dec-2018
|
||||
|
||||
NOTE - **Menus are broken** on version 2.7. Don't know how long they've been this way. Please get off legacy Python if that's what you're running.
|
||||
|
||||
* Default progress bar length changed to shorter
|
||||
* Master window and tracking of num open windows moved from global to Window class variable
|
||||
* Element visibility setting (when created and when Updating element)
|
||||
* Input text visiblity
|
||||
* Combo visiblity
|
||||
* Combo replaces InputCombo as the primary class name
|
||||
* Option menu visibility
|
||||
* Listbox visiblity
|
||||
* Listbox new SetFocus method
|
||||
* Radio visibility
|
||||
* Checkbox visibility
|
||||
* Spin visiblity
|
||||
* Spin new Get method returns current value
|
||||
* Multiline visiblity
|
||||
* Text visibility
|
||||
* StatusBar visiblity
|
||||
* Output visibility
|
||||
* Button visibility
|
||||
* Button SetFocus
|
||||
* ProgressBar - New Update method (used only for visibility)
|
||||
* Image - clickable images! enable_events parameter
|
||||
* Image visibility
|
||||
* Canvas visibility
|
||||
* Graph visibility
|
||||
* Graph - new DrawImage capability (finally)
|
||||
* Frame visibility
|
||||
* Tab visibility (may not be fully functional)
|
||||
* TabGroup visibility
|
||||
* Slider visibility
|
||||
* Slider - new disable_number_display parameter
|
||||
* Column visibilty
|
||||
* Menu visibility - Not functional
|
||||
* Table visibility
|
||||
* Table - new num_rows parm for Update - changes number of visible rows
|
||||
* Tree visiblity
|
||||
* Window - New element_padding parameter will get padding for entire window
|
||||
* OneLineProgressMeter - Completely REPLACED the implementation
|
||||
* OneLineProgressMeter - can get reason for the cancellation (cancel button versus X)
|
||||
* EasyProgressMeter - completely removed. Use OneLineProgressMeter instead
|
||||
* Debug window, EasyPrint, Print - debug window will re-open if printed to after being closed
|
||||
* SetOptions - can change the error button color
|
||||
* Much bigger window created when running PySimpleGUI.py by itself. Meant to help with regression testing
|
||||
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
||||
|
|
Loading…
Reference in New Issue