diff --git a/DemoPrograms/Demo_Media_Player_VLC_Based.py b/DemoPrograms/Demo_Media_Player_VLC_Based.py new file mode 100644 index 00000000..748a20e9 --- /dev/null +++ b/DemoPrograms/Demo_Media_Player_VLC_Based.py @@ -0,0 +1,68 @@ +""" + Bare Bones Media Player Demo with Playlist. Adapeted from media player located at https://github.com/israel-dryer/Media-Player + Original Author : Israel Dryer + Modified to be a PySimpleGUI Demo Program + A very simple media player ready for you to customize. Uses the VLC player to playback local files and YouTube streams. You will need to install the Python bindings for VLC as well as the VLC player itself. + You will need to pip install: + pip install python-vlc + pip install youtube-dl +""" +import PySimpleGUI as sg +import vlc + +#------- GUI definition & setup --------# + +sg.change_look_and_feel('DarkBlue') + +def btn(name): # a PySimpleGUI "User Defined Element" (see docs) + return sg. Button(name, size=(6, 1), pad=(1, 1)) + +layout = [[sg.Input(default_text='Video URL or Local Path:', size=(30, 1), key='-VIDEO_LOCATION-'), sg.Button('load')], + [sg.Image('', size=(300, 170), key='-VID_OUT-')], + [btn('previous'), btn('play'), btn('next'), btn('pause'), btn('stop')], + [sg.Text('Load media to start', key='-MESSAGE_AREA-')]] + +window = sg.Window('Mini Player', layout, element_justification='center', finalize=True) + +#------------ Media Player Setup ---------# + +inst = vlc.Instance() +list_player = inst.media_list_player_new() +media_list = inst.media_list_new([]) +list_player.set_media_list(media_list) +player = list_player.get_media_player() +player.set_hwnd(window['-VID_OUT-'].Widget.winfo_id()) + +#------------ The Event Loop ------------# +while True: + event, values = window.read(timeout=1000) # run with a timeout so that current location can be updated + if event is None: + break + + if event == 'play': + list_player.play() + if event == 'pause': + list_player.pause() + if event == 'stop': + list_player.stop() + if event == 'next': + list_player.next() + list_player.play() + if event == 'previous': + list_player.previous() # first call causes current video to start over + list_player.previous() # second call moves back 1 video from current + list_player.play() + if event == 'load': + if not 'Video URL' in values['-VIDEO_LOCATION-']: + media_list.add_media(values['-VIDEO_LOCATION-']) + list_player.set_media_list(media_list) + window['-VIDEO_LOCATION-'].update('Video URL or Local Path:') # only add a legit submit + + # update elapsed time if there is a video loaded and the player is playing + if player.is_playing(): + window['-MESSAGE_AREA-'].update("{:02d}:{:02d} / {:02d}:{:02d}".format(*divmod(player.get_time()//1000, 60), + *divmod(player.get_length()//1000, 60))) + else: + window['-MESSAGE_AREA-'].update('Load media to start' if media_list.count() == 0 else 'Ready to play media' ) + +window.close() 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: