From a2443c63ad97e73fe2fd916ce34965368183782e Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 30 Oct 2019 14:35:01 -0400 Subject: [PATCH] Fixed flicker problem!!! Updated all of the PySimpleGUIWeb demos --- .../Demo_Graph_pymunk_2D_Graphics.py | 33 +++-- .../Demo Programs/Web_Color_Names.py | 39 +++--- .../Web_Color_Names_Smaller_List.py | 21 +-- .../Demo Programs/Web_Demo_Font_Sizer.py | 31 +++-- .../Demo Programs/Web_Demo_HowDoI.py | 74 +++++----- .../Web_Desktop_Widget_CPU_Utilization.py | 51 +++---- PySimpleGUIWeb/Demo Programs/Web_Popup.py | 13 +- PySimpleGUIWeb/Demo Programs/Web_Simple.py | 26 ++-- .../Demo Programs/Web_Table_Element.py | 61 +++------ PySimpleGUIWeb/Demo Programs/Web_Timer.py | 43 +++--- .../Demo Programs/Web_Widget_Summary.py | 63 +++++---- .../Web_psutil_Kill_Processes.py | 64 +++++---- .../Demo Programs/widgets_overview_app.py | 128 +++++++++++------- PySimpleGUIWeb/PySimpleGUIWeb.py | 64 +++++++++ 14 files changed, 413 insertions(+), 298 deletions(-) diff --git a/PySimpleGUIWeb/Demo Programs/Demo_Graph_pymunk_2D_Graphics.py b/PySimpleGUIWeb/Demo Programs/Demo_Graph_pymunk_2D_Graphics.py index a62d6303..65d8faed 100644 --- a/PySimpleGUIWeb/Demo Programs/Demo_Graph_pymunk_2D_Graphics.py +++ b/PySimpleGUIWeb/Demo Programs/Demo_Graph_pymunk_2D_Graphics.py @@ -1,5 +1,4 @@ -# import PySimpleGUIWeb as sg -import PySimpleGUI as sg +import PySimpleGUIWeb as sg import pymunk import random import socket @@ -10,17 +9,20 @@ import socket Note this exact same demo runs with PySimpleGUIWeb by changing the import statement """ + class Ball(): def __init__(self, x, y, r, *args, **kwargs): mass = 10 self.body = pymunk.Body(mass, pymunk.moment_for_circle(mass, 0, r, (0, 0))) # Create a Body with mass and moment self.body.position = x, y - self.shape = pymunk.Circle(self.body, r, offset=(0, 0)) # Create a box shape and attach to body + # Create a box shape and attach to body + self.shape = pymunk.Circle(self.body, r, offset=(0, 0)) self.shape.elasticity = 0.99999 self.shape.friction = 0.8 self.gui_circle_figure = None + class Playfield(): def __init__(self): self.space = pymunk.Space() @@ -30,7 +32,7 @@ class Playfield(): self.add_wall(self.space, (600, 0), (600, 400)) # right side def add_wall(self, space, pt_from, pt_to): - body = pymunk.Body(body_type=pymunk.Body.STATIC) + body = pymunk.Body(body_type=pymunk.Body.STATIC) ground_shape = pymunk.Segment(body, pt_from, pt_to, 0.0) ground_shape.friction = 0.8 ground_shape.elasticity = .99 @@ -45,24 +47,25 @@ class Playfield(): ball = Ball(x, y, r) self.arena_balls.append(ball) area.space.add(ball.body, ball.shape) - ball.gui_circle_figure = graph_elem.DrawCircle((x, y), r, fill_color='black', line_color='red') + ball.gui_circle_figure = graph_elem.draw_circle( + (x, y), r, fill_color='black', line_color='red') # ------------------- Build and show the GUI Window ------------------- -graph_elem = sg.Graph((600, 400), (0, 400), (600, 0), enable_events=True, key='_GRAPH_', background_color='lightblue') +graph_elem = sg.Graph((600, 400), (0, 400), (600, 0), + enable_events=True, key='_GRAPH_', background_color='lightblue') -layout = [[sg.Text('Ball Test'), sg.T('My IP {}'.format(socket.gethostbyname(socket.gethostname())))], +layout = [[sg.Text('Ball Test'), sg.Text('My IP {}'.format(socket.gethostbyname(socket.gethostname())))], [graph_elem], - [sg.B('Kick'), sg.Button('Exit')]] - -window = sg.Window('Window Title', layout, ).Finalize() + [sg.Button('Kick'), sg.Button('Exit')]] +window = sg.Window('Window Title', layout, finalize=True) area = Playfield() area.add_balls() # ------------------- GUI Event Loop ------------------- while True: # Event Loop - event, values = window.Read(timeout=0) + event, values = window.read(timeout=0) # print(event, values) if event in (None, 'Exit'): break @@ -70,7 +73,9 @@ while True: # Event Loop for ball in area.arena_balls: if event == 'Kick': - ball.body.position = ball.body.position[0], ball.body.position[1]-random.randint(1,200) - graph_elem.RelocateFigure(ball.gui_circle_figure, ball.body.position[0], ball.body.position[1]) + ball.body.position = ball.body.position[0], ball.body.position[1]-random.randint( + 1, 200) + graph_elem.relocate_figure( + ball.gui_circle_figure, ball.body.position[0], ball.body.position[1]) -window.Close() +window.close() diff --git a/PySimpleGUIWeb/Demo Programs/Web_Color_Names.py b/PySimpleGUIWeb/Demo Programs/Web_Color_Names.py index 8b8d41c0..7bdb82d3 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Color_Names.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Color_Names.py @@ -1,7 +1,5 @@ #!/usr/bin/env python import PySimpleGUIWeb as sg -# import PySimpleGUI as sg - """ @@ -669,25 +667,26 @@ color_map = { def detailed_view(window): - layout2 = [[sg.Button(event, button_color=('white', color_map[event]), key=event, tooltip=color_map[color]), - sg.Button(event, button_color=('black', color_map[event]), key=event+'1', tooltip=color_map[color])], - [sg.Txt('Hover over button to see color value. Click to clocse and return to main interface.')], ] - sg.Window('Buttons with white and black text', layout2, keep_on_top=True).Read() - window.Close() + layout2 = [[sg.Button(event, button_color=('white', color_map[event]), + key=event, tooltip=color_map[color]), + sg.Button(event, button_color=('black', color_map[event]), + key=event+'1', tooltip=color_map[color])], + [sg.Text('Hover over button to see color value. Click to clocse and return to main interface.')], ] + sg.Window('Buttons with white and black text', + layout2, keep_on_top=True).Read() + window.close() return -sg.SetOptions(button_element_size=(16,1), auto_size_buttons=False, border_width=0, tooltip_time=100) +sg.set_options(button_element_size=(16, 1), + auto_size_buttons=False, border_width=0, tooltip_time=100) -#start layout with the tittle +# start layout with the tittle layout = [[sg.Text('Hover mouse to see RGB value. Click to see Button with White or Black text.', - text_color='blue', - font=('Hevletica', 20), - relief=sg.RELIEF_SUNKEN, - justification='center', - size=(90,2), - background_color='#90EE90', - pad=(0,0)),]] + text_color='blue', background_color='#90EE90', + font=('Hevletica', 20), + relief=sg.RELIEF_SUNKEN, justification='center', + size=(90, 2), pad=(0, 0))]] # -- Create primary color viewer window by building rows and appending to layout -- color_list = [key for key in color_map] @@ -696,14 +695,16 @@ for rows in range(40): for i in range(12): try: color = color_list[rows+40*i] - row.append(sg.Button(color, button_color=('black', color_map[color]), key=color, tooltip=color_map[color]),) + row.append(sg.Button(color, + button_color=('black', color_map[color]), key=color, tooltip=color_map[color]),) except: pass layout.append(row) while True: - window = sg.Window('Color Viewer', layout, font=('any 12'), default_button_element_size=(12,1), element_padding=(0,0)) - event, values = window.Read() + window = sg.Window('Color Viewer', layout, font=('any 12'), + default_button_element_size=(12, 1), element_padding=(0, 0)) + event, values = window.read() if event is None: break detailed_view(window) diff --git a/PySimpleGUIWeb/Demo Programs/Web_Color_Names_Smaller_List.py b/PySimpleGUIWeb/Demo Programs/Web_Color_Names_Smaller_List.py index 3109c450..51f9f3d2 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Color_Names_Smaller_List.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Color_Names_Smaller_List.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -import sys import PySimpleGUIWeb as sg """ @@ -12,7 +11,6 @@ import PySimpleGUIWeb as sg """ - 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', @@ -91,11 +89,11 @@ COLORS = ['snow', 'ghost white', 'white smoke', 'gainsboro', 'floral white', 'ol 'grey93', 'grey94', 'grey95', 'grey97', 'grey98', 'grey99'] +sg.set_options(button_element_size=(12, 1), + element_padding=(0, 0), auto_size_buttons=False, border_width=0) - -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')]] +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 -- @@ -117,13 +115,16 @@ for rows in range(40): # layout.append(row) # row = [] -window = sg.Window('Color Viewer', grab_anywhere=False, font=('any 9')).Layout(layout) +window = sg.Window('Color Viewer', layout, + grab_anywhere=False, font=('any 9')) # -- Event loop -- while True: - event, values = window.Read() + event, values = window.read() if event is None: break # -- Create a secondary window that shows white and black text on chosen color - layout2 =[[sg.DummyButton(event, button_color=('white', event)), sg.DummyButton(event, button_color=('black', event))]] - sg.Window('Buttons with white and black text', keep_on_top=True).Layout(layout2).Read(timeout=0) \ No newline at end of file + layout2 = [[sg.DummyButton(event, button_color=('white', event)), + sg.DummyButton(event, button_color=('black', event))]] + sg.Window('Buttons with white and black text', + layout2, keep_on_top=True).read(timeout=0) diff --git a/PySimpleGUIWeb/Demo Programs/Web_Demo_Font_Sizer.py b/PySimpleGUIWeb/Demo Programs/Web_Demo_Font_Sizer.py index 26d4d88d..c07a9b71 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Demo_Font_Sizer.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Demo_Font_Sizer.py @@ -9,21 +9,30 @@ In other words, the slider and the spinner are essentially connected together fontsize = 12 # initial and smallest font size to show -layout = [[sg.Spin([sz for sz in range(6, 172)], size=(6,1), font=('Helvetica 20'), initial_value=fontsize, change_submits=True, key='spin'), - sg.Slider(range=(6,172), orientation='h', size=(10,20), change_submits=True, key='slider', font=('Helvetica 20')), - sg.Text("Aa", size=(2, 1), font="Helvetica " + str(fontsize), key='text')],] +layout = [ + [sg.Spin([sz for sz in range(6, 172)], size=(6, 1), + font=('Helvetica 20'), initial_value=fontsize, + change_submits=True, key='spin'), + sg.Slider(range=(6, 172), orientation='h', size=(10, 20), + change_submits=True, key='slider', font=('Helvetica 20')), + sg.Text("Aa", size=(2, 1), font="Helvetica " + str(fontsize), key='text')] + ] -window = sg.Window("Font size selector").Layout(layout) +window = sg.Window("Font size selector", layout) while True: # the event loop - event, values= window.Read() + event, values = window.read() if event is None or event == 'Quit': break - fontsize = int(values['spin']) if int(values['spin']) != fontsize else int(values['slider']) - font = "Helvetica " + str(fontsize) - window.FindElement('text').Update(font=font) - window.FindElement('slider').Update(fontsize, range=(10,20)) - window.FindElement('spin').Update(fontsize) -window.Close() + + if int(values['spin']) != fontsize: + fontsize = int(values['spin']) + else: + fontsize = int(values['slider']) + + window['text'].update(font="Helvetica " + str(fontsize)) + window['slider'].update(fontsize, range=(10, 20)) + window['spin'].update(fontsize) +window.close() print("Done.") diff --git a/PySimpleGUIWeb/Demo Programs/Web_Demo_HowDoI.py b/PySimpleGUIWeb/Demo Programs/Web_Demo_HowDoI.py index 0fc0a0f0..e8f80ec0 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Demo_HowDoI.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Demo_HowDoI.py @@ -1,16 +1,11 @@ #!/usr/bin/env python -import sys import PySimpleGUIWeb as sg import subprocess import howdoi - # Test this command in a dos window if you are having trouble. HOW_DO_I_COMMAND = 'python -m howdoi.howdoi' -# if you want an icon on your taskbar for this gui, then change this line of code to point to the ICO file -DEFAULT_ICON = 'E:\\TheRealMyDocs\\Icons\\QuestionMark.ico' - def HowDoI(): ''' Make and show a window (PySimpleGUI form) that takes user input and sends to the HowDoI web oracle @@ -20,52 +15,69 @@ def HowDoI(): :return: never returns ''' # ------- Make a new Window ------- # - sg.ChangeLookAndFeel('GreenTan') # give our form a spiffy set of colors + sg.change_look_and_feel('GreenTan') # give our form a spiffy set of colors layout = [ [sg.Text('Ask and your answer will appear here....', size=(40, 1))], - [sg.MultilineOutput(size_px=(980, 400),key='_OUTPUT_' )], + [sg.MLineOutput(size_px=(980, 400),key='_OUTPUT_' )], # [ sg.Spin(values=(1, 2, 3, 4), initial_value=1, size=(2, 1), key='Num Answers', font='Helvetica 15'), - [ sg.Checkbox('Display Full Text', key='full text', font='Helvetica 15'), - sg.T('Command History', font='Helvetica 15'), sg.T('', size=(40,3), text_color=sg.BLUES[0], key='history')], - [sg.Multiline(size=(85, 5), enter_submits=True, key='query', do_not_clear=False), + [ sg.CBox('Display Full Text', key='full text', font='Helvetica 15'), + sg.Text('Command History', font='Helvetica 15'), sg.Text('', size=(40,3), text_color=sg.BLUES[0], key='history')], + [sg.MLine(size=(85, 5), enter_submits=True, key='query', do_not_clear=False), sg.ReadButton('SEND', button_color=(sg.YELLOWS[0], sg.BLUES[0]), bind_return_key=True), sg.Button('EXIT', button_color=(sg.YELLOWS[0], sg.GREENS[0]))] ] - window = sg.Window('How Do I ??', default_element_size=(30,1), icon=DEFAULT_ICON, font=('Helvetica',' 17'), default_button_element_size=(8,2), return_keyboard_events=False, ) - window.Layout(layout) + window = sg.Window('How Do I?', layout, default_element_size=(30,1), + font=('Helvetica',' 17'), default_button_element_size=(8,2), + return_keyboard_events=False) + # ---===--- Loop taking in user input and using it to query HowDoI --- # command_history = [] history_offset = 0 while True: + event, values = window.Read() # print(event, values) if type(event) is int: event = str(event) if event == 'SEND': query = values['query'].rstrip() - window.Element('_OUTPUT_').Update(query, append=True) + window['_OUTPUT_'].update(query, append=True) print(query) QueryHowDoI(query, 1, values['full text'], window) # send the string to HowDoI command_history.append(query) history_offset = len(command_history)-1 - window.FindElement('query').Update('') # manually clear input because keyboard events blocks clear - window.FindElement('history').Update('\n'.join(command_history[-3:])) - elif event == None or event == 'EXIT': # if exit button or closed using X - break - elif 'Up' in event and len(command_history): # scroll back in history - command = command_history[history_offset] - history_offset -= 1 * (history_offset > 0) # decrement is not zero - window.FindElement('query').Update(command) - elif 'Down' in event and len(command_history): # scroll forward in history - history_offset += 1 * (history_offset < len(command_history)-1) # increment up to end of list - command = command_history[history_offset] - window.FindElement('query').Update(command) - elif 'Escape' in event: # clear currently line - window.FindElement('query').Update('') - window.Close() + # manually clear input because keyboard events blocks clear + window['query'].update('') + window['history'].update('\n'.join(command_history[-3:])) + + # if exit button or closed using X + elif event == None or event == 'EXIT': + break + + # scroll back in history + elif 'Up' in event and len(command_history): + command = command_history[history_offset] + + # decrement is not zero + history_offset -= 1 * (history_offset > 0) + window['query'].update(command) + + # scroll forward in history + elif 'Down' in event and len(command_history): + + # increment up to end of list + history_offset += 1 * (history_offset < len(command_history)-1) + command = command_history[history_offset] + window['query'].update(command) + + # clear currently line + elif 'Escape' in event: + window['query'].update('') + + window.close() def QueryHowDoI(Query, num_answers, full_text, window:sg.Window): ''' @@ -78,9 +90,9 @@ def QueryHowDoI(Query, num_answers, full_text, window:sg.Window): full_text_option = ' -a' if full_text else '' t = subprocess.Popen(howdoi_command + ' \"'+ Query + '\" -n ' + str(num_answers)+full_text_option, stdout=subprocess.PIPE) (output, err) = t.communicate() - window.Element('_OUTPUT_').Update('{:^88}'.format(Query.rstrip()), append=True) - window.Element('_OUTPUT_').Update('_'*60, append=True) - window.Element('_OUTPUT_').Update(output.decode("utf-8"), append=True) + window['_OUTPUT_'].update('{:^88}'.format(Query.rstrip()), append=True) + window['_OUTPUT_'].update('_'*60, append=True) + window['_OUTPUT_'].update(output.decode("utf-8"), append=True) exit_code = t.wait() if __name__ == '__main__': diff --git a/PySimpleGUIWeb/Demo Programs/Web_Desktop_Widget_CPU_Utilization.py b/PySimpleGUIWeb/Demo Programs/Web_Desktop_Widget_CPU_Utilization.py index 659b3af2..b77fd451 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Desktop_Widget_CPU_Utilization.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Desktop_Widget_CPU_Utilization.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -import sys -import sys import PySimpleGUIWeb as sg import psutil import time @@ -26,6 +24,7 @@ g_cpu_percent = 0 g_procs = None g_exit = False + def CPU_thread(args): global g_interval, g_cpu_percent, g_procs, g_exit @@ -41,30 +40,30 @@ def main(): global g_interval, g_procs, g_exit # ---------------- Create Form ---------------- - sg.ChangeLookAndFeel('Black') - layout = [[sg.Text('', size=(8,1), font=('Helvetica', 20),text_color=sg.YELLOWS[0], - justification='center', key='text')], - [sg.Text('', size=(30, 8), font=('Courier New', 12),text_color='white', justification='left', key='processes')], - [sg.Exit(button_color=('white', 'firebrick4'), pad=((15,0), 0), size=(9,1)),] - ] + sg.change_look_and_feel('Black') + layout = [[sg.Text('', size=(8, 1), font=('Helvetica', 20), text_color=sg.YELLOWS[0], + justification='center', key='text')], + [sg.Text('', size=(30, 8), font=('Courier New', 12), + text_color='white', justification='left', key='processes')], + [sg.Exit(button_color=('white', 'firebrick4'), + pad=((15, 0), 0), size=(9, 1)), ] + ] - window = sg.Window('CPU Utilization', - no_titlebar=True, - keep_on_top=True, - alpha_channel=.8, - grab_anywhere=True).Layout(layout) + window = sg.Window('CPU Utilization', layout, + no_titlebar=True, keep_on_top=True, alpha_channel=.8, grab_anywhere=True) # start cpu measurement thread - thread = Thread(target=CPU_thread,args=(None,), daemon=True) + thread = Thread(target=CPU_thread, args=(None,), daemon=True) thread.start() timeout_value = 1 # make first read really quick g_interval = 1 # ---------------- main loop ---------------- - while (True): + while True: # --------- Read and update window -------- - event, values = window.Read(timeout=timeout_value, timeout_key='Timeout') + event, values = window.read( + timeout=timeout_value, timeout_key='Timeout') # --------- Do Button Operations -------- - if event is None or event == 'Exit': + if event in (None, 'Exit'): break timeout_value = 1000 @@ -74,11 +73,12 @@ def main(): if g_procs: # --------- Create list of top % CPU porocesses -------- try: - top = {proc.name() : proc.cpu_percent() for proc in g_procs} - except: pass + top = {proc.name(): proc.cpu_percent() for proc in g_procs} + except: + pass - - top_sorted = sorted(top.items(), key=operator.itemgetter(1), reverse=True) + top_sorted = sorted( + top.items(), key=operator.itemgetter(1), reverse=True) if top_sorted: top_sorted.pop(0) display_string = '' @@ -86,10 +86,11 @@ def main(): display_string += '{:2.2f} {}\n'.format(cpu/10, proc) # --------- Display timer and proceses in window -------- - window.FindElement('text').Update('CPU {}'.format(cpu_percent)) - window.FindElement('processes').Update(display_string) + window['text'].update('CPU {}'.format(cpu_percent)) + window['processes'].update(display_string) + + window.close() - window.Close() if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/PySimpleGUIWeb/Demo Programs/Web_Popup.py b/PySimpleGUIWeb/Demo Programs/Web_Popup.py index f286b88f..c6d7a6eb 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Popup.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Popup.py @@ -16,19 +16,20 @@ print('Starting up...') layout = [ [sg.Text('Your typed chars appear here:'), sg.Text('', key='_OUTPUT_')], - [sg.Input(do_not_clear=True, key='_IN_')], + [sg.Input('', key='_IN_')], [sg.Button('Show'), sg.Button('Exit'), sg.Button('Blank')] ] -window = sg.Window('Window Title').Layout(layout) +window = sg.Window('Window Title', layout) while True: # Event Loop print('in event loop') - event, values = window.Read() + event, values = window.read() + print(event, values) - if event is None or event == 'Exit': + if event in (None, 'Exit'): break if event == 'Show': - sg.Popup('A popup!', ' You typed ', values['_IN_']) + sg.popup('A popup!', ' You typed ', values['_IN_']) -window.Close() \ No newline at end of file +window.close() diff --git a/PySimpleGUIWeb/Demo Programs/Web_Simple.py b/PySimpleGUIWeb/Demo Programs/Web_Simple.py index 61d5ef5d..dd4d39a3 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Simple.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Simple.py @@ -1,26 +1,28 @@ import PySimpleGUIWeb as sg +# Basic example of PSGWeb + def main(): layout = [ - [sg.Text('This is a text element')], - [sg.Input()], - [sg.Combo(['Combo 1'])], - [sg.Text('If you close the browser tab, the app will exit gracefully')], - [sg.InputText('Source', do_not_clear=True)], - [sg.InputText('Dest', do_not_clear=True)], - [sg.Ok(), sg.Cancel()] - ] + [sg.Text('This is a text element')], + [sg.Input()], + [sg.Combo(['Combo 1'])], + [sg.Text('If you close the browser tab, the app will exit gracefully')], + [sg.InputText('Source')], + [sg.InputText('Dest')], + [sg.Ok(), sg.Cancel()] + ] - window = sg.Window('Demo window..').Layout(layout) + window = sg.Window('Demo window..', layout) i = 0 while True: - event, values = window.Read(timeout=1) + event, values = window.read(timeout=1) if event != sg.TIMEOUT_KEY: print(event, values) if event is None: break i += 1 - window.Close() + window.close() main() -print('Program terminating normally') \ No newline at end of file +print('Program terminating normally') diff --git a/PySimpleGUIWeb/Demo Programs/Web_Table_Element.py b/PySimpleGUIWeb/Demo Programs/Web_Table_Element.py index 780ed806..eb3ef886 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Table_Element.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Table_Element.py @@ -2,69 +2,42 @@ import PySimpleGUIWeb as sg import random import string -""" -ooooooooooooo .o8 oooo -8' 888 `8 "888 `888 - 888 .oooo. 888oooo. 888 .ooooo. - 888 `P )88b d88' `88b 888 d88' `88b - 888 .oP"888 888 888 888 888ooo888 - 888 d8( 888 888 888 888 888 .o - o888o `Y888""8o `Y8bod8P' o888o `Y8bod8P' - - - -oooooooooooo oooo . -`888' `8 `888 .o8 - 888 888 .ooooo. ooo. .oo. .oo. .ooooo. ooo. .oo. .o888oo - 888oooo8 888 d88' `88b `888P"Y88bP"Y88b d88' `88b `888P"Y88b 888 - 888 " 888 888ooo888 888 888 888 888ooo888 888 888 888 - 888 o 888 888 .o 888 888 888 888 .o 888 888 888 . -o888ooooood8 o888o `Y8bod8P' o888o o888o o888o `Y8bod8P' o888o o888o "888" -""" +# Example with Table element +def word(): + return ''.join(random.choice(string.ascii_lowercase) for i in range(10)) -# ------------------ Create a fake table ------------------ -class Fake(): - @classmethod - def word(self): - return ''.join(random.choice(string.ascii_lowercase) for i in range(10)) - - @classmethod - def number(self, max=1000): - return random.randint(0,max) +def number(max_val=1000): + return random.randint(0,max_val) def make_table(num_rows, num_cols): data = [[j for j in range(num_cols)] for i in range(num_rows)] - data[0] = [Fake.word() for _ in range(num_cols)] + data[0] = [word() for _ in range(num_cols)] for i in range(1, num_rows): - data[i] = [Fake.word(), *[Fake.number() for i in range(num_cols - 1)]] + data[i] = [word(), *[number() for i in range(num_cols - 1)]] return data table_data = make_table(num_rows=15, num_cols=6) # ------------------ Create a window layout ------------------ -layout = [[sg.Table(values=table_data, - enable_events=True, - display_row_numbers=True, - font='Courier 14', - row_header_text='Row #', - key='_table_', - text_color='red')], +layout = [[sg.Table(values=table_data, enable_events=True, + display_row_numbers=True, font='Courier 14', + row_header_text='Row #', key='_table_', text_color='red')], [sg.Button('Exit')], - [sg.T('Selected rows = '), sg.T('', size=(30,1), key='_selected_rows_')], - [sg.T('Selected value = '), sg.T('', size=(30,1), key='_selected_value_')]] + [sg.Text('Selected rows = '), sg.Text('', size=(30,1), key='_selected_rows_')], + [sg.Text('Selected value = '), sg.Text('', size=(30,1), key='_selected_value_')]] # ------------------ Create the window ------------------ -window = sg.Window('Table Element Example').Layout(layout) +window = sg.Window('Table Element Example', layout) # ------------------ The Event Loop ------------------ while True: - event, values = window.Read() + event, values = window.read() print(event, values) if event in (None, 'Exit'): break - window.Element('_selected_rows_').Update(values['_table_']) - window.Element('_selected_value_').Update(window.Element('_table_').SelectedItem) + window['_selected_rows_'].update(values['_table_']) + window['_selected_value_'].update(window['_table_'].SelectedItem) # ------------------ User closed window so exit ------------------ -window.Close() +window.close() diff --git a/PySimpleGUIWeb/Demo Programs/Web_Timer.py b/PySimpleGUIWeb/Demo Programs/Web_Timer.py index b81203d7..51e47589 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Timer.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Timer.py @@ -1,57 +1,62 @@ #!/usr/bin/env python import PySimpleGUIWeb as sg import time -import sys # ---------------- Create Form ---------------- layout = [ [sg.Text('', background_color='black')], - [sg.Text('00:00', size=(30, 1), font=('Helvetica', 30), justification='center', text_color='white', key='text', background_color='black')], + [sg.Text('00:00', size=(30, 1), font=('Helvetica', 30), justification='center', + text_color='white', key='text', background_color='black')], [sg.Text('', background_color='black')], [sg.Button('Pause', key='button', button_color=('white', '#001480')), sg.Button('Reset', button_color=('white', '#007339'), key='Reset'), sg.Exit(button_color=('white', '#8B1A1A'), key='Exit', )], - ] +] -window = sg.Window('Running Timer', background_color='black', font='Helvetica 18').Layout(layout) +window = sg.Window('Running Timer', layout, + background_color='black', font='Helvetica 18') # ---------------- main loop ---------------- current_time = 0 paused = False start_time = int(round(time.time() * 100)) -while (True): - # --------- Read and update window -------- +while True: + # --------- read and update window -------- if not paused: - event, values = window.Read(timeout=0) + event, values = window.read(timeout=0) current_time = int(round(time.time() * 100)) - start_time else: - event, values = window.Read() + event, values = window.read() print(event, values) if event != sg.TIMEOUT_KEY else None + if event == 'button': - event = window.FindElement(event).GetText() + event = window[event].GetText() # --------- Do Button Operations -------- + if event in (None, 'Exit'): # ALWAYS give a way out of program break + if event == 'Reset': start_time = int(round(time.time() * 100)) current_time = 0 paused_time = start_time + elif event == 'Pause': paused = True paused_time = int(round(time.time() * 100)) - element = window.FindElement('button') - element.Update(text='Run') + element = window['button'] + element.update(text='Run') + elif event == 'Run': paused = False start_time = start_time + int(round(time.time() * 100)) - paused_time - element = window.FindElement('button') - element.Update(text='Pause') + element = window['button'] + element.update(text='Pause') # --------- Display timer in window -------- - window.FindElement('text').Update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60, - (current_time // 100) % 60, - current_time % 100)) + window['text'].update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60, + (current_time // + 100) % 60, + current_time % 100)) # --------- After loop -------- -window.Close() -print('after loop') -sys.exit() \ No newline at end of file +window.close() diff --git a/PySimpleGUIWeb/Demo Programs/Web_Widget_Summary.py b/PySimpleGUIWeb/Demo Programs/Web_Widget_Summary.py index 88b63ec5..5377a50c 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_Widget_Summary.py +++ b/PySimpleGUIWeb/Demo Programs/Web_Widget_Summary.py @@ -3,43 +3,48 @@ import datetime DEFAULT_BASE64_ICON = b'R0lGODlhIQAgAPcAAAAAADBpmDBqmTFqmjJrmzJsnDNtnTRrmTZtmzZumzRtnTdunDRunTRunjVvnzdwnzhwnjlxnzVwoDZxoTdyojhzozl0ozh0pDp1pjp2pjp2pzx0oj12pD52pTt3qD54pjt4qDx4qDx5qTx5qj16qj57qz57rD58rT98rkB4pkJ7q0J9rEB9rkF+rkB+r0d9qkZ/rEl7o0h8p0x9pk5/p0l+qUB+sEyBrE2Crk2Er0KAsUKAskSCtEeEtUWEtkaGuEiHuEiHukiIu0qKu0mJvEmKvEqLvk2Nv1GErVGFr1SFrVGHslaHsFCItFSIs1COvlaPvFiJsVyRuWCNsWSPsWeQs2SQtGaRtW+Wt2qVuGmZv3GYuHSdv3ievXyfvV2XxGWZwmScx2mfyXafwHikyP7TPP/UO//UPP/UPf/UPv7UP//VQP/WQP/WQf/WQv/XQ//WRP7XSf/XSv/YRf/YRv/YR//YSP/YSf/YSv/ZS//aSv/aS/7YTv/aTP/aTf/bTv/bT//cT/7aUf/cUP/cUf/cUv/cU//dVP/dVf7dVv/eVv/eV//eWP/eWf/fWv/fW/7cX/7cYf7cZP7eZf7dav7eb//gW//gXP/gXf/gXv/gX//gYP/hYf/hYv/iYf/iYv7iZP7iZf/iZv/kZv7iaP/kaP/ka//ma//lbP/lbv/mbP/mbv7hdP7lcP/ncP/nc//ndv7gef7gev7iff7ke/7kfv7lf//ocf/ocv/odP/odv/peP/pe//ofIClw4Ory4GszoSszIqqxI+vyoSv0JGvx5OxyZSxyZSzzJi0y5m2zpC10pi715++16C6z6a/05/A2qHC3aXB2K3I3bLH2brP4P7jgv7jh/7mgf7lhP7mhf7liv/qgP7qh/7qiP7rjf7sjP7nkv7nlv7nmP7pkP7qkP7rkv7rlv7slP7sl/7qmv7rnv7snv7sn/7un/7sqv7vq/7vrf7wpv7wqf7wrv7wsv7wtv7ytv7zvP7zv8LU48LV5c3a5f70wP7z0AAAACH5BAEAAP8ALAAAAAAhACAAAAj/AP8JHEiwoMGDCA1uoYIF4bhK1vwlPOjlQICLApwVpFTGzBk1siYSrCLgoskFyQZKMsOypRyR/GKYnBkgQbF/s8603KnmWkIaNIMaw6lzZ8tYB2cIWMo0KIJj/7YV9XgGDRo14gpOIUBggNevXpkKGCDsXySradSoZcMmDsFnDxpEKEC3bl2uXCFQ+7emjV83bt7AgTNroJINAq0wWBxBgYHHdgt0+cdnMJw5c+jQqYNnoARkAx04kPEvS4PTqBswuPIPUp06duzcuYMHT55wAjkwEahsQgqBNSQIHy582D9BePTs2dOnjx8/f1gJ9GXhRpTqApFQoDChu3cOAps///9D/g+gQvYGjrlw4cU/fUnYX6hAn34HgZMABQo0iJB/Qoe8UxAXOQiEg3wIXvCBQLUU4mAhh0R4SCLqJOSEBhhqkAEGHIYgUDaGICIiIoossogj6yBUTQ4htNgiCCB4oIJAtJTIyI2MOOLIIxMtQQIJIwQZpAgwCKRNI43o6Igll1ySSTsI7dOECSaUYOWVKwhkiyVMYuJlJpp0IpA6oJRTkBQopHnCmmu2IBA2mmQi5yZ0fgJKPP+0IwoooZwzkDQ2uCCoCywUyoIW/5DDyaKefOLoJ6LU8w87pJgDTzqmDNSMDpzqYMOnn/7yTyiglBqKKKOMUopA7JgCy0DdeMEjUDM71GqrrcH8QwqqqpbiayqToqJKLwN5g45A0/TAw7LL2krGP634aoopp5yiiiqrZLuKK+jg444uBIHhw7g+MMsDFP/k4wq22rririu4xItLLriAUxAQ5ObrwzL/0PPKu7fIK3C8uxz0w8EIIwzMP/cM7HC88hxEzBBCBGGxxT8AwQzDujws7zcJQVMEEUKUbPITAt1D78OSivSFEUXEXATKA+HTscC80CPSQNGEccQRYhjUDzfxcjPPzkgnLVBAADs=' +layout = [ + [sg.Text('PySimpleGUIWeb running on the web and in your browser!', + size=(60, 1), font=('Comic sans ms', 20), text_color='red')], + [sg.Text('This program has been running for... ', size=(30, 1)), + sg.Text('', size=(30, 1), key='_DATE_')], -sg.ChangeLookAndFeel('GreenTan') + [sg.Text('', size=(30, 1), key='_TEXT_')], + [sg.Input('Single Line Input', enable_events=True, size=(30, 1))], + # [sg.MultiLine('Multiline Input', size=(40, 4), enable_events=True)], + # [sg.MultiLine('Multiline Output', size=(80, 8), + # key='_MULTIOUT_', font='Courier 12')], -layout = [ - [sg.Text('PySimpleGUIWeb running on the web and in your browser!', size=(60,1), font=('Comic sans ms', 20), text_color='red')], - [sg.Text('This program has been running for... ', size=(30,1)),sg.Text('', size=(30,1), key='_DATE_')], - [sg.Text('', size=(30,1), key='_TEXT_')], - [sg.Input('Single Line Input', do_not_clear=True, enable_events=True, size=(30,1))], - [sg.Multiline('Multiline Input', do_not_clear=True, size=(40,4), enable_events=True)], - [sg.Multiline('Multiline Output', size=(80,8), key='_MULTIOUT_', font='Courier 12')], - [sg.Checkbox('Checkbox 1', enable_events=True, key='_CB1_'), sg.Checkbox('Checkbox 2', default=True, enable_events=True, key='_CB2_')], - [sg.Combo(values=['Combo 1', 'Combo 2', 'Combo 3'], default_value='Combo 2', key='_COMBO_',enable_events=True, readonly=False, tooltip='Combo box', disabled=False, size=(12,1))], - [sg.Listbox(values=('Listbox 1', 'Listbox 2', 'Listbox 3'), size=(10,3))], - [sg.Slider((1,100), default_value=80, key='_SLIDER_', visible=True, enable_events=True, orientation='h')], - [sg.Spin(values=(1,2,3),initial_value=2, size=(4,1))], - [sg.Image(filename=r'dot:logo.jpg')], - [sg.OK(), sg.Button('Exit', button_color=('white', 'red'))] - ] + [sg.CBox('Checkbox 1', enable_events=True, key='_CB1_'), + sg.CBox('Checkbox 2', default=True, + enable_events=True, key='_CB2_')], -window = sg.Window('My PySimpleGUIWeb Window', - default_element_size=(30,1), - font='Helvetica 18', - background_image=r'dot:logo.jpg' - ).Layout(layout) + [sg.Combo(values=['Combo 1', 'Combo 2', 'Combo 3'], default_value='Combo 2', key='_COMBO_', + enable_events=True, readonly=False, tooltip='Combo box', disabled=False, size=(12, 1))], + + [sg.Listbox(values=('Listbox 1', 'Listbox 2', + 'Listbox 3'), size=(10, 3))], + + [sg.Slider((1, 100), default_value=80, key='_SLIDER_', + visible=True, enable_events=True, orientation='h')], + + [sg.Spin(values=(1, 2, 3), initial_value=2, size=(4, 1))], + [sg.Image(filename=r'dot:logo.jpg')], + [sg.OK(), sg.Button('Exit', button_color=('white', 'red'))] +] + +window = sg.Window('My PySimpleGUIWeb Window', layout, + default_element_size=(30, 1), font='Helvetica 18') start_time = datetime.datetime.now() while True: - event, values = window.Read(timeout=10) + event, values = window.read(timeout=10) if event != sg.TIMEOUT_KEY: print(event, values) - window.Element('_MULTIOUT_').Update(str(event) + '\n' + str(values), append=True) + window['_MULTIOUT_'].update( + str(event) + '\n' + str(values), append=True) if event in (None, 'Exit'): break - window.Element('_DATE_').Update(str(datetime.datetime.now()-start_time)) - -window.Close() - - - + window['_DATE_'].update(str(datetime.datetime.now()-start_time)) +window.close() diff --git a/PySimpleGUIWeb/Demo Programs/Web_psutil_Kill_Processes.py b/PySimpleGUIWeb/Demo Programs/Web_psutil_Kill_Processes.py index afeca438..204c4507 100644 --- a/PySimpleGUIWeb/Demo Programs/Web_psutil_Kill_Processes.py +++ b/PySimpleGUIWeb/Demo Programs/Web_psutil_Kill_Processes.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -import sys -import sys import PySimpleGUIWeb as sg import os import signal @@ -13,6 +11,7 @@ import operator Based on psutil package that is easily installed using pip """ + def kill_proc_tree(pid, sig=signal.SIGTERM, include_parent=True, timeout=None, on_terminate=None): """Kill a process tree (including grandchildren) with signal @@ -35,32 +34,31 @@ def kill_proc_tree(pid, sig=signal.SIGTERM, include_parent=True, def main(): - # ---------------- Create Form ---------------- - # sg.ChangeLookAndFeel('Topanga') - layout = [[sg.Text('Process Killer - Choose one or more processes', - size=(45,1), font=('Helvetica', 15), text_color='red')], - [sg.Listbox(values=[' '], size=(50, 30), select_mode=sg.SELECT_MODE_EXTENDED, font=('Courier', 12), key='_processes_')], + size=(45, 1), font=('Helvetica', 15), text_color='red')], + + [sg.Listbox(values=[' '], size=(50, 30), + select_mode=sg.SELECT_MODE_EXTENDED, font=('Courier', 12), key='_processes_')], + [sg.Text('Click refresh once or twice.. once for list, second to get CPU usage')], - [sg.T('Filter by typing name', font='ANY 14'), sg.In(size=(15,1), font='any 14', key='_filter_')], + [sg.Text('Filter by typing name', font='ANY 14'), sg.Input( + size=(15, 1), font='any 14', key='_filter_')], + [sg.Button('Sort by Name', ), sg.Button('Sort by % CPU', button_color=('white', 'DarkOrange2')), - sg.Button('Kill', button_color=('white','red'), bind_return_key=True), + sg.Button('Kill', button_color=('white', 'red'), bind_return_key=True), sg.Exit(button_color=('white', 'sea green'))]] - window = sg.Window('Process Killer', - keep_on_top=True, - auto_size_buttons=False, - default_button_element_size=(12,1), - return_keyboard_events=True, - ).Layout(layout) + window = sg.Window('Process Killer', layout, + keep_on_top=True, auto_size_buttons=False, + default_button_element_size=(12, 1), return_keyboard_events=True) display_list = None # ---------------- main loop ---------------- - while (True): + while True: # --------- Read and update window -------- event, values = window.Read() - if event is None or event == 'Exit': + if event in (None, 'Exit'): break # skip mouse, control key and shift key events entirely @@ -71,40 +69,46 @@ def main(): if event == 'Sort by Name': psutil.cpu_percent(interval=.1) procs = psutil.process_iter() - all_procs = [[proc.cpu_percent(), proc.name(), proc.pid] for proc in procs] - sorted_by_cpu_procs = sorted(all_procs, key=operator.itemgetter(1), reverse=False) + all_procs = [[proc.cpu_percent(), proc.name(), proc.pid] + for proc in procs] + sorted_by_cpu_procs = sorted( + all_procs, key=operator.itemgetter(1), reverse=False) display_list = [] for process in sorted_by_cpu_procs: - display_list.append('{:5d} {:5.2f} {}\n'.format(process[2], process[0]/10, process[1])) - window.FindElement('_processes_').Update(display_list) + display_list.append('{:5d} {:5.2f} {}\n'.format( + process[2], process[0]/10, process[1])) + window['_processes_'].update(display_list) print(display_list) elif event == 'Kill': processes_to_kill = values['_processes_'] for proc in processes_to_kill: pid = int(proc[0:5]) - # if sg.PopupYesNo('About to kill {} {}'.format(pid, proc[12:]), keep_on_top=True) == 'Yes': + # if sg.popupYesNo('About to kill {} {}'.format(pid, proc[12:]), keep_on_top=True) == 'Yes': try: kill_proc_tree(pid=pid) except: - sg.PopupAutoClose('Error killing process', auto_close_duration=1) + sg.popup_auto_close( + 'Error killing process', auto_close_duration=1) elif event == 'Sort by % CPU': psutil.cpu_percent(interval=.1) procs = psutil.process_iter() - all_procs = [[proc.cpu_percent(), proc.name(), proc.pid] for proc in procs] - sorted_by_cpu_procs = sorted(all_procs, key=operator.itemgetter(0), reverse=True) + all_procs = [[proc.cpu_percent(), proc.name(), proc.pid] + for proc in procs] + sorted_by_cpu_procs = sorted( + all_procs, key=operator.itemgetter(0), reverse=True) display_list = [] for process in sorted_by_cpu_procs: - display_list.append('{:5d} {:5.2f} {}\n'.format(process[2], process[0]/10, process[1])) - window.FindElement('_processes_').Update(display_list) + display_list.append('{:5d} {:5.2f} {}\n'.format( + process[2], process[0]/10, process[1])) + window['_processes_'].update(display_list) else: # was a typed character if display_list is not None: new_output = [] for line in display_list: if values['_filter_'] in line.lower(): new_output.append(line) - window.FindElement('_processes_').Update(new_output) - + window['_processes_'].update(new_output) + window.close() if __name__ == "__main__": main() - sys.exit(0) \ No newline at end of file diff --git a/PySimpleGUIWeb/Demo Programs/widgets_overview_app.py b/PySimpleGUIWeb/Demo Programs/widgets_overview_app.py index d5b388df..6eca2d96 100644 --- a/PySimpleGUIWeb/Demo Programs/widgets_overview_app.py +++ b/PySimpleGUIWeb/Demo Programs/widgets_overview_app.py @@ -23,32 +23,39 @@ class MyApp(App): def idle(self): self.counter.set_text('Running Time: ' + str(self.count)) - self.progress.set_value(self.count%100) + self.progress.set_value(self.count % 100) def main(self): # the margin 0px auto centers the main container - verticalContainer = gui.Widget(width=540, margin='0px auto', style={'display': 'block', 'overflow': 'hidden'}) + verticalContainer = gui.Widget(width=540, margin='0px auto', style={ + 'display': 'block', 'overflow': 'hidden'}) - horizontalContainer = gui.Widget(width='100%', layout_orientation=gui.Widget.LAYOUT_HORIZONTAL, margin='0px', style={'display': 'block', 'overflow': 'auto'}) - - subContainerLeft = gui.Widget(width=320, style={'display': 'block', 'overflow': 'auto', 'text-align': 'center'}) + horizontalContainer = gui.Widget(width='100%', layout_orientation=gui.Widget.LAYOUT_HORIZONTAL, + margin='0px', style={'display': 'block', 'overflow': 'auto'}) + + subContainerLeft = gui.Widget(width=320, + style={'display': 'block', 'overflow': 'auto', 'text-align': 'center'}) self.img = gui.Image('/res:logo.png', height=100, margin='10px') self.img.onclick.connect(self.on_img_clicked) self.table = gui.Table.new_from_list([('ID', 'First Name', 'Last Name'), - ('101', 'Danny', 'Young'), - ('102', 'Christine', 'Holand'), - ('103', 'Lars', 'Gordon'), - ('104', 'Roberto', 'Robitaille'), - ('105', 'Maria', 'Papadopoulos')], width=300, height=200, margin='10px') + ('101', 'Danny', 'Young'), + ('102', 'Christine', 'Holand'), + ('103', 'Lars', 'Gordon'), + ('104', 'Roberto', 'Robitaille'), + ('105', 'Maria', 'Papadopoulos')], + width=300, height=200, margin='10px') self.table.on_table_row_click.connect(self.on_table_row_click) - # the arguments are width - height - layoutOrientationOrizontal - subContainerRight = gui.Widget(style={'width': '220px', 'display': 'block', 'overflow': 'auto', 'text-align': 'center'}) + # the arguments are width - height - layoutOrientationOrizontal + subContainerRight = gui.Widget( + style={'width': '220px', 'display': 'block', + 'overflow': 'auto', 'text-align': 'center'}) self.count = 0 self.counter = gui.Label('', width=200, height=30, margin='10px') - self.lbl = gui.Label('This is a LABEL!', width=200, height=30, margin='10px') + self.lbl = gui.Label('This is a LABEL!', width=200, + height=30, margin='10px') self.bt = gui.Button('Press me!', width=200, height=30, margin='10px') # setting the listener for the onclick event of the button @@ -63,46 +70,56 @@ class MyApp(App): self.progress = gui.Progress(1, 100, width=200, height=5) - self.check = gui.CheckBoxLabel('Label checkbox', True, width=200, height=30, margin='10px') + self.check = gui.CheckBoxLabel( + 'Label checkbox', True, width=200, height=30, margin='10px') self.check.onchange.connect(self.on_check_change) - self.btInputDiag = gui.Button('Open InputDialog', width=200, height=30, margin='10px') + self.btInputDiag = gui.Button( + 'Open InputDialog', width=200, height=30, margin='10px') self.btInputDiag.onclick.connect(self.open_input_dialog) - self.btFileDiag = gui.Button('File Selection Dialog', width=200, height=30, margin='10px') + self.btFileDiag = gui.Button( + 'File Selection Dialog', width=200, height=30, margin='10px') self.btFileDiag.onclick.connect(self.open_fileselection_dialog) - self.btUploadFile = gui.FileUploader('./', width=200, height=30, margin='10px') + self.btUploadFile = gui.FileUploader( + './', width=200, height=30, margin='10px') self.btUploadFile.onsuccess.connect(self.fileupload_on_success) self.btUploadFile.onfailed.connect(self.fileupload_on_failed) - items = ('Danny Young','Christine Holand','Lars Gordon','Roberto Robitaille') - self.listView = gui.ListView.new_from_list(items, width=300, height=120, margin='10px') + items = ('Danny Young', 'Christine Holand', + 'Lars Gordon', 'Roberto Robitaille') + self.listView = gui.ListView.new_from_list( + items, width=300, height=120, margin='10px') self.listView.onselection.connect(self.list_view_on_selected) - self.link = gui.Link("http://localhost:8081", "A link to here", width=200, height=30, margin='10px') + self.link = gui.Link("http://localhost:8081", "A link to here", + width=200, height=30, margin='10px') - self.dropDown = gui.DropDown.new_from_list(('DropDownItem 0', 'DropDownItem 1'), - width=200, height=20, margin='10px') + self.dropDown = gui.DropDown.new_from_list( + ('DropDownItem 0', 'DropDownItem 1'), width=200, height=20, margin='10px') self.dropDown.onchange.connect(self.drop_down_changed) self.dropDown.select_by_value('DropDownItem 0') - self.slider = gui.Slider(10, 0, 100, 5, width=200, height=20, margin='10px') + self.slider = gui.Slider( + 10, 0, 100, 5, width=200, height=20, margin='10px') self.slider.onchange.connect(self.slider_changed) - self.colorPicker = gui.ColorPicker('#ffbb00', width=200, height=20, margin='10px') + self.colorPicker = gui.ColorPicker( + '#ffbb00', width=200, height=20, margin='10px') self.colorPicker.onchange.connect(self.color_picker_changed) self.date = gui.Date('2015-04-13', width=200, height=20, margin='10px') self.date.onchange.connect(self.date_changed) - self.video = gui.Widget( _type='iframe', width=290, height=200, margin='10px') + self.video = gui.Widget(_type='iframe', width=290, + height=200, margin='10px') self.video.attributes['src'] = "https://drive.google.com/file/d/0B0J9Lq_MRyn4UFRsblR3UTBZRHc/preview" self.video.attributes['width'] = '100%' self.video.attributes['height'] = '100%' self.video.attributes['controls'] = 'true' self.video.style['border'] = 'none' - + self.tree = gui.TreeView(width='100%', height=300) ti1 = gui.TreeItem("Item1") ti2 = gui.TreeItem("Item2") @@ -117,16 +134,20 @@ class MyApp(App): self.tree.append([ti1, ti2, ti3]) ti2.append([subti1, subti2, subti3, subti4]) subti4.append([subsubti1, subsubti2, subsubti3]) - + # appending a widget to another, the first argument is a string key - subContainerRight.append([self.counter, self.lbl, self.bt, self.txt, self.spin, self.progress, self.check, self.btInputDiag, self.btFileDiag]) + subContainerRight.append([self.counter, self.lbl, self.bt, self.txt, + self.spin, self.progress, self.check, self.btInputDiag, self.btFileDiag]) # use a defined key as we replace this widget later - fdownloader = gui.FileDownloader('download test', '../remi/res/logo.png', width=200, height=30, margin='10px') + fdownloader = gui.FileDownloader( + 'download test', '../remi/res/logo.png', width=200, height=30, margin='10px') subContainerRight.append(fdownloader, key='file_downloader') - subContainerRight.append([self.btUploadFile, self.dropDown, self.slider, self.colorPicker, self.date, self.tree]) + subContainerRight.append( + [self.btUploadFile, self.dropDown, self.slider, self.colorPicker, self.date, self.tree]) self.subContainerRight = subContainerRight - subContainerLeft.append([self.img, self.table, self.listView, self.link, self.video]) + subContainerLeft.append( + [self.img, self.table, self.listView, self.link, self.video]) horizontalContainer.append([subContainerLeft, subContainerRight]) @@ -153,8 +174,8 @@ class MyApp(App): verticalContainer.append([menubar, horizontalContainer]) - #this flag will be used to stop the display_counter Timer - self.stop_flag = False + # this flag will be used to stop the display_counter Timer + self.stop_flag = False # kick of regular display of counter self.display_counter() @@ -168,20 +189,28 @@ class MyApp(App): Timer(1, self.display_counter).start() def menu_dialog_clicked(self, widget): - self.dialog = gui.GenericDialog(title='Dialog Box', message='Click Ok to transfer content to main page', width='500px') + self.dialog = gui.GenericDialog( + title='Dialog Box', + message='Click Ok to transfer content to main page', width='500px') self.dtextinput = gui.TextInput(width=200, height=30) self.dtextinput.set_value('Initial Text') - self.dialog.add_field_with_label('dtextinput', 'Text Input', self.dtextinput) + self.dialog.add_field_with_label( + 'dtextinput', 'Text Input', self.dtextinput) self.dcheck = gui.CheckBox(False, width=200, height=30) - self.dialog.add_field_with_label('dcheck', 'Label Checkbox', self.dcheck) - values = ('Danny Young', 'Christine Holand', 'Lars Gordon', 'Roberto Robitaille') - self.dlistView = gui.ListView.new_from_list(values, width=200, height=120) - self.dialog.add_field_with_label('dlistView', 'Listview', self.dlistView) + self.dialog.add_field_with_label( + 'dcheck', 'Label Checkbox', self.dcheck) + values = ('Danny Young', 'Christine Holand', + 'Lars Gordon', 'Roberto Robitaille') + self.dlistView = gui.ListView.new_from_list( + values, width=200, height=120) + self.dialog.add_field_with_label( + 'dlistView', 'Listview', self.dlistView) self.ddropdown = gui.DropDown.new_from_list(('DropDownItem 0', 'DropDownItem 1'), width=200, height=20) - self.dialog.add_field_with_label('ddropdown', 'Dropdown', self.ddropdown) + self.dialog.add_field_with_label( + 'ddropdown', 'Dropdown', self.ddropdown) self.dspinbox = gui.SpinBox(min=0, max=5000, width=200, height=20) self.dspinbox.set_value(50) @@ -193,7 +222,8 @@ class MyApp(App): self.dcolor = gui.ColorPicker(width=200, height=20) self.dcolor.set_value('#ffff00') - self.dialog.add_field_with_label('dcolor', 'Colour Picker', self.dcolor) + self.dialog.add_field_with_label( + 'dcolor', 'Colour Picker', self.dcolor) self.ddate = gui.Date(width=200, height=20) self.ddate.set_value('2000-01-01') @@ -249,8 +279,7 @@ class MyApp(App): def open_input_dialog(self, widget): self.inputDialog = gui.InputDialog('Input Dialog', 'Your name?', - initial_value='type here', - width=500, height=160) + initial_value='type here', width=500, height=160) self.inputDialog.confirm_value.connect( self.on_input_dialog_confirm) @@ -261,8 +290,8 @@ class MyApp(App): self.lbl.set_text('Hello ' + value) def open_fileselection_dialog(self, widget): - self.fileselectionDialog = gui.FileSelectionDialog('File Selection Dialog', 'Select files and folders', False, - '.') + self.fileselectionDialog = gui.FileSelectionDialog('File Selection Dialog', + 'Select files and folders', False, '.') self.fileselectionDialog.confirm_value.connect( self.on_fileselection_dialog_confirm) @@ -275,14 +304,16 @@ class MyApp(App): if len(filelist): f = filelist[0] # replace the last download link - fdownloader = gui.FileDownloader("download selected", f, width=200, height=30) + fdownloader = gui.FileDownloader( + "download selected", f, width=200, height=30) self.subContainerRight.append(fdownloader, key='file_downloader') def list_view_on_selected(self, widget, selected_item_key): """ The selection event of the listView, returns a key of the clicked event. You can retrieve the item rapidly """ - self.lbl.set_text('List selection: ' + self.listView.children[selected_item_key].get_text()) + self.lbl.set_text('List selection: ' + + self.listView.children[selected_item_key].get_text()) def drop_down_changed(self, widget, value): self.lbl.set_text('New Combo value: ' + value) @@ -326,4 +357,5 @@ if __name__ == "__main__": # optional parameters # start(MyApp,address='127.0.0.1', port=8081, multiple_instance=False,enable_file_cache=True, update_interval=0.1, start_browser=True) import ssl - start(MyApp, debug=True, address='0.0.0.0', port=8081, start_browser=True, multiple_instance=True) + start(MyApp, debug=True, address='0.0.0.0', port=8081, + start_browser=True, multiple_instance=True) diff --git a/PySimpleGUIWeb/PySimpleGUIWeb.py b/PySimpleGUIWeb/PySimpleGUIWeb.py index 1123c74b..3eb95189 100644 --- a/PySimpleGUIWeb/PySimpleGUIWeb.py +++ b/PySimpleGUIWeb/PySimpleGUIWeb.py @@ -1474,6 +1474,8 @@ class Image(Element): # def get_image_data(self, update_index): # headers = {'Content-type': self.mimetype if self.mimetype else 'application/octet-stream'} # return [self.imagedata, headers] + + class SuperImage(remi.gui.Image): def __init__(self, file_path_name=None, **kwargs): """ @@ -1493,6 +1495,68 @@ class SuperImage(remi.gui.Image): if not image: return self.load(image) + def load(self, file_path_name): + if type(file_path_name) is bytes or len(file_path_name) > 200: + try: + #here a base64 image is received + self.imagedata = base64.b64decode(file_path_name, validate=True) + self.attributes['src'] = "/%s/get_image_data?update_index=%s" % (id(self), str(time.time())) + except binascii.Error: + #here an image data is received (opencv image) + self.imagedata = file_path_name + self.refresh() + self.refresh() + else: + #here a filename is received + self.attributes['src'] = remi.gui.load_resource(file_path_name) + """print(f'***** Loading file = {file_path_name}') + self.mimetype, self.encoding = mimetypes.guess_type(file_path_name) + with open(file_path_name, 'rb') as f: + self.imagedata = f.read()""" + self.refresh() + + def refresh(self): + i = int(time.time() * 1e6) + # self.app_instance.execute_javascript(""" + if Window.App is not None: + Window.App.execute_javascript(""" + var url = '/%(id)s/get_image_data?update_index=%(frame_index)s'; + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'blob' + xhr.onload = function(e){ + var urlCreator = window.URL || window.webkitURL; + var imageUrl = urlCreator.createObjectURL(this.response); + document.getElementById('%(id)s').src = imageUrl; + } + xhr.send(); + """ % {'id': id(self), 'frame_index':i}) + + def get_image_data(self, update_index): + headers = {'Content-type': self.mimetype if self.mimetype else 'application/octet-stream'} + return [self.imagedata, headers] + + + +class SuperImage_OLD(remi.gui.Image): + def __init__(self, file_path_name=None, **kwargs): + """ + This new app_instance variable is causing lots of problems. I do not know the value of the App + when I create this image. + :param app_instance: + :param file_path_name: + :param kwargs: + """ + # self.app_instance = app_instance + image = file_path_name + super(SuperImage, self).__init__(image, **kwargs) + + self.imagedata = None + self.mimetype = None + self.encoding = None + if not image: return + self.load(image) + def load(self, file_path_name): if type(file_path_name) is bytes or len(file_path_name) > 200: try: