Merge pull request #902 from MikeTheWatchGuy/Dev-latest

Dev latest
This commit is contained in:
MikeTheWatchGuy 2018-12-11 14:12:22 -05:00 committed by GitHub
commit 4b476d7d19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 953 additions and 848 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -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

View File

@ -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