More demo programs updates 🤦‍♂️ wow.....I thought for sure these were checked in....

This commit is contained in:
PySimpleGUI 2022-02-16 19:51:47 -05:00
parent cfe2c96a1f
commit 430d1bc77f
15 changed files with 655 additions and 72 deletions

View File

@ -85,7 +85,8 @@ def main(location):
margins=(1,1),
element_padding=(0,0),
border_depth=0,
location=location)
location=location,
right_click_menu=[[''], ['Edit Me', 'Exit',]])
graphs = []
@ -95,12 +96,15 @@ def main(location):
window[('-TXT-', (rows, cols))],
0, colors[(rows*NUM_COLS+cols)%len(colors)])]
# ---------------- main loop ----------------
while True :
# --------- Read and update window once every Polling Frequency --------
event, values = window.read(timeout=POLL_FREQUENCY)
if event in (sg.WIN_CLOSED, 'Exit'): # Be nice and give an exit
break
elif event == 'Edit Me':
sg.execute_editor(__file__)
# read CPU for each core
stats = psutil.cpu_percent(percpu=True)

View File

@ -42,7 +42,7 @@ class Gauge():
: Return
Addition result for number1 and number2.
"""
return number1 + number1
return number1 + number2
def limit(number):
"""
@ -274,7 +274,7 @@ def main(location):
[sg.T(size=(5, 1), font='Any 20', justification='c', background_color='black', k='-gauge VALUE-')]]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True)
gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(),
minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45,
@ -293,7 +293,8 @@ def main(location):
# ----------- update the graphics and text in the window ------------
# update the window, wait for a while, then check for exit
event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS)
if event == sg.WIN_CLOSED or event == 'Exit':
if event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break
if event == 'Edit Me':
sg.execute_editor(__file__)
@ -306,5 +307,5 @@ if __name__ == '__main__':
location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1]))
else:
location = (None, None)
location = sg.user_settings_get_entry('-location-', (None, None))
main(location)

View File

@ -2,6 +2,7 @@
import PySimpleGUI as sg
import sys
import psutil
import math
"""
Desktop floating widget - CPU Cores as Gauges
@ -17,20 +18,17 @@ import psutil
Copyright 2020 PySimpleGUI
"""
GRAPH_WIDTH = 120 # each individual graph size in pixels
GRAPH_HEIGHT = 40
# gsize = (120, 75)
# gsize = (85, 40)
gsize = (55, 30)
TRANSPARENCY = .8 # how transparent the window looks. 0 = invisible, 1 = normal window
NUM_COLS = 4
POLL_FREQUENCY = 2000 # how often to update graphs in milliseconds
POLL_FREQUENCY = 1500 # how often to update graphs in milliseconds
colors = ('#23a0a0', '#56d856', '#be45be', '#5681d8', '#d34545', '#BE7C29')
import math
import random
class Gauge():
def mapping(func, sequence, *argc):
"""
@ -56,7 +54,7 @@ class Gauge():
: Return
Addition result for number1 and number2.
"""
return number1 + number1
return number1 + number2
def limit(number):
"""
@ -67,7 +65,6 @@ class Gauge():
angel degree in 0 ~ 360, return 0 if number < 0, 360 if number > 360.
"""
return max(min(360, number), 0)
class Clock():
"""
Draw background circle or arc
@ -134,7 +131,7 @@ class Gauge():
self.figure = []
self.stop_angle = angle
self.graph_elem = graph_elem
self.new(degree=angle)
self.new(degree=angle, color=pointer_color)
def new(self, degree=0, color=None):
"""
@ -224,10 +221,10 @@ class Gauge():
All angles defined as count clockwise from negative x-axis.
Should create instance of clock, pointer, minor tick and major tick first.
"""
def __init__(self, center=(0, 0), start_angle=0, stop_angle=180, major_tick_width=5, minor_tick_width=2,major_tick_start_radius=90, major_tick_stop_radius=100, major_tick_step=30, clock_radius=100, pointer_line_width=5, pointer_inner_radius=10, pointer_outer_radius=75, pointer_color='white', pointer_origin_color='black', pointer_outer_color='white', pointer_angle=0, degree=0, clock_color='white', major_tick_color='black', minor_tick_color='black', minor_tick_start_radius=90, minor_tick_stop_radius=100, graph_elem=None):
def __init__(self, center=(0, 0), start_angle=0, stop_angle=180, major_tick_width=5, minor_tick_width=2,major_tick_start_radius=90, major_tick_stop_radius=100, minor_tick_step=5, major_tick_step=30, clock_radius=100, pointer_line_width=5, pointer_inner_radius=10, pointer_outer_radius=75, pointer_color='white', pointer_origin_color='black', pointer_outer_color='white', pointer_angle=0, degree=0, clock_color='white', major_tick_color='black', minor_tick_color='black', minor_tick_start_radius=90, minor_tick_stop_radius=100, graph_elem=None):
self.clock = Gauge.Clock(start_angle=start_angle, stop_angle=stop_angle, fill_color=clock_color, radius=clock_radius, graph_elem=graph_elem)
self.minor_tick = Gauge.Tick(start_angle=start_angle, stop_angle=stop_angle, line_width=minor_tick_width, line_color=minor_tick_color, start_radius=minor_tick_start_radius, stop_radius=minor_tick_stop_radius, graph_elem=graph_elem)
self.minor_tick = Gauge.Tick(start_angle=start_angle, stop_angle=stop_angle, line_width=minor_tick_width, line_color=minor_tick_color, start_radius=minor_tick_start_radius, stop_radius=minor_tick_stop_radius, graph_elem=graph_elem, step=minor_tick_step)
self.major_tick = Gauge.Tick(start_angle=start_angle, stop_angle=stop_angle, line_width=major_tick_width, start_radius=major_tick_start_radius, stop_radius=major_tick_stop_radius, step=major_tick_step, line_color=major_tick_color, graph_elem=graph_elem)
self.pointer = Gauge.Pointer(angle=pointer_angle, inner_radius=pointer_inner_radius, outer_radius=pointer_outer_radius, pointer_color=pointer_color, outer_color=pointer_outer_color, origin_color=pointer_origin_color, line_width=pointer_line_width, graph_elem=graph_elem)
@ -250,7 +247,7 @@ class Gauge():
if self.pointer:
self.pointer.move(delta_x, delta_y)
def change(self, degree=None, step=1):
def change(self, degree=None, step=1, pointer_color=None):
"""
Rotation of pointer
call it with degree and step to set initial options for rotation.
@ -266,17 +263,17 @@ class Gauge():
new_degree = now + step
if ((step > 0 and new_degree < self.pointer.stop_degree) or
(step < 0 and new_degree > self.pointer.stop_degree)):
self.pointer.new(degree=new_degree, color='red' if new_degree > 90 else None)
self.pointer.new(degree=new_degree, color=pointer_color)
return False
else:
self.pointer.new(degree=self.pointer.stop_degree, color='red' if self.pointer.stop_degree > 90 else None)
self.pointer.new(degree=self.pointer.stop_degree, color=pointer_color)
return True
# ------------------------------ BEGINNING OF CPU WIDGET GUI CODE ------------------------------
# DashGraph does the drawing of each graph
class DashGraph(object):
def __init__(self, graph_elem, text_elem, starting_count, color):
def __init__(self, gsize, graph_elem, text_elem, starting_count, color):
self.graph_current_item = 0
self.graph_elem = graph_elem # type: sg.Graph
self.text_elem = text_elem
@ -285,26 +282,36 @@ class DashGraph(object):
self.color = color
self.line_list = [] # list of currently visible lines. Used to delete oild figures
self.gauge = Gauge(pointer_color=color, clock_color=color, major_tick_color=color,
minor_tick_color=color, pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45,
minor_tick_start_radius=45, minor_tick_stop_radius=50, major_tick_stop_radius=50, major_tick_step=30, clock_radius=50, pointer_line_width=3,
pointer_inner_radius=10, pointer_outer_radius=50, graph_elem=graph_elem)
self.gauge = Gauge(pointer_color=color,
clock_color=color,
major_tick_color=color,
minor_tick_color=color,
pointer_outer_color=color,
major_tick_start_radius=gsize[1] - 10,
minor_tick_start_radius=gsize[1] - 10,
minor_tick_stop_radius=gsize[1] - 5,
major_tick_stop_radius=gsize[1] - 5,
clock_radius=gsize[1] - 5,
pointer_outer_radius=gsize[1] - 5,
major_tick_step=30,
minor_tick_step=15,
pointer_line_width=3,
pointer_inner_radius=10,
graph_elem=graph_elem)
self.gauge.change(degree=0)
def graph_percentage_abs(self, value):
if self.gauge.change():
if self.gauge.change(pointer_color='red' if value > 50 else None):
new_angle = value*180/100
self.gauge.change(degree=new_angle, step=new_angle)
self.gauge.change()
self.gauge.change(degree=new_angle, step=100, pointer_color='red' if value > 50 else None)
self.gauge.change(pointer_color='red' if value > 50 else None)
def text_display(self, text):
self.text_elem.update(text)
def main(location):
gsize = (100, 55)
# A couple of "User defined elements" that combine several elements and enable bulk edits
def Txt(text, **kwargs):
return(sg.Text(text, font=('Helvetica 8'), **kwargs))
@ -312,7 +319,7 @@ def main(location):
def GraphColumn(name, key):
layout = [
[sg.Graph(gsize, (-gsize[0] // 2, 0), (gsize[0] // 2, gsize[1]), key=key+'-GRAPH-')],
[sg.T(size=(5, 1), justification='c', font='Courier 14', k=key+'-GAUGE VALUE-')]]
[sg.T(size=(5, 1), justification='c', font='Courier 10', k=key+'-GAUGE VALUE-')]]
return sg.Column(layout, pad=(2, 2), element_justification='c')
num_cores = len(psutil.cpu_percent(percpu=True)) # get the number of cores in the CPU
@ -320,9 +327,7 @@ def main(location):
sg.theme('black')
sg.set_options(element_padding=(0,0), margins=(1,1), border_width=0)
# the clever Red X graphic
red_x = "R0lGODlhEAAQAPeQAIsAAI0AAI4AAI8AAJIAAJUAAJQCApkAAJoAAJ4AAJkJCaAAAKYAAKcAAKcCAKcDA6cGAKgAAKsAAKsCAKwAAK0AAK8AAK4CAK8DAqUJAKULAKwLALAAALEAALIAALMAALMDALQAALUAALYAALcEALoAALsAALsCALwAAL8AALkJAL4NAL8NAKoTAKwbAbEQALMVAL0QAL0RAKsREaodHbkQELMsALg2ALk3ALs+ALE2FbgpKbA1Nbc1Nb44N8AAAMIWAMsvAMUgDMcxAKVABb9NBbVJErFYEq1iMrtoMr5kP8BKAMFLAMxKANBBANFCANJFANFEB9JKAMFcANFZANZcANpfAMJUEMZVEc5hAM5pAMluBdRsANR8AM9YOrdERMpIQs1UVMR5WNt8X8VgYMdlZcxtYtx4YNF/btp9eraNf9qXXNCCZsyLeNSLd8SSecySf82kd9qqc9uBgdyBgd+EhN6JgtSIiNuJieGHhOGLg+GKhOKamty1ste4sNO+ueenp+inp+HHrebGrefKuOPTzejWzera1O7b1vLb2/bl4vTu7fbw7ffx7vnz8f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAJAALAAAAAAQABAAAAjUACEJHEiwYEEABniQKfNFgQCDkATQwAMokEU+PQgUFDAjjR09e/LUmUNnh8aBCcCgUeRmzBkzie6EeQBAoAAMXuA8ciRGCaJHfXzUMCAQgYooWN48anTokR8dQk4sELggBhQrU9Q8evSHiJQgLCIIfMDCSZUjhbYuQkLFCRAMAiOQGGLE0CNBcZYmaRIDLqQFGF60eTRoSxc5jwjhACFWIAgMLtgUocJFy5orL0IQRHAiQgsbRZYswbEhBIiCCH6EiJAhAwQMKU5DjHCi9gnZEHMTDAgAOw=="
layout = [[ sg.Button(image_data=red_x, button_color=('black', 'black'), key='Exit', tooltip='Closes window'),
layout = [[ sg.Button(image_data=sg.red_x, button_color=('black', 'black'), key='Exit', tooltip='Closes window'),
sg.Text(' CPU Core Usage')] ]
# add on the graphs
@ -342,10 +347,12 @@ def main(location):
use_default_focus=False,
finalize=True,
location=location,
right_click_menu=[[''], 'Exit'])
right_click_menu=[[''], 'Exit'],
# transparent_color='black',
)
# setup graphs & initial values
graphs = [DashGraph(window['-CPU-'+str(i)+'-GRAPH-'],
graphs = [DashGraph(gsize, window['-CPU-'+str(i)+'-GRAPH-'],
window['-CPU-'+str(i) + '-GAUGE VALUE-'],
0, colors[i%6]) for i in range(num_cores) ]

View File

@ -4,7 +4,7 @@ import sys
"""
Another simple Desktop Widget using PySimpleGUI
This time a RAM indicator. The Widget is square.
This time a CPU Usage indicator. The Widget is square.
The bottom section will be shaded to
represent the total amount CPU currently in use.
Uses the theme's button color for colors.
@ -13,23 +13,19 @@ import sys
"""
ALPHA = 0.5
THEME = 'Dark purple 6 '
THEME = 'Dark purple 6'
GSIZE = (160, 160)
UPDATE_FREQUENCY_MILLISECONDS = 2 * 1000
def human_size(bytes, units=(' bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB')):
""" Returns a human readable string reprentation of bytes"""
return str(bytes) + ' ' + units[0] if bytes < 1024 else human_size(bytes >> 10, units[1:])
def main(location):
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True)
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-')
layout = [[graph]]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True)
text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
while True: # Event Loop
@ -45,7 +41,8 @@ def main(location):
# update the window, wait for a while, then check for exit
event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS)
if event == sg.WIN_CLOSED or event == 'Exit':
if event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break
if event == 'Edit Me':
sg.execute_editor(__file__)
@ -62,5 +59,5 @@ if __name__ == '__main__':
location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1]))
else:
location = (None, None)
location = sg.user_settings_get_entry('-location-', (None, None))
main(location)

View File

@ -24,7 +24,6 @@ g_cpu_percent = 0
g_procs = None
g_exit = False
def CPU_thread(args):
global g_interval, g_cpu_percent, g_procs, g_exit
@ -53,7 +52,7 @@ def main(location):
]
window = sg.Window('Top CPU Processes', layout,
no_titlebar=True, keep_on_top=True,location=location, use_default_focus=False, alpha_channel=.8, grab_anywhere=True)
no_titlebar=True, keep_on_top=True,location=location, use_default_focus=False, alpha_channel=.8, grab_anywhere=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
# start cpu measurement thread
thread = Thread(target=CPU_thread, args=(None,))
@ -67,9 +66,10 @@ def main(location):
# --------- Do Button Operations --------
if event in (sg.WIN_CLOSED, 'Exit'):
break
elif event == 'Edit Me':
sg.execute_editor(__file__)
timeout_value = int(values['spin']) * 1000 # for now on, use spinner for timeout
g_interval = int(values['spin'])
cpu_percent = g_cpu_percent
display_string = ''
if g_procs:

View File

@ -50,7 +50,7 @@ class Gauge():
: Return
Addition result for number1 and number2.
"""
return number1 + number1
return number1 + number2
def limit(number):
"""

View File

@ -0,0 +1,198 @@
import PySimpleGUI as sg
import sys
from datetime import datetime
from datetime import timedelta
"""
Desktop Widget - Display the date
Simple display of the date in the format of:
Day of week Day Month Year
You can change the format by modifying the function get_date_string
Copyright 2021 PySimpleGUI
"""
ALPHA = 0.9 # Initial alpha until user changes
THEME = 'Dark green 3' # Initial theme until user changes
refresh_font = title_font = 'Courier 8'
main_info_font = sg.user_settings_get_entry('-main info font-', 'Courier 60')
main_info_size = (12, 1)
UPDATE_FREQUENCY_MILLISECONDS = 1000 * 60 * 60 # update every hour by default until set by user
def choose_theme(location, size):
"""
A window to allow new themes to be tried out.
Changes the theme to the newly chosen one and returns theme's name
Automaticallyi switches to new theme and saves the setting in user settings file
:param location: (x,y) location of the Widget's window
:type location: Tuple[int, int]
:param size: Size in pixels of the Widget's window
:type size: Tuple[int, int]
:return: The name of the newly selected theme
:rtype: None | str
"""
layout = [[sg.Text('Try a theme')],
[sg.Listbox(values=sg.theme_list(), size=(20, 20), key='-LIST-', enable_events=True)],
[sg.OK(), sg.Cancel()]]
window = sg.Window('Look and Feel Browser', layout, location=location)
old_theme = sg.theme()
while True: # Event Loop
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit', 'OK', 'Cancel'):
break
sg.theme(values['-LIST-'][0])
window.hide()
# make at test window to the left of the current one
test_window = make_window(location=((location[0] - size[0] * 1.2, location[1])), test_window=True)
test_window.read(close=True)
window.un_hide()
window.close()
# after choice made, save theme or restore the old one
if event == 'OK' and values['-LIST-']:
sg.theme(values['-LIST-'][0])
sg.user_settings_set_entry('-theme-', values['-LIST-'][0])
return values['-LIST-'][0]
else:
sg.theme(old_theme)
return None
def make_window(location, test_window=False):
"""
Defines the layout and creates the window for the main window
If the parm test_window is True, then a simplified, and EASY to close version is shown
:param location: (x,y) location to create the window
:type location: Tuple[int, int]
:param test_window: If True, then this is a test window & will close by clicking on it
:type test_window: bool
:return: newly created window
:rtype: sg.Window
"""
title = sg.user_settings_get_entry('-title-', '')
if not test_window:
theme = sg.user_settings_get_entry('-theme-', THEME)
sg.theme(theme)
main_info_font = sg.user_settings_get_entry('-main info font-', 'Courier 60')
# ------------------- Window Layout -------------------
initial_text = get_date_string()
if test_window:
title_element = sg.Text('Click to close', font=title_font, enable_events=True)
right_click_menu = [[''], ['Exit', ]]
else:
title_element = sg.pin(sg.Text(title, size=(20, 1), font=title_font, justification='c', k='-TITLE-'))
right_click_menu = [[''],
['Choose Title', 'Edit Me', 'New Theme', 'Save Location', 'Font', 'Refresh', 'Set Refresh Rate', 'Show Refresh Info', 'Hide Refresh Info',
'Alpha', [str(x) for x in range(1, 11)], 'Exit', ]]
layout = [[title_element],
[sg.Text(initial_text, size=(len(initial_text)+2, 1), font=main_info_font, k='-MAIN INFO-', justification='c', enable_events=test_window)],
[sg.pin(
sg.Text(size=(15, 2), font=refresh_font, k='-REFRESHED-', justification='c', visible=sg.user_settings_get_entry('-show refresh-', True)))]]
# ------------------- Window Creation -------------------
try:
window = sg.Window('Desktop Widget Template', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=sg.user_settings_get_entry('-alpha-', ALPHA), finalize=True, right_click_menu=right_click_menu, right_click_menu_tearoff=False)
except Exception as e:
if sg.popup_yes_no('Error creating the window', e, 'Do you want to delete your settings file to fix?') == 'Yes':
sg.user_settings_delete_filename()
sg.popup('Settings file deleted. Please restart your program.')
exit()
return window
def get_date_string():
dtime_here = datetime.utcnow() + timedelta(hours=-5)
return dtime_here.strftime('%a %d %b %Y')
def main(location):
"""
Where execution begins
The Event Loop lives here, but the window creation is done in another function
This is an important design pattern
:param location: Location to create the main window if one is not found in the user settings
:type location: Tuple[int, int]
"""
window = make_window(sg.user_settings_get_entry('-location-', location))
refresh_frequency = sg.user_settings_get_entry('-fresh frequency-', UPDATE_FREQUENCY_MILLISECONDS)
while True: # Event Loop
# Normally a window.read goes here, but first we're updating the values in the window, then reading it
# First update the status information
window['-MAIN INFO-'].update(get_date_string())
# for debugging show the last update date time
if sg.user_settings_get_entry('-title-', 'None') in ('None', 'Hide'):
window['-TITLE-'].update(visible=False)
else:
window['-TITLE-'].update(sg.user_settings_get_entry('-title-', 'None'),visible=True)
window['-REFRESHED-'].update(datetime.now().strftime("%m/%d/%Y\n%I:%M:%S %p"))
# -------------- Start of normal event loop --------------
event, values = window.read(timeout=refresh_frequency)
print(event, values)
if event in (sg.WIN_CLOSED, 'Exit'): # standard exit test... ALWAYS do this
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Choose Title':
new_title = sg.popup_get_text('Choose a title for your Widget\nEnter None if you do not want anything displayed', location=window.current_location())
if new_title is not None:
if new_title in ('None', 'Hide'):
window['-TITLE-'].update(visible=False)
else:
window['-TITLE-'].update(new_title, visible=True)
sg.user_settings_set_entry('-title-', new_title)
elif event == 'Show Refresh Info':
window['-REFRESHED-'].update(visible=True)
sg.user_settings_set_entry('-show refresh-', True)
elif event == 'Save Location':
sg.user_settings_set_entry('-location-', window.current_location())
sg.popup_notify(f'Saved your current window location:', window.current_location(), title='Saved Location')
elif event == 'Hide Refresh Info':
window['-REFRESHED-'].update(visible=False)
sg.user_settings_set_entry('-show refresh-', False)
elif event in [str(x) for x in range(1, 11)]: # if Alpha Channel was chosen
window.set_alpha(int(event) / 10)
sg.user_settings_set_entry('-alpha-', int(event) / 10)
elif event == 'Set Refresh Rate':
choice = sg.popup_get_text('How frequently to update window in seconds? (can be a float)',
default_text=sg.user_settings_get_entry('-fresh frequency-', UPDATE_FREQUENCY_MILLISECONDS) / 1000,
location=window.current_location())
if choice is not None:
try:
refresh_frequency = float(choice) * 1000 # convert to milliseconds
sg.user_settings_set_entry('-fresh frequency-', float(refresh_frequency))
except Exception as e:
sg.popup_error(f'You entered an incorrect number of seconds: {choice}', f'Error: {e}', location=window.current_location())
elif event == 'New Theme':
loc = window.current_location()
if choose_theme(window.current_location(), window.size) is not None:
window.close() # out with the old...
window = make_window(loc) # in with the new
elif event == 'Font':
font = sg.popup_get_text('Enter font string using PySimpleGUI font format (e.g. courier 70 or courier 70 bold)', default_text=sg.user_settings_get_entry('-main info font-'), keep_on_top=True)
if font:
sg.user_settings_set_entry('-main info font-', font)
loc = window.current_location()
_, window = window.close(), make_window(loc)
window.close()
if __name__ == '__main__':
# To start the window at a specific location, get this location on the command line
# The location should be in form x,y with no spaces
location = (None, None) # assume no location provided
if len(sys.argv) > 1:
location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1]))
main(location)

View File

@ -19,6 +19,7 @@ import datetime
ALPHA = 0.9 # Initial alpha until user changes
THEME = 'Dark green 3' # Initial theme until user changes
sg.user_settings_filename(filename='DaysUntil.json')
refresh_font = sg.user_settings_get_entry('-refresh font-', 'Courier 8')
title_font = sg.user_settings_get_entry('-title font-', 'Courier 8')
main_number_font = sg.user_settings_get_entry('-main number font-', 'Courier 70')

View File

@ -0,0 +1,359 @@
#!/usr/bin/env python
import PySimpleGUI as sg
import psutil
import sys
import math
"""
Desktop "Rainmeter" style widget - Drive usage
Requires: psutil
Uses a "Gauge" to display drive usage
"""
ALPHA = 0.7
THEME = 'black'
UPDATE_FREQUENCY_MILLISECONDS = 20 * 1000
BAR_COLORS = ('#23a0a0', '#56d856', '#be45be', '#5681d8', '#d34545', '#BE7C29')
gsize = (50, 30)
class Gauge():
def mapping(func, sequence, *argc):
"""
Map function with extra argument, not for tuple.
: Parameters
func - function to call.
sequence - list for iteration.
argc - more arguments for func.
: Return
list of func(element of sequence, *argc)
"""
if isinstance(sequence, list):
return list(map(lambda i: func(i, *argc), sequence))
else:
return func(sequence, *argc)
def add(number1, number2):
"""
Add two number
: Parameter
number1 - number to add.
numeer2 - number to add.
: Return
Addition result for number1 and number2.
"""
return number1 + number1
def limit(number):
"""
Limit angle in range 0 ~ 360
: Parameter
number: angle degree.
: Return
angel degree in 0 ~ 360, return 0 if number < 0, 360 if number > 360.
"""
return max(min(360, number), 0)
class Clock():
"""
Draw background circle or arc
All angles defined as clockwise from negative x-axis.
"""
def __init__(self, center_x=0, center_y=0, radius=100, start_angle=0,
stop_angle=360, fill_color='white', line_color='black', line_width=2, graph_elem=None):
instance = Gauge.mapping(isinstance, [center_x, center_y, radius, start_angle,
stop_angle, line_width], (int, float)) + Gauge.mapping(isinstance,
[fill_color, line_color], str)
if False in instance:
raise ValueError
start_angle, stop_angle = Gauge.limit(start_angle), Gauge.limit(stop_angle)
self.all = [center_x, center_y, radius, start_angle, stop_angle,
fill_color, line_color, line_width]
self.figure = []
self.graph_elem = graph_elem
self.new()
def new(self):
"""
Draw Arc or circle
"""
x, y, r, start, stop, fill, line, width = self.all
start, stop = (180 - start, 180 - stop) if stop < start else (180 - stop, 180 - start)
if start == stop % 360:
self.figure.append(self.graph_elem.DrawCircle((x, y), r, fill_color=fill,
line_color=line, line_width=width))
else:
self.figure.append(self.graph_elem.DrawArc((x - r, y + r), (x + r, y - r), stop - start,
start, style='arc', arc_color=fill))
def move(self, delta_x, delta_y):
"""
Move circle or arc in clock by delta x, delta y
"""
if False in Gauge.mapping(isinstance, [delta_x, delta_y], (int, float)):
raise ValueError
self.all[0] += delta_x
self.all[1] += delta_y
for figure in self.figure:
self.graph_elem.MoveFigure(figure, delta_x, delta_y)
class Pointer():
"""
Draw pointer of clock
All angles defined as clockwise from negative x-axis.
"""
def __init__(self, center_x=0, center_y=0, angle=0, inner_radius=20,
outer_radius=80, outer_color='white', pointer_color='blue',
origin_color='black', line_width=2, graph_elem=None):
instance = Gauge.mapping(isinstance, [center_x, center_y, angle, inner_radius,
outer_radius, line_width], (int, float)) + Gauge.mapping(isinstance,
[outer_color, pointer_color, origin_color], str)
if False in instance:
raise ValueError
self.all = [center_x, center_y, angle, inner_radius, outer_radius,
outer_color, pointer_color, origin_color, line_width]
self.figure = []
self.stop_angle = angle
self.graph_elem = graph_elem
self.new(degree=angle, color=pointer_color)
def new(self, degree=0, color=None):
"""
Draw new pointer by angle, erase old pointer if exist
degree defined as clockwise from negative x-axis.
"""
(center_x, center_y, angle, inner_radius, outer_radius,
outer_color, pointer_color, origin_color, line_width) = self.all
pointer_color = color or pointer_color
if self.figure != []:
for figure in self.figure:
self.graph_elem.DeleteFigure(figure)
self.figure = []
d = degree - 90
self.all[2] = degree
dx1 = int(2 * inner_radius * math.sin(d / 180 * math.pi))
dy1 = int(2 * inner_radius * math.cos(d / 180 * math.pi))
dx2 = int(outer_radius * math.sin(d / 180 * math.pi))
dy2 = int(outer_radius * math.cos(d / 180 * math.pi))
self.figure.append(self.graph_elem.DrawLine((center_x - dx1, center_y - dy1),
(center_x + dx2, center_y + dy2),
color=pointer_color, width=line_width))
self.figure.append(self.graph_elem.DrawCircle((center_x, center_y), inner_radius,
fill_color=origin_color, line_color=outer_color, line_width=line_width))
def move(self, delta_x, delta_y):
"""
Move pointer with delta x and delta y
"""
if False in Gauge.mapping(isinstance, [delta_x, delta_y], (int, float)):
raise ValueError
self.all[:2] = [self.all[0] + delta_x, self.all[1] + delta_y]
for figure in self.figure:
self.graph_elem.MoveFigure(figure, delta_x, delta_y)
class Tick():
"""
Create tick on click for minor tick, also for major tick
All angles defined as clockwise from negative x-axis.
"""
def __init__(self, center_x=0, center_y=0, start_radius=90, stop_radius=100,
start_angle=0, stop_angle=360, step=6, line_color='black', line_width=2, graph_elem=None):
instance = Gauge.mapping(isinstance, [center_x, center_y, start_radius,
stop_radius, start_angle, stop_angle, step, line_width],
(int, float)) + [Gauge.mapping(isinstance, line_color, (list, str))]
if False in instance:
raise ValueError
start_angle, stop_angle = Gauge.limit(start_angle), Gauge.limit(stop_angle)
self.all = [center_x, center_y, start_radius, stop_radius,
start_angle, stop_angle, step, line_color, line_width]
self.figure = []
self.graph_elem = graph_elem
self.new()
def new(self):
"""
Draw ticks on clock
"""
(x, y, start_radius, stop_radius, start_angle, stop_angle, step,
line_color, line_width) = self.all
start_angle, stop_angle = (180 - start_angle, 180 - stop_angle
) if stop_angle < start_angle else (180 - stop_angle, 180 - start_angle)
for i in range(start_angle, stop_angle + 1, step):
start_x = x + start_radius * math.cos(i / 180 * math.pi)
start_y = y + start_radius * math.sin(i / 180 * math.pi)
stop_x = x + stop_radius * math.cos(i / 180 * math.pi)
stop_y = y + stop_radius * math.sin(i / 180 * math.pi)
self.figure.append(self.graph_elem.DrawLine((start_x, start_y),
(stop_x, stop_y), color=line_color, width=line_width))
def move(self, delta_x, delta_y):
"""
Move ticks by delta x and delta y
"""
if False in Gauge.mapping(isinstance, [delta_x, delta_y], (int, float)):
raise ValueError
self.all[0] += delta_x
self.all[1] += delta_y
for figure in self.figure:
self.graph_elem.MoveFigure(figure, delta_x, delta_y)
"""
Create Gauge
All angles defined as count clockwise from negative x-axis.
Should create instance of clock, pointer, minor tick and major tick first.
"""
def __init__(self, center=(0, 0), start_angle=0, stop_angle=180, major_tick_width=5, minor_tick_width=2,major_tick_start_radius=90, major_tick_stop_radius=100, minor_tick_step=5, major_tick_step=30, clock_radius=100, pointer_line_width=5, pointer_inner_radius=10, pointer_outer_radius=75, pointer_color='white', pointer_origin_color='black', pointer_outer_color='white', pointer_angle=0, degree=0, clock_color='white', major_tick_color='black', minor_tick_color='black', minor_tick_start_radius=90, minor_tick_stop_radius=100, graph_elem=None):
self.clock = Gauge.Clock(start_angle=start_angle, stop_angle=stop_angle, fill_color=clock_color, radius=clock_radius, graph_elem=graph_elem)
self.minor_tick = Gauge.Tick(start_angle=start_angle, stop_angle=stop_angle, line_width=minor_tick_width, line_color=minor_tick_color, start_radius=minor_tick_start_radius, stop_radius=minor_tick_stop_radius, graph_elem=graph_elem, step=minor_tick_step)
self.major_tick = Gauge.Tick(start_angle=start_angle, stop_angle=stop_angle, line_width=major_tick_width, start_radius=major_tick_start_radius, stop_radius=major_tick_stop_radius, step=major_tick_step, line_color=major_tick_color, graph_elem=graph_elem)
self.pointer = Gauge.Pointer(angle=pointer_angle, inner_radius=pointer_inner_radius, outer_radius=pointer_outer_radius, pointer_color=pointer_color, outer_color=pointer_outer_color, origin_color=pointer_origin_color, line_width=pointer_line_width, graph_elem=graph_elem)
self.center_x, self.center_y = self.center = center
self.degree = degree
self.dx = self.dy = 1
def move(self, delta_x, delta_y):
"""
Move gauge to move all componenets in gauge.
"""
self.center_x, self.center_y =self.center = (
self.center_x+delta_x, self.center_y+delta_y)
if self.clock:
self.clock.move(delta_x, delta_y)
if self.minor_tick:
self.minor_tick.move(delta_x, delta_y)
if self.major_tick:
self.major_tick.move(delta_x, delta_y)
if self.pointer:
self.pointer.move(delta_x, delta_y)
def change(self, degree=None, step=1, pointer_color=None):
"""
Rotation of pointer
call it with degree and step to set initial options for rotation.
Without any option to start rotation.
"""
if self.pointer:
if degree != None:
self.pointer.stop_degree = degree
self.pointer.step = step if self.pointer.all[2] < degree else -step
return True
now = self.pointer.all[2]
step = self.pointer.step
new_degree = now + step
if ((step > 0 and new_degree < self.pointer.stop_degree) or
(step < 0 and new_degree > self.pointer.stop_degree)):
self.pointer.new(degree=new_degree, color=pointer_color)
return False
else:
self.pointer.new(degree=self.pointer.stop_degree, color=pointer_color)
return True
def human_size(bytes, units=(' bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB')):
""" Returns a human readable string reprentation of bytes"""
return str(bytes) + ' ' + units[0] if bytes < 1024 else human_size(bytes >> 10, units[1:])
def update_window(window):
particians = psutil.disk_partitions()
for count, part in enumerate(particians):
mount = part[0]
try:
usage = psutil.disk_usage(mount)
window[('-NAME-', mount)].update(mount)
# window[('-PROG-', mount)].update_bar(int(usage.percent))
window[('-%-', mount)].update(f'{usage.percent}%')
window[('-STATS-', mount)].update(f'{human_size(usage.used)} / {human_size(usage.total)} = {human_size(usage.free)} free')
gauge = Gauge(pointer_color=window[('-GRAPH-', mount)].metadata,
clock_color=window[('-GRAPH-', mount)].metadata,
major_tick_color=sg.theme_input_background_color(),
minor_tick_color=sg.theme_input_text_color(),
pointer_outer_color=sg.theme_input_background_color(),
major_tick_start_radius=gsize[1] - 10,
minor_tick_start_radius=gsize[1] - 10,
minor_tick_stop_radius=gsize[1] - 5,
major_tick_stop_radius=gsize[1] - 5,
clock_radius=gsize[1] - 5,
pointer_outer_radius=gsize[1] - 5,
major_tick_step=30,
minor_tick_step=15,
pointer_line_width=3,
pointer_inner_radius=10,
graph_elem=window[('-GRAPH-', mount)])
gauge.change(degree=0)
gauge.change(degree=180 * usage.percent / 100, step=180)
gauge.change()
except KeyError as e: # A key error means a new drive was added
print('Got a key error, so a new drive was added. Window will restart')
return False
except BaseException as e:
print(e)
return True
def create_window(location):
layout = [[sg.Text('Drive Status', font='Any 16')]]
# Add a row for every partician that has a bar graph and text stats
particians = psutil.disk_partitions()
for count, part in enumerate(particians):
mount = part[0]
try:
bar_color = sg.theme_progress_bar_color()
this_color = BAR_COLORS[count % len(BAR_COLORS)]
usage = psutil.disk_usage(mount)
stats_info = f'{human_size(usage.used)} / {human_size(usage.total)} = {human_size(usage.free)} free'
layout += [[sg.Text(mount, size=(3, 1), key=('-NAME-', mount)),
sg.Graph(gsize, (-gsize[0] // 2, 0), (gsize[0] // 2, gsize[1]), key=('-GRAPH-', mount), metadata=this_color),
# sg.ProgressBar(100, 'h', size=(10, 15), key=('-PROG-', mount), bar_color=(this_color, bar_color[1])),
sg.Text(f'{usage.percent}%', size=(6, 1), key=('-%-', mount)), sg.T(stats_info, size=(30, 1), key=('-STATS-', mount)),
]]
except:
pass
layout += [[sg.Text('Refresh', font='Any 8', key='-REFRESH-', enable_events=True), sg.Text('', enable_events=True, key='Exit Text')]]
# ---------------- Create Window ----------------
window = sg.Window('Drive Status Widget', layout, location=location, keep_on_top=True, grab_anywhere=True, no_titlebar=True, alpha_channel=ALPHA, use_default_focus=False,
finalize=True)
return window
def main(location):
# Turn off the popups because key errors are normal in this program.
# Will get a key error is a new drive is added. Want to get the key error as an exception.
sg.set_options(suppress_error_popups=True, suppress_raise_key_errors=False, suppress_key_guessing=True)
sg.theme(THEME)
window = create_window(location)
update_window(window) # sets the progress bars
# ---------------- Event Loop ----------------
while True:
event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS)
if event == sg.WIN_CLOSED or event.startswith('Exit'):
break
if not update_window(window):
window.close()
window = create_window(location)
update_window(window)
if __name__ == '__main__':
if len(sys.argv) > 1:
location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1]))
else:
location = (None, None)
main(location)

View File

@ -150,6 +150,8 @@ def main():
while True:
event, values = window.read(timeout=1000*60*60) # wake every hour
if event == sg.WIN_CLOSED or event == 'Exit':
if event == 'Exit':
sg.user_settings_set_entry('-location-', window.current_location())
break
if event == 'Add Package':
window.metadata += 1

View File

@ -121,7 +121,7 @@ def main():
if new_count is not None:
counter = int(new_count)
elif event == 'Choose Title':
new_title = sg.popup_get_text('Choose a title for your counter', default_text=sg.user_settings_get_entry('-title-', ''), location=window.current_location(), keep_on_top=True)
new_title = sg.popup_get_text('Choose a title for your counter', default_text=sg.user_settings_get_entry('-title-', ''), location=window.current_location(), )
if new_title is not None:
window['-TITLE-'].update(new_title)
sg.user_settings_set_entry('-title-', new_title)
@ -134,7 +134,7 @@ def main():
# this is result of hacking code down to 99 lines in total. Not tried it before. Interesting test.
_, window = window.close(), make_window(loc)
elif event == 'Set Main Font':
font = sg.popup_get_text('Main Information Font and Size (e.g. courier 70)', default_text=sg.user_settings_get_entry('-main number font-'), keep_on_top=True, location=window.current_location())
font = sg.popup_get_text('Main Information Font and Size (e.g. courier 70)', default_text=sg.user_settings_get_entry('-main number font-'), keep_on_top=False, location=window.current_location())
if font:
sg.user_settings_set_entry('-main number font-', font)
_, window = window.close(), make_window(loc)
@ -164,7 +164,7 @@ def main():
if sound_file is not None:
sg.user_settings_set_entry('-sound file-', sound_file)
elif event =='Show Settings':
sg.Print(sg.UserSettings._default_for_function_interface)
sg.popup_scrolled(sg.UserSettings._default_for_function_interface, location=window.current_location())
sg.user_settings_set_entry('-counter-', counter)
@ -172,4 +172,5 @@ def main():
if __name__ == '__main__':
sg.set_options(keep_on_top=True)
main()

View File

@ -51,7 +51,7 @@ class Gauge():
: Return
Addition result for number1 and number2.
"""
return number1 + number1
return number1 + number2
def limit(number):
"""

View File

@ -30,7 +30,7 @@ def main(location):
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True)
layout = [[graph]]
window = sg.Window('RAM Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
window = sg.Window('RAM Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True)
while True: # Event Loop
@ -43,7 +43,9 @@ def main(location):
text_id2 = graph.draw_text(f'{human_size(ram.used)} used', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS)
if event == sg.WIN_CLOSED or event == 'Exit':
if event in (sg.WIN_CLOSED, 'Exit', sg.WIN_CLOSE_ATTEMPTED_EVENT):
if event != sg.WIN_CLOSED:
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break
elif event == 'Edit Me':
sg.execute_editor(__file__)
@ -59,5 +61,5 @@ if __name__ == '__main__':
location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1]))
else:
location = (None, None)
location = sg.user_settings_get_entry('-location-', (None, None))
main(location)

View File

@ -208,11 +208,12 @@ def create_window(win_location):
layout = [[top_col],
[lf_col, rt_col],
[bot_col]]
[bot_col],
[sg.Text(f'{sg.ver} {sg.framework_version} {sys.version}', font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, pad=(0,0))]]
window = sg.Window(layout=layout, title='Weather Widget', margins=(0, 0), finalize=True, location=win_location,
element_justification='center', keep_on_top=True, no_titlebar=True, grab_anywhere=True, alpha_channel=ALPHA,
right_click_menu=[[''], 'Exit'])
right_click_menu=[[''], ['Edit Me', 'Versions', 'Exit',]], enable_close_attempted_event=True)
for col in ['COL1', 'COL2', 'TopCOL', 'BotCOL', '-QUIT-']:
window[col].expand(expand_y=True, expand_x=True)
@ -261,14 +262,19 @@ def main(refresh_rate, win_location):
while True: # Event Loop
event, values = window.read(timeout=refresh_in_milliseconds)
if event in (None, '-QUIT-', 'Exit'):
if event in (None, '-QUIT-', 'Exit', sg.WIN_CLOSE_ATTEMPTED_EVENT):
sg.user_settings_set_entry('-win location-', window.current_location()) # The line of code to save the position before exiting
break
if event == '-CHANGE-':
x, y = window.current_location()
settings = change_settings(settings, (x + 200, y+50))
elif event == '-REFRESH-':
sg.popup_quick_message('Refreshing...', keep_on_top=True, background_color='red', text_color='white',
auto_close_duration=3, non_blocking=False, location=(win_location[0]+170, win_location[1]+150))
auto_close_duration=3, non_blocking=False, location=(window.current_location()[0]+window.size[0]//2-30, window.current_location()[1]+window.size[1]//2-10))
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Versions':
sg.main_get_debug_data()
elif event != sg.TIMEOUT_KEY:
sg.Print('Unknown event received\nEvent & values:\n', event, values, location=win_location)
@ -282,5 +288,6 @@ if __name__ == '__main__':
win_location = sys.argv[1].split(',')
win_location = (int(win_location[0]), int(win_location[1]))
else:
win_location = (None, None)
win_location = sg.user_settings_get_entry('-win location-', (None, None))
main(refresh_rate=1, win_location=win_location)

View File

@ -25,34 +25,38 @@ import PySimpleGUI as sg
"""
# ------------------- The Old Way -------------------
import PySimpleGUI as sg
layout = [[sg.Text('My Window')],
[sg.InputText(size=(50, 1), key='-FILENAME-'), sg.FileBrowse()],
[sg.Button('Go'), sg.Button('Exit')]]
event1, values1 = sg.Window('Window Title', layout).read(close=True)
event1, values1 = sg.Window('Normal Filename', layout).read(close=True)
# ------------------- The New Way with history -------------------
import PySimpleGUI as sg
layout = [[sg.Text('My Window')],
[sg.Combo(sg.user_settings_get_entry('-filenames-', []), default_value=sg.user_settings_get_entry('-last filename-', ''), size=(50, 1), key='-FILENAME-'),
sg.FileBrowse()],
[sg.Button('Go'), sg.Button('Exit')]]
event, values = sg.Window('Window Title', layout).read(close=True)
event, values = sg.Window('Filename with History', layout).read(close=True)
if event == 'Go':
sg.user_settings_set_entry('-filenames-', list(set(sg.user_settings_get_entry('-filenames-', []) + [values['-FILENAME-'], ])))
sg.user_settings_set_entry('-last filename-', values['-FILENAME-'])
# ------------------- The New Way with history and clear -------------------
import PySimpleGUI as sg
layout = [[sg.Text('My Window')],
[sg.Combo(sg.user_settings_get_entry('-filenames-', []), default_value=sg.user_settings_get_entry('-last filename-', ''), size=(50, 1), key='-FILENAME-'),
sg.FileBrowse()],
[sg.Button('Go'), sg.B('Clear'), sg.Button('Exit')]]
window = sg.Window('Window Title', layout)
window = sg.Window('Filename History Clearable', layout)
while True:
event, values = window.read()