diff --git a/Demo_All_Widgets.py b/Demo_All_Widgets.py index 939a1ad6..fe5a9596 100644 --- a/Demo_All_Widgets.py +++ b/Demo_All_Widgets.py @@ -20,7 +20,7 @@ column1 = [[sg.Text('Column 1', background_color='#F7F3EC', justification='cente layout = [ [sg.Menu(menu_def, tearoff=True)], - [sg.Text('All graphic widgets in one form!', size=(30, 1), justification='center', font=("Helvetica", 25), relief=sg.RELIEF_RIDGE)], + [sg.Text('All graphic widgets in one Window!', size=(30, 1), justification='center', font=("Helvetica", 25), relief=sg.RELIEF_RIDGE, text_color='midnightblue')], [sg.Text('Here is some text.... and a place to enter text')], [sg.InputText('This is my text')], [sg.Frame(layout=[ diff --git a/Demo_Button_States.py b/Demo_Button_States.py index 729fa5ba..9468bb12 100644 --- a/Demo_Button_States.py +++ b/Demo_Button_States.py @@ -16,16 +16,16 @@ sg.SetOptions(element_padding=(0,0)) layout = [[sg.T('User:', pad=((3,0),0)), sg.OptionMenu(values = ('User 1', 'User 2'), size=(20,1)), sg.T('0', size=(8,1))], [sg.T('Customer:', pad=((3,0),0)), sg.OptionMenu(values=('Customer 1', 'Customer 2'), size=(20,1)), sg.T('1', size=(8,1))], [sg.T('Notes:', pad=((3,0),0)), sg.In(size=(44,1), background_color='white', text_color='black')], - [sg.ReadButton('Start', button_color=('white', 'black'), key='Start'), - sg.ReadButton('Stop', button_color=('white', 'black'), key='Stop'), - sg.ReadButton('Reset', button_color=('white', 'firebrick3'), key='Reset'), - sg.ReadButton('Submit', button_color=('white', 'springgreen4'), key='Submit')]] + [sg.ReadButton('Start', button_color=('white', 'black'), key='_Start_'), + sg.ReadButton('Stop', button_color=('white', 'black'), key='_Stop_'), + sg.ReadButton('Reset', button_color=('white', 'firebrick3'), key='_Reset_'), + sg.ReadButton('Submit', button_color=('white', 'springgreen4'), key='_Submit_')]] window = sg.Window("Time Tracker", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False, default_button_element_size=(12,1)).Layout(layout).Finalize() -for key, state in {'Start': False, 'Stop': True, 'Reset': True, 'Submit': True}.items(): +for key, state in {'_Start_': False, '_Stop_': True, '_Reset_': True, '_Submit_': True}.items(): window.FindElement(key).Update(disabled=state) recording = have_data = False @@ -34,18 +34,18 @@ while True: print(button) if button is None: sys.exit(69) - if button is 'Start': - for key, state in {'Start':True, 'Stop':False, 'Reset':False, 'Submit':True}.items(): + if button == '_Start_': + for key, state in {'_Start_':True, '_Stop_':False, '_Reset_':False, '_Submit_':True}.items(): window.FindElement(key).Update(disabled=state) recording = True - elif button is 'Stop' and recording: - [window.FindElement(key).Update(disabled=value) for key,value in {'Start':False, 'Stop':True, 'Reset':False, 'Submit':False}.items()] + elif button == '_Stop_' and recording: + [window.FindElement(key).Update(disabled=value) for key,value in {'_Start_':False, '_Stop_':True, '_Reset_':False, '_Submit_':False}.items()] recording = False have_data = True - elif button is 'Reset': - [window.FindElement(key).Update(disabled=value) for key,value in {'Start':False, 'Stop':True, 'Reset':True, 'Submit':True}.items()] + elif button == '_Reset_': + [window.FindElement(key).Update(disabled=value) for key,value in {'_Start_':False, '_Stop_':True, '_Reset_':True, '_Submit_':True}.items()] recording = False have_data = False - elif button is 'Submit' and have_data: - [window.FindElement(key).Update(disabled=value) for key,value in {'Start':False, 'Stop':True, 'Reset':True, 'Submit':False}.items()] + elif button is '_Submit_' and have_data: + [window.FindElement(key).Update(disabled=value) for key,value in {'_Start_':False, '_Stop_':True, '_Reset_':True, '_Submit_':False}.items()] recording = False diff --git a/Demo_Color_Names.py b/Demo_Color_Names.py index aeba15d0..ff46e2f8 100644 --- a/Demo_Color_Names.py +++ b/Demo_Color_Names.py @@ -11,6 +11,7 @@ else: Shows a big chart of colors... give it a few seconds to create it Once large window is shown, you can click on any color and another window will popup showing both white and black text on that color + Uses TOOLTIPS to show the hex values for the colors. Hover over a color and a tooltip will show you the RGB You will find the list of tkinter colors here: http://www.tcl.tk/man/tcl8.5/TkCmd/colors.htm @@ -670,7 +671,7 @@ color_map = { } -sg.SetOptions(button_element_size=(12,1), element_padding=(0,0), auto_size_buttons=False, border_width=1) +sg.SetOptions(button_element_size=(12,1), element_padding=(0,0), auto_size_buttons=False, border_width=1, tooltip_time=100) layout = [[sg.Text('Hover mouse to see RGB value, click for white & black text', text_color='blue', font='Any 15', relief=sg.RELIEF_SUNKEN, justification='center', size=(100,1), background_color='light green', pad=(0,(0,20))),]] row = [] @@ -689,5 +690,5 @@ while True: if b is None: break # -- Create a secondary window that shows white and black text on chosen color - layout2 =[[sg.Button(b, button_color=('white', b), tooltip=color_map[b]), sg.Button(b, button_color=('black', b), tooltip=color_map[b])] ] - sg.Window('Buttons with white and black text', keep_on_top=True).Layout(layout2).Read() \ No newline at end of file + layout2 =[[sg.DummyButton(b, button_color=('white', b), tooltip=color_map[b]), sg.DummyButton(b, button_color=('black', b), tooltip=color_map[b])] ] + sg.Window('Buttons with white and black text', keep_on_top=True).Layout(layout2).ReadNonBlocking() \ No newline at end of file diff --git a/Demo_Color_Names_Smaller_List.py b/Demo_Color_Names_Smaller_List.py index fac8fe5c..4578c002 100644 --- a/Demo_Color_Names_Smaller_List.py +++ b/Demo_Color_Names_Smaller_List.py @@ -109,5 +109,5 @@ while True: if b is None: break # -- Create a secondary window that shows white and black text on chosen color - layout2 =[[sg.Button(b, button_color=('white', b)), sg.Button(b, button_color=('black', b))] ] - sg.Window('Buttons with white and black text', keep_on_top=True).Layout(layout2).Read() \ No newline at end of file + layout2 =[[sg.DummyButton(b, button_color=('white', b)), sg.DummyButton(b, button_color=('black', b))] ] + sg.Window('Buttons with white and black text', keep_on_top=True).Layout(layout2).ReadNonBlocking() \ No newline at end of file diff --git a/Demo_Cookbook_Browser.py b/Demo_Cookbook_Browser.py index b346d5a0..980162a8 100644 --- a/Demo_Cookbook_Browser.py +++ b/Demo_Cookbook_Browser.py @@ -277,7 +277,7 @@ def CallbackSimulation(): break # All done! - sg.PopupOk('Done') + sg.PopupOK('Done') def RealtimeButtons(): """ diff --git a/Demo_Desktop_Widget_CPU_Utilization.py b/Demo_Desktop_Widget_CPU_Utilization.py index af970e62..97de5af6 100644 --- a/Demo_Desktop_Widget_CPU_Utilization.py +++ b/Demo_Desktop_Widget_CPU_Utilization.py @@ -45,12 +45,16 @@ def main(): # ---------------- Create Form ---------------- sg.ChangeLookAndFeel('Black') - layout = [[sg.Text('', size=(8,1), font=('Helvetica', 20),text_color=sg.YELLOWS[0], justification='center', key='text')], + 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)), sg.Spin([x+1 for x in range(10)], 1, key='spin')],] + [sg.Exit(button_color=('white', 'firebrick4'), pad=((15,0), 0), size=(9,1)), + sg.Spin([x+1 for x in range(10)], 1, key='spin')],] - window = sg.Window('CPU Utilization', no_titlebar=True, auto_size_buttons=False, - keep_on_top=True, grab_anywhere=True).Layout(layout) + window = sg.Window('CPU Utilization', + no_titlebar=True, + keep_on_top=True, + grab_anywhere=True).Layout(layout) # start cpu measurement thread thread = Thread(target=CPU_thread,args=(None,)) diff --git a/Demo_Desktop_Widget_CPU_Utilization_Simple.py b/Demo_Desktop_Widget_CPU_Utilization_Simple.py index afb5efd4..460e2692 100644 --- a/Demo_Desktop_Widget_CPU_Utilization_Simple.py +++ b/Demo_Desktop_Widget_CPU_Utilization_Simple.py @@ -10,12 +10,17 @@ import psutil # ---------------- Create Form ---------------- sg.ChangeLookAndFeel('Black') -layout = [[sg.Text('')], - [sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='text')], - [sg.Exit(button_color=('white', 'firebrick4'), pad=((15, 0), 0)), - sg.Spin([x + 1 for x in range(10)], 1, key='spin')]] -# Layout the rows of the form and perform a read. Indicate the form is non-blocking! -window = sg.Window('CPU Meter', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True).Layout(layout) + +layout = [[sg.Text('CPU Utilization')], + [sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='_text_')], + [sg.Exit(button_color=('white', 'firebrick4'), pad=((15, 0), 0), size=(9,1)), + sg.Spin([x + 1 for x in range(10)], 1, key='_spin_')]] + +# Layout the rows of the Window +window = sg.Window('CPU Meter', + no_titlebar=True, + keep_on_top=True, + grab_anywhere=True).Layout(layout) # ---------------- main loop ---------------- while (True): @@ -26,7 +31,7 @@ while (True): if values is None or button == 'Exit': break try: - interval = int(values['spin']) + interval = int(values['_spin_']) except: interval = 1 @@ -34,7 +39,7 @@ while (True): # --------- Display timer in window -------- - window.FindElement('text').Update(f'CPU {cpu_percent:02.0f}%') + window.FindElement('_text_').Update(f'CPU {cpu_percent:02.0f}%') # Broke out of main loop. Close the window. window.CloseNonBlocking() \ No newline at end of file diff --git a/Demo_Desktop_Widget_Timer.py b/Demo_Desktop_Widget_Timer.py index 5d15f079..c567c9d2 100644 --- a/Demo_Desktop_Widget_Timer.py +++ b/Demo_Desktop_Widget_Timer.py @@ -23,7 +23,7 @@ layout = [[sg.Text('')], sg.ReadButton('Reset', button_color=('white', '#007339'), key='Reset'), sg.Exit(button_color=('white', 'firebrick4'), key='Exit')]] -window = sg.Window('Running Timer', no_titlebar=False, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True).Layout(layout) +window = sg.Window('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True).Layout(layout) # ---------------- main loop ---------------- current_time = 0 diff --git a/Demo_Graph_Drawing.py b/Demo_Graph_Drawing.py index 193da119..c211a3cf 100644 --- a/Demo_Graph_Drawing.py +++ b/Demo_Graph_Drawing.py @@ -11,7 +11,7 @@ layout = [[sg.Graph(canvas_size=(400, 400), graph_bottom_left=(0,0), graph_top_r window = sg.Window('Graph test').Layout(layout).Finalize() graph = window.FindElement('graph') -circle = graph.DrawCircle((75,75), 25, fill_color='black',line_color='white') +circle =graph .DrawCircle((75,75), 25, fill_color='black',line_color='white') point = graph.DrawPoint((75,75), 10, color='green') oval = graph.DrawOval((25,300), (100,280), fill_color='purple', line_color='purple' ) rectangle = graph.DrawRectangle((25,300), (100,280), line_color='purple' ) diff --git a/Demo_Img_Viewer.py b/Demo_Img_Viewer.py index 0f279ff6..7e76849f 100644 --- a/Demo_Img_Viewer.py +++ b/Demo_Img_Viewer.py @@ -22,9 +22,9 @@ Dependecies Python v3 PIL """ -# Get the folder containing the images from the user -rc, folder = sg.GetPathBox('Image Browser', 'Image folder to open', default_path='') -if not rc or not folder: +# Get the folder containin:g the images from the user +folder = sg.PopupGetFolder('Image folder to open', default_path='') +if not folder: sg.PopupCancel('Cancelling') raise SystemExit() @@ -89,7 +89,7 @@ i=0 while True: # read the form button, values = window.Read() - + print(button, values) # perform button and keyboard operations if button is None: break @@ -103,7 +103,7 @@ while True: if i < 0: i = num_files + i filename = os.path.join(folder, fnames[i]) - elif button in ('Read', ''): # something from the listbox + elif button == 'listbox': # something from the listbox f = values["listbox"][0] # selected filename filename = os.path.join(folder, f) # read this file i = fnames.index(f) # update running index diff --git a/Demo_Keypad.py b/Demo_Keypad.py index a66685c4..c99e6dd3 100644 --- a/Demo_Keypad.py +++ b/Demo_Keypad.py @@ -35,7 +35,7 @@ while True: if button == 'Clear': # clear keys if clear button keys_entered = '' elif button in '1234567890': - keys_entere=d = values['input'] # get what's been entered so far + keys_entered = values['input'] # get what's been entered so far keys_entered += button # add the new digit elif button == 'Submit': keys_entered = values['input'] diff --git a/Demo_LED_Indicators.py b/Demo_LED_Indicators.py index 5754c653..809eb54b 100644 --- a/Demo_LED_Indicators.py +++ b/Demo_LED_Indicators.py @@ -16,29 +16,33 @@ import random """ -def LEDIndicator(key): - return sg.Graph(canvas_size=(30, 30), graph_bottom_left=(-20, -20), graph_top_right=(20, 20), - pad=(0, 0), key=key) - +def LEDIndicator(key=None, radius=30): + return sg.Graph(canvas_size=(radius, radius), + graph_bottom_left=(-radius, -radius), + graph_top_right=(radius, radius), + pad=(0, 0), key=key) def SetLED(window, key, color): graph = window.FindElement(key) graph.Erase() - graph.DrawCircle((0, 0), 10, fill_color=color, line_color=color) + graph.DrawCircle((0, 0), 12, fill_color=color, line_color=color) -layout = [[sg.Text('My Status Report')], +layout = [[sg.Text('My LED Status Indicators', size=(20,1))], [sg.Text('CPU Use'), LEDIndicator('_cpu_')], [sg.Text('RAM'), LEDIndicator('_ram_')], [sg.Text('Temperature'), LEDIndicator('_temp_')], [sg.Text('Server 1'), LEDIndicator('_server1_')], - [sg.Exit()]] + [sg.RButton('Exit')]] window = sg.Window('My new window', default_element_size=(12, 1), auto_size_text=False).Layout(layout).Finalize() i = 0 while True: # Event Loop button, value = window.ReadNonBlocking() + if button == 'Exit': + window.CloseNonBlocking() + break if value is None: break i += 1 diff --git a/Demo_MIDI_Player.py b/Demo_MIDI_Player.py index fa4ea87c..dfac6460 100644 --- a/Demo_MIDI_Player.py +++ b/Demo_MIDI_Player.py @@ -76,7 +76,7 @@ class PlayerGUI(): image_filename=image_exit, image_size=(50,50), image_subsample=2, border_width=0, )] ] - window = sg.FlexForm('MIDI File Player', default_element_size=(30, 1), font=("Helvetica", 25)).Layout(layout).Finalize() + window = sg.Window('MIDI File Player', default_element_size=(30, 1), font=("Helvetica", 25)).Layout(layout).Finalize() self.Window = window @@ -87,7 +87,7 @@ class PlayerGUI(): # ------------------------------------------------------------------------- # def PlayerPlaybackGUIUpdate(self, DisplayString): window = self.Window - if 'window' not in locals() or window is None: # if the form has been destoyed don't mess with it + if 'window' not in locals() or window is None: # if the widnow has been destoyed don't mess with it return PLAYER_COMMAND_EXIT self.TextElem.Update(DisplayString) button, (values) = window.ReadNonBlocking() diff --git a/Demo_Matplotlib.py b/Demo_Matplotlib.py index 8cf6eb01..4019194c 100644 --- a/Demo_Matplotlib.py +++ b/Demo_Matplotlib.py @@ -23,22 +23,6 @@ Basic steps are: """ -def draw_figure(canvas, figure, loc=(0, 0)): - """ Draw a matplotlib figure onto a Tk canvas - - loc: location of top-left corner of figure on canvas in pixels. - - Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py - """ - figure_canvas_agg = FigureCanvasAgg(figure) - figure_canvas_agg.draw() - figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds - figure_w, figure_h = int(figure_w), int(figure_h) - photo = Tk.PhotoImage(master=canvas, width=figure_w, height=figure_h) - canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo) - tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2) - return photo - #------------------------------- PASTE YOUR MATPLOTLIB CODE HERE ------------------------------- import numpy as np @@ -95,7 +79,28 @@ figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds #------------------------------- END OF YOUR MATPLOTLIB CODE ------------------------------- -# define the form layout +#------------------------------- Beginning of Matplotlib helper code ----------------------- + + +def draw_figure(canvas, figure, loc=(0, 0)): + """ Draw a matplotlib figure onto a Tk canvas + + loc: location of top-left corner of figure on canvas in pixels. + + Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py + """ + figure_canvas_agg = FigureCanvasAgg(figure) + figure_canvas_agg.draw() + figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds + figure_w, figure_h = int(figure_w), int(figure_h) + photo = Tk.PhotoImage(master=canvas, width=figure_w, height=figure_h) + canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo) + tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2) + return photo + +#------------------------------- Beginning of GUI CODE ------------------------------- + +# define the window layout layout = [[sg.Text('Plot test', font='Any 18')], [sg.Canvas(size=(figure_w, figure_h), key='canvas')], [sg.OK(pad=((figure_w / 2, 0), 3), size=(4, 2))]] diff --git a/Demo_Menus.py b/Demo_Menus.py index e88cbe36..0849cd49 100644 --- a/Demo_Menus.py +++ b/Demo_Menus.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import sys if sys.version_info[0] >= 3: - import PySimpleGUI_mod as sg + import PySimpleGUI as sg else: import PySimpleGUI27 as sg """ @@ -20,26 +20,26 @@ def SecondForm(): def TestMenus(): - import PySimpleGUI as sg + sg.ChangeLookAndFeel('LightGreen') sg.SetOptions(element_padding=(0, 0)) # ------ Menu Definition ------ # - menu_def = [['&File', ['&Open', '&Save', '---', 'Properties', 'E&xit' ]], - ['&Edit', ['Paste', ['Special', 'Normal',], 'Undo'],], - ['' - '&Help', '&About...'],] + menu_def = [['&File', ['&Open', '&Save', '&Properties', 'E&xit' ]], + ['&Edit', ['&Paste', ['Special', 'Normal',], 'Undo'],], + ['&Toolbar', ['---', 'Command &1', 'Command &2', '---', 'Command &3', 'Command &4']], + ['&Help', '&About...'],] # ------ GUI Defintion ------ # layout = [ - [sg.Menu(menu_def, tearoff=False)], + [sg.Menu(menu_def, tearoff=True)], [sg.Output(size=(60,20))], [sg.In('Test', key='input', do_not_clear=True)] ] - window = sg.Window("Windows-like program", default_element_size=(12, 1), auto_size_text=False, auto_size_buttons=False, - default_button_element_size=(12, 1)).Layout(layout) + window = sg.Window("Windows-like program", default_element_size=(12, 1), auto_size_text=False, + auto_size_buttons=False, default_button_element_size=(12, 1)).Layout(layout) # ------ Loop & Process button menu choices ------ # while True: @@ -58,6 +58,4 @@ def TestMenus(): elif button == 'Properties': SecondForm() - - TestMenus() \ No newline at end of file diff --git a/Demo_Popups.py b/Demo_Popups.py index c55a55cd..be3455be 100644 --- a/Demo_Popups.py +++ b/Demo_Popups.py @@ -6,7 +6,7 @@ else: import PySimpleGUI27 as sg # Here, have some windows on me.... -[sg.PopupNoWait(location=(500+100*x,500)) for x in range(10)] +[sg.PopupNoWait('No-wait Popup', location=(500+100*x,500)) for x in range(10)] answer = sg.PopupYesNo('Do not worry about all those open windows... they will disappear at the end', 'Are you OK with that?') @@ -26,7 +26,6 @@ sg.Popup('Simple popup') sg.PopupNoTitlebar('No titlebar') sg.PopupNoBorder('No border') sg.PopupNoFrame('No frame') -# sg.PopupNoButtons('No Buttons') # don't mix with non-blocking... disaster ahead... sg.PopupCancel('Cancel') sg.PopupOKCancel('OK Cancel') sg.PopupAutoClose('Autoclose') diff --git a/Demo_Pyplot_Bar_Chart.py b/Demo_Pyplot_Bar_Chart.py index f927129b..e60322d1 100644 --- a/Demo_Pyplot_Bar_Chart.py +++ b/Demo_Pyplot_Bar_Chart.py @@ -31,10 +31,9 @@ If you want to change the GUI, make changes to the GUI portion marked below. import numpy as np import matplotlib.pyplot as plt -N = 5 values_to_plot = (20, 35, 30, 35, 27) -ind = np.arange(N) # the x locations for the groups -width = 0.4 # the width of the bars: can also be len(x) sequence +ind = np.arange(len(values_to_plot)) +width = 0.4 p1 = plt.bar(ind, values_to_plot, width) diff --git a/Demo_Script_Launcher.py b/Demo_Script_Launcher.py index 088aa5fc..9ee52fea 100644 --- a/Demo_Script_Launcher.py +++ b/Demo_Script_Launcher.py @@ -53,7 +53,7 @@ def Launcher2(): window.Layout(layout) - # ---===--- Loop taking in user input and using it to query HowDoI --- # + # ---===--- Loop taking in user input --- # while True: (button, value) = window.Read() if button in ('EXIT', None): diff --git a/Demo_YouTube_Intro.py b/Demo_YouTube_Intro.py new file mode 100644 index 00000000..cd61d71a --- /dev/null +++ b/Demo_YouTube_Intro.py @@ -0,0 +1,11 @@ +import PySimpleGUI as sg + +layout = [[sg.Text('What is your name?')], + [sg.InputText()], + [sg.Button('Ok')]] + +window = sg.Window('Title of Window').Layout(layout) + +button, values = window.Read() + +sg.Popup('Hello {}'.format(values[0])) \ No newline at end of file diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 5423e238..d0a0fa3f 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -15,6 +15,7 @@ else: import tkFont import ScrolledText + import types import datetime import textwrap @@ -218,6 +219,7 @@ ELEM_TYPE_MENUBAR = 600 ELEM_TYPE_PROGRESS_BAR = 200 ELEM_TYPE_BLANK = 100 ELEM_TYPE_TABLE = 700 +ELEM_TYPE_TREE = 800 ELEM_TYPE_ERROR = 666 # ------------------------- Popup Buttons Types ------------------------- # @@ -2045,7 +2047,7 @@ class Menu(Element): # Table # # ---------------------------------------------------------------------- # class Table(Element): - def __init__(self, values, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, scrollable=None, font=None, justification='right', text_color=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): + def __init__(self, values, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, font=None, justification='right', text_color=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): self.Values = values self.ColumnHeadings = headings self.ColumnsToDisplay = visible_column_map @@ -2056,7 +2058,6 @@ class Table(Element): self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.TextColor = text_color self.Justification = justification - self.Scrollable = scrollable self.InitialState = None self.SelectMode = select_mode self.DisplayRowNumbers = display_row_numbers @@ -2070,6 +2071,37 @@ class Table(Element): super().__del__() + +# ---------------------------------------------------------------------- # +# Tree # +# ---------------------------------------------------------------------- # +class Tree(Element): + def __init__(self, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, font=None, justification='right', text_color=None, background_color=None, num_rows=None, pad=None, key=None, tooltip=None): + self.ColumnHeadings = headings + self.ColumnsToDisplay = visible_column_map + self.ColumnWidths = col_widths + self.MaxColumnWidth = max_col_width + self.DefaultColumnWidth = def_col_width + self.AutoSizeColumns = auto_size_columns + self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR + self.TextColor = text_color + self.Justification = justification + self.InitialState = None + self.SelectMode = select_mode + self.NumRows = num_rows + self.TKTreeview = None + + super().__init__(ELEM_TYPE_TREE, text_color=text_color, background_color=background_color, font=font, pad=pad, key=key, tooltip=tooltip) + return + + + def __del__(self): + super().__del__() + + + + + # ---------------------------------------------------------------------- # # Error Element # # ---------------------------------------------------------------------- # @@ -2914,9 +2946,11 @@ else: AddMenuItem(top_menu, item, element) i += 1 +# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ # # ===================================== TK CODE STARTS HERE ====================================================== # # ------------------------------------------------------------------------------------------------------------------ # +# ------------------------------------------------------------------------------------------------------------------ # def PackFormIntoFrame(form, containing_frame, toplevel_form): def CharWidthInPixels(): @@ -3560,6 +3594,48 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKTreeview.pack(side=tk.LEFT,expand=True, padx=0, pady=0, fill='both') if element.Tooltip is not None: element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) + # ------------------------- Tree element ------------------------- # + elif element_type == ELEM_TYPE_TREE: + width, height = element_size + if element.Justification == 'left': # justification + anchor = tk.W + elif element.Justification == 'right': + anchor = tk.E + else: + anchor = tk.CENTER + + if element.ColumnsToDisplay is None: # Which cols to display + displaycolumns = element.ColumnHeadings + else: + displaycolumns = [] + for i, should_display in enumerate(element.ColumnsToDisplay): + if should_display: + displaycolumns.append(element.ColumnHeadings[i]) + column_headings= element.ColumnHeadings + # ------------- GET THE TREEVIEW WIDGET ------------- + element.TKTreeview = ttk.Treeview(tk_row_frame, columns=column_headings, + displaycolumns=displaycolumns, show='headings', height=height, selectmode=element.SelectMode) + treeview = element.TKTreeview + for i, heading in enumerate(element.ColumnHeadings): # Configure cols + headings + treeview.heading(heading, text=heading) + if element.AutoSizeColumns: + width = min(element.MaxColumnWidth, len(heading)) + else: + try: + width = element.ColumnWidths[i] + except: + width = element.DefaultColumnWidth + treeview.column(heading, width=width*CharWidthInPixels(), anchor=anchor) + # ----- configure colors ----- + if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: + ttk.Style().configure("Treeview", background=element.BackgroundColor, fieldbackground=element.BackgroundColor) + if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: + ttk.Style().configure("Treeview", foreground=element.TextColor) + + element.TKTreeview.pack(side=tk.LEFT,expand=True, padx=0, pady=0, fill='both') + if element.Tooltip is not None: # tooltip + element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) + #............................DONE WITH ROW pack the row of widgets ..........................# # done with row, pack the row of widgets # tk_row_frame.grid(row=row_num+2, sticky=tk.NW, padx=DEFAULT_MARGINS[0]) @@ -4385,7 +4461,6 @@ def SetOptions(icon=None, button_color=None, element_size=(None,None), button_el # of the elements. # ############################################################## LOOK_AND_FEEL_TABLE = {'SystemDefault': {'BACKGROUND' : COLOR_SYSTEM_DEFAULT, 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT': COLOR_SYSTEM_DEFAULT,'TEXT_INPUT' : COLOR_SYSTEM_DEFAULT, 'SCROLL': COLOR_SYSTEM_DEFAULT, 'BUTTON': OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR, 'PROGRESS': COLOR_SYSTEM_DEFAULT, 'BORDER': 1,'SLIDER_DEPTH':1, 'PROGRESS_DEPTH':0}, - # ∩(^-^)∩ 'Topanga': {'BACKGROUND': '#282923', 'TEXT': '#E7DB74', 'INPUT': '#393a32', 'TEXT_INPUT': '#E7C855','SCROLL': '#E7C855', 'BUTTON': ('#E7C855', '#284B5A'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1,'SLIDER_DEPTH':0, 'PROGRESS_DEPTH':0}, diff --git a/PySimpleGUI27.py b/PySimpleGUI27.py index a757522c..befb8316 100644 --- a/PySimpleGUI27.py +++ b/PySimpleGUI27.py @@ -27,6 +27,7 @@ else: import tkinter.font import tkinter.scrolledtext + import types import datetime import textwrap @@ -149,6 +150,14 @@ TITLE_LOCATION_TOP_RIGHT = tk.NE TITLE_LOCATION_BOTTOM_LEFT = tk.SW TITLE_LOCATION_BOTTOM_RIGHT = tk.SE +THEME_DEFAULT = 'default' +THEME_WINNATIVE = 'winnative' +THEME_CLAM = 'clam' +THEME_ALT = 'alt' +THEME_CLASSIC = 'classic' +THEME_VISTA = 'vista' +THEME_XPNATIVE = 'xpnative' + # DEFAULT_METER_ORIENTATION = 'Vertical' # ----====----====----==== Constants the user should NOT f-with ====----====----====----# @@ -222,6 +231,7 @@ ELEM_TYPE_MENUBAR = 600 ELEM_TYPE_PROGRESS_BAR = 200 ELEM_TYPE_BLANK = 100 ELEM_TYPE_TABLE = 700 +ELEM_TYPE_TREE = 800 ELEM_TYPE_ERROR = 666 # ------------------------- Popup Buttons Types ------------------------- # @@ -623,7 +633,6 @@ class Listbox(Element): self.Values = values - def SetValue(self, values): for index, item in enumerate(self.Values): try: @@ -634,6 +643,9 @@ class Listbox(Element): except: pass self.DefaultValues = values + def GetListValues(self): + return self.Values + def __del__(self): try: self.TKListBox.__del__() @@ -897,7 +909,7 @@ T = Text # ---------------------------------------------------------------------- # class TKProgressBar(object): - def __init__(self, root, max, length=400, width=DEFAULT_PROGRESS_BAR_SIZE[1], style=DEFAULT_PROGRESS_BAR_STYLE, relief=DEFAULT_PROGRESS_BAR_RELIEF, border_width=DEFAULT_PROGRESS_BAR_BORDER_WIDTH, orientation='horizontal', BarColor=(None,None)): + def __init__(self, root, max, length=400, width=DEFAULT_PROGRESS_BAR_SIZE[1], style=DEFAULT_PROGRESS_BAR_STYLE, relief=DEFAULT_PROGRESS_BAR_RELIEF, border_width=DEFAULT_PROGRESS_BAR_BORDER_WIDTH, orientation='horizontal', BarColor=(None,None), key=None): self.Length = length self.Width = width self.Max = max @@ -909,11 +921,11 @@ class TKProgressBar(object): s = tkinter.ttk.Style() s.theme_use(style) if BarColor != COLOR_SYSTEM_DEFAULT: - s.configure(str(length)+str(width)+"my.Horizontal.TProgressbar", background=BarColor[0], troughcolor=BarColor[1], troughrelief=relief, borderwidth=border_width, thickness=width) + s.configure(str(key)+"my.Horizontal.TProgressbar", background=BarColor[0], troughcolor=BarColor[1], troughrelief=relief, borderwidth=border_width, thickness=width) else: - s.configure(str(length)+str(width)+"my.Horizontal.TProgressbar", troughrelief=relief, borderwidth=border_width, thickness=width) + s.configure(str(key)+"my.Horizontal.TProgressbar", troughrelief=relief, borderwidth=border_width, thickness=width) - self.TKProgressBarForReal = tkinter.ttk.Progressbar(root, maximum=self.Max, style=str(length)+str(width)+'my.Horizontal.TProgressbar', length=length, orient=tk.HORIZONTAL, mode='determinate') + self.TKProgressBarForReal = tkinter.ttk.Progressbar(root, maximum=self.Max, style=str(key)+'my.Horizontal.TProgressbar', length=length, orient=tk.HORIZONTAL, mode='determinate') else: s = tkinter.ttk.Style() s.theme_use(style) @@ -1154,8 +1166,7 @@ class Button(Element): self.ParentForm.LastButtonClicked = self.ButtonText self.ParentForm.FormRemainedOpen = True self.ParentForm.TKroot.quit() # kick the users out of the mainloop - elif self.BType == BUTTON_TYPE_CLOSES_WIN_ONLY: # this is a return type button so GET RESULTS and destroy window - # if the form is tabbed, must collect all form's results and destroy all forms + elif self.BType == BUTTON_TYPE_CLOSES_WIN_ONLY: # special kind of button that does not exit main loop self.ParentForm._Close() if self.ParentForm.NonBlocking: self.ParentForm.TKroot.destroy() @@ -1494,7 +1505,7 @@ class Frame(Element): # Tab # # ---------------------------------------------------------------------- # class Tab(Element): - def __init__(self, title, layout, title_color=None, background_color=None, font=None, pad=None, border_width=None, key=None, tooltip=None): + def __init__(self, title, layout, title_color=None, background_color=None, font=None, pad=None, disabled=False, border_width=None, key=None, tooltip=None): self.UseDictionary = False self.ReturnValues = None @@ -1506,6 +1517,9 @@ class Tab(Element): self.TKFrame = None self.Title = title self.BorderWidth = border_width + self.Disabled = disabled + self.ParentNotebook = None + self.TabID = None self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.Layout(layout) @@ -1531,6 +1545,15 @@ class Tab(Element): def Layout(self, rows): for row in rows: self.AddRow(*row) + return self + + def Update(self, disabled = None): # TODO Disable / enable of tabs is not complete + if disabled is None: + return + self.Disabled = disabled + state = 'disabled' if disabled is True else 'normal' + self.ParentNotebook.tab(self.TabID, state=state) + return self def _GetElementAtLocation(self, location): (row_num,col_num) = location @@ -1551,7 +1574,7 @@ class Tab(Element): # TabGroup # # ---------------------------------------------------------------------- # class TabGroup(Element): - def __init__(self, layout, tab_location=None, title_color=None, background_color=None, font=None, change_submits=False, pad=None, border_width=None, key=None, tooltip=None): + def __init__(self, layout, tab_location=None, title_color=None, selected_title_color=None, background_color=None, font=None, change_submits=False, pad=None, border_width=None, theme=None, key=None, tooltip=None): self.UseDictionary = False self.ReturnValues = None @@ -1559,9 +1582,12 @@ class TabGroup(Element): self.ReturnValuesDictionary = {} self.DictionaryKeyCounter = 0 self.ParentWindow = None + self.SelectedTitleColor = selected_title_color self.Rows = [] self.TKNotebook = None + self.TabCount = 0 self.BorderWidth = border_width + self.Theme = theme self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.ChangeSubmits = change_submits self.TabLocation = tab_location @@ -2033,7 +2059,7 @@ class Menu(Element): # Table # # ---------------------------------------------------------------------- # class Table(Element): - def __init__(self, values, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, scrollable=None, font=None, justification='right', text_color=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): + def __init__(self, values, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, font=None, justification='right', text_color=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): self.Values = values self.ColumnHeadings = headings self.ColumnsToDisplay = visible_column_map @@ -2044,7 +2070,6 @@ class Table(Element): self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.TextColor = text_color self.Justification = justification - self.Scrollable = scrollable self.InitialState = None self.SelectMode = select_mode self.DisplayRowNumbers = display_row_numbers @@ -2058,6 +2083,37 @@ class Table(Element): super().__del__() + +# ---------------------------------------------------------------------- # +# Tree # +# ---------------------------------------------------------------------- # +class Tree(Element): + def __init__(self, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, font=None, justification='right', text_color=None, background_color=None, num_rows=None, pad=None, key=None, tooltip=None): + self.ColumnHeadings = headings + self.ColumnsToDisplay = visible_column_map + self.ColumnWidths = col_widths + self.MaxColumnWidth = max_col_width + self.DefaultColumnWidth = def_col_width + self.AutoSizeColumns = auto_size_columns + self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR + self.TextColor = text_color + self.Justification = justification + self.InitialState = None + self.SelectMode = select_mode + self.NumRows = num_rows + self.TKTreeview = None + + super().__init__(ELEM_TYPE_TREE, text_color=text_color, background_color=background_color, font=font, pad=pad, key=key, tooltip=tooltip) + return + + + def __del__(self): + super().__del__() + + + + + # ---------------------------------------------------------------------- # # Error Element # # ---------------------------------------------------------------------- # @@ -2078,11 +2134,9 @@ class ErrorElement(Element): return self - def MenuItemChosenCallback(self, item_chosen): - # print('IN MENU ITEM CALLBACK', item_chosen) - self.ParentForm.LastButtonClicked = item_chosen - self.ParentForm.FormRemainedOpen = True - self.ParentForm.TKroot.quit() # kick the users out of the mainloop + def Get(self): + return 'This is NOT a valid Element!\nSTOP trying to do things with it or I will have to crash at some point!' + def __del__(self): super().__del__() @@ -2227,9 +2281,12 @@ class Window(object): else: window = self if window: - window._Close() - self.TKroot.quit() - self.RootNeedsDestroying = True + if window.NonBlocking: + self.CloseNonBlockingForm() + else: + window._Close() + self.TKroot.quit() + self.RootNeedsDestroying = True except: pass @@ -2472,6 +2529,14 @@ class UberForm(object): def __del__(self): return +# ################################################################################ +# ################################################################################ +# END OF ELEMENT DEFINITIONS +# ################################################################################ +# ################################################################################ + + + # =========================================================================== # # Button Lazy Functions so the caller doesn't have to define a bunch of stuff # # =========================================================================== # @@ -2893,9 +2958,11 @@ else: AddMenuItem(top_menu, item, element) i += 1 +# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ # # ===================================== TK CODE STARTS HERE ====================================================== # # ------------------------------------------------------------------------------------------------------------------ # +# ------------------------------------------------------------------------------------------------------------------ # def PackFormIntoFrame(form, containing_frame, toplevel_form): def CharWidthInPixels(): @@ -3160,7 +3227,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TooltipObject = ToolTip(element.TKOptionMenu, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- LISTBOX element ------------------------- # elif element_type == ELEM_TYPE_INPUT_LISTBOX: - max_line_len = max([len(str(l)) for l in element.Values]) + max_line_len = max([len(str(l)) for l in element.Values]) if len(element.Values) != 0 else 0 if auto_size_text is False: width=element_size[0] else: width = max_line_len listbox_frame = tk.Frame(tk_row_frame) @@ -3242,7 +3309,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): bar_color = element.BarColor else: bar_color = DEFAULT_PROGRESS_BAR_COLOR - element.TKProgressBar = TKProgressBar(tk_row_frame, element.MaxValue, progress_length, progress_width, orientation=direction, BarColor=bar_color, border_width=element.BorderWidth, relief=element.Relief, style=element.BarStyle ) + element.TKProgressBar = TKProgressBar(tk_row_frame, element.MaxValue, progress_length, progress_width, orientation=direction, BarColor=bar_color, border_width=element.BorderWidth, relief=element.Relief, style=element.BarStyle, key=element.Key ) element.TKProgressBar.TKProgressBarForReal.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # ------------------------- INPUT RADIO BUTTON element ------------------------- # elif element_type == ELEM_TYPE_INPUT_RADIO: @@ -3383,15 +3450,27 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): elif element_type == ELEM_TYPE_TAB: element.TKFrame = tk.Frame(form.TKNotebook) PackFormIntoFrame(element, element.TKFrame, toplevel_form) - form.TKNotebook.add(element.TKFrame, text=element.Title) + if element.Disabled: + form.TKNotebook.add(element.TKFrame, text=element.Title, state='disabled') + else: + form.TKNotebook.add(element.TKFrame, text=element.Title) form.TKNotebook.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) - + element.ParentNotebook = form.TKNotebook + element.TabID = form.TabCount + form.TabCount += 1 if element.BackgroundColor != COLOR_SYSTEM_DEFAULT and element.BackgroundColor is not None: element.TKFrame.configure(background=element.BackgroundColor, highlightbackground=element.BackgroundColor, highlightcolor=element.BackgroundColor) # if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None: # element.TKFrame.configure(foreground=element.TextColor) + + # ttk.Style().configure("TNotebook", background='red') + # ttk.Style().map("TNotebook.Tab", background=[("selected", 'orange')], + # foreground=[("selected", 'green')]) + # ttk.Style().configure("TNotebook.Tab", background='blue', foreground='yellow') + + if element.BorderWidth is not None: element.TKFrame.configure(borderwidth=element.BorderWidth) if element.Tooltip is not None: @@ -3400,20 +3479,37 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): # ------------------------- TabGroup element ------------------------- # elif element_type == ELEM_TYPE_TAB_GROUP: + custom_style = str(element.Key)+'customtab.TNotebook' + style = tkinter.ttk.Style(tk_row_frame) + if element.Theme is not None: + style.theme_use(element.Theme) if element.TabLocation is not None: - style = tkinter.ttk.Style(tk_row_frame) - if element.TabLocation == 'left': - style.configure('customtab.TNotebook', tabposition='ws') - elif element.TabLocation == 'right': - style.configure('customtab.TNotebook', tabposition='es') - elif element.TabLocation == 'top': - style.configure('customtab.TNotebook', tabposition='nw') - elif element.TabLocation == 'bottom': - style.configure('customtab.TNotebook', tabposition='sw') + position_dict = {'left':'w','right':'e', 'top':'n', 'bottom':'s', 'lefttop':'wn', 'leftbottom':'ws', 'righttop':'en', 'rightbottom':'es', 'bottomleft':'sw', 'bottomright':'se', 'topleft':'nw', 'topright':'ne'} + try: + tab_position = position_dict[element.TabLocation] + except: + tab_position = position_dict['top'] + style.configure(custom_style, tabposition=tab_position) - element.TKNotebook = tkinter.ttk.Notebook(tk_row_frame, style='customtab.TNotebook') - else: - element.TKNotebook = tkinter.ttk.Notebook(tk_row_frame) + if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: + style.configure(custom_style, background=element.BackgroundColor, foreground='purple') + + # style.theme_create("yummy", parent="alt", settings={ + # "TNotebook": {"configure": {"tabmargins": [2, 5, 2, 0]}}, + # "TNotebook.Tab": { + # "configure": {"padding": [5, 1], "background": mygreen}, + # "map": {"background": [("selected", myred)], + # "expand": [("selected", [1, 1, 1, 0])]}}}) + + # style.configure(custom_style+'.Tab', background='red') + if element.SelectedTitleColor != None: + style.map(custom_style+'.Tab', foreground=[("selected",element.SelectedTitleColor)]) + if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: + style.configure(custom_style+'.Tab', foreground=element.TextColor) + # style.configure(custom_style, background='blue', foreground='yellow') + + + element.TKNotebook = tkinter.ttk.Notebook(tk_row_frame, style=custom_style) PackFormIntoFrame(element, toplevel_form.TKroot, toplevel_form) @@ -3510,6 +3606,48 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKTreeview.pack(side=tk.LEFT,expand=True, padx=0, pady=0, fill='both') if element.Tooltip is not None: element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) + # ------------------------- Tree element ------------------------- # + elif element_type == ELEM_TYPE_TREE: + width, height = element_size + if element.Justification == 'left': # justification + anchor = tk.W + elif element.Justification == 'right': + anchor = tk.E + else: + anchor = tk.CENTER + + if element.ColumnsToDisplay is None: # Which cols to display + displaycolumns = element.ColumnHeadings + else: + displaycolumns = [] + for i, should_display in enumerate(element.ColumnsToDisplay): + if should_display: + displaycolumns.append(element.ColumnHeadings[i]) + column_headings= element.ColumnHeadings + # ------------- GET THE TREEVIEW WIDGET ------------- + element.TKTreeview = tkinter.ttk.Treeview(tk_row_frame, columns=column_headings, + displaycolumns=displaycolumns, show='headings', height=height, selectmode=element.SelectMode) + treeview = element.TKTreeview + for i, heading in enumerate(element.ColumnHeadings): # Configure cols + headings + treeview.heading(heading, text=heading) + if element.AutoSizeColumns: + width = min(element.MaxColumnWidth, len(heading)) + else: + try: + width = element.ColumnWidths[i] + except: + width = element.DefaultColumnWidth + treeview.column(heading, width=width*CharWidthInPixels(), anchor=anchor) + # ----- configure colors ----- + if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: + tkinter.ttk.Style().configure("Treeview", background=element.BackgroundColor, fieldbackground=element.BackgroundColor) + if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: + tkinter.ttk.Style().configure("Treeview", foreground=element.TextColor) + + element.TKTreeview.pack(side=tk.LEFT,expand=True, padx=0, pady=0, fill='both') + if element.Tooltip is not None: # tooltip + element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) + #............................DONE WITH ROW pack the row of widgets ..........................# # done with row, pack the row of widgets # tk_row_frame.grid(row=row_num+2, sticky=tk.NW, padx=DEFAULT_MARGINS[0]) @@ -3961,7 +4099,7 @@ class DebugWin(object): self.output_element = Output(size=win_size) self.form_rows = [[Text('EasyPrint Output')], [self.output_element], - [Quit()]] + [DummyButton('Quit')]] self.form.AddRows(self.form_rows) self.form.Show(non_blocking=True) # Show a ;non-blocking form, returns immediately return @@ -4406,13 +4544,10 @@ def SetOptions(icon=None, button_color=None, element_size=(None,None), button_el # Predefined settings that will change the colors and styles # # of the elements. # ############################################################## -def ChangeLookAndFeel(index): - if sys.platform == 'darwin': - print('*** Changing look and feel is not supported on Mac platform ***') - return - - # look and feel table - look_and_feel = {'SystemDefault': {'BACKGROUND' : COLOR_SYSTEM_DEFAULT, 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT': COLOR_SYSTEM_DEFAULT,'TEXT_INPUT' : COLOR_SYSTEM_DEFAULT, 'SCROLL': COLOR_SYSTEM_DEFAULT, 'BUTTON': OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR, 'PROGRESS': COLOR_SYSTEM_DEFAULT, 'BORDER': 1,'SLIDER_DEPTH':1, 'PROGRESS_DEPTH':0}, +LOOK_AND_FEEL_TABLE = {'SystemDefault': {'BACKGROUND' : COLOR_SYSTEM_DEFAULT, 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT': COLOR_SYSTEM_DEFAULT,'TEXT_INPUT' : COLOR_SYSTEM_DEFAULT, 'SCROLL': COLOR_SYSTEM_DEFAULT, 'BUTTON': OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR, 'PROGRESS': COLOR_SYSTEM_DEFAULT, 'BORDER': 1,'SLIDER_DEPTH':1, 'PROGRESS_DEPTH':0}, + 'Topanga': {'BACKGROUND': '#282923', 'TEXT': '#E7DB74', 'INPUT': '#393a32', + 'TEXT_INPUT': '#E7C855','SCROLL': '#E7C855', 'BUTTON': ('#E7C855', '#284B5A'), + 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1,'SLIDER_DEPTH':0, 'PROGRESS_DEPTH':0}, 'GreenTan': {'BACKGROUND' : '#9FB8AD', 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT':'#F7F3EC','TEXT_INPUT' : 'black','SCROLL': '#F7F3EC', 'BUTTON': ('white', '#475841'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1,'SLIDER_DEPTH':0, 'PROGRESS_DEPTH':0}, @@ -4497,8 +4632,18 @@ def ChangeLookAndFeel(index): 'TealMono': {'BACKGROUND': '#a8cfdd', 'TEXT': 'black', 'INPUT': '#dfedf2','SCROLL': '#dfedf2', 'TEXT_INPUT' : 'black', 'BUTTON': ('white', '#183440'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1,'SLIDER_DEPTH':0, 'PROGRESS_DEPTH':0} } + +def ChangeLookAndFeel(index): + global LOOK_AND_FEEL_TABLE + + if sys.platform == 'darwin': + print('*** Changing look and feel is not supported on Mac platform ***') + return + + # look and feel table + try: - colors = look_and_feel[index] + colors = LOOK_AND_FEEL_TABLE[index] SetOptions(background_color=colors['BACKGROUND'], text_element_background_color=colors['BACKGROUND'], @@ -4607,7 +4752,7 @@ def Popup(*args, **_3to2kwargs): else: local_line_width = MESSAGE_BOX_LINE_WIDTH title = args_to_print[0] if args_to_print[0] is not None else 'None' - form = Window(title, auto_size_text=True, background_color=background_color, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, icon=icon, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) + window = Window(title, auto_size_text=True, background_color=background_color, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, icon=icon, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) max_line_total, total_lines = 0,0 for message in args_to_print: # fancy code to check if string and convert if not is not need. Just always convert to string :-) @@ -4623,34 +4768,32 @@ def Popup(*args, **_3to2kwargs): max_line_total = max(max_line_total, width_used) # height = _GetNumLinesNeeded(message, width_used) height = message_wrapped_lines - form.AddRow(Text(message_wrapped, auto_size_text=True, text_color=text_color, background_color=background_color)) + window.AddRow(Text(message_wrapped, auto_size_text=True, text_color=text_color, background_color=background_color)) total_lines += height - pad = max_line_total-15 if max_line_total > 15 else 1 - pad =1 if non_blocking: - PopupButton = DummyButton + PopupButton = DummyButton # important to use or else button will close other windows too! else: - PopupButton = SimpleButton + PopupButton = Button # show either an OK or Yes/No depending on paramater if button_type is POPUP_BUTTONS_YES_NO: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False, text_color=text_color, background_color=background_color), PopupButton('Yes', button_color=button_color, focus=True, bind_return_key=True), PopupButton('No', button_color=button_color)) + window.AddRow(PopupButton('Yes', button_color=button_color, focus=True, bind_return_key=True, pad=((20,5),3)), PopupButton('No', button_color=button_color)) elif button_type is POPUP_BUTTONS_CANCELLED: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False, text_color=text_color, background_color=background_color), PopupButton('Cancelled', button_color=button_color, focus=True, bind_return_key=True)) + window.AddRow(PopupButton('Cancelled', button_color=button_color, focus=True, bind_return_key=True, pad=((20,0),3))) elif button_type is POPUP_BUTTONS_ERROR: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False, text_color=text_color, background_color=background_color), PopupButton('Error', size=(6, 1), button_color=button_color, focus=True, bind_return_key=True)) + window.AddRow(PopupButton('Error', size=(6,1), button_color=button_color, focus=True, bind_return_key=True, pad=((20,0),3))) elif button_type is POPUP_BUTTONS_OK_CANCEL: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False, text_color=text_color, background_color=background_color), PopupButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True), - PopupButton('Cancel', size=(5, 1), button_color=button_color)) + window.AddRow(PopupButton('OK', size=(5,1), button_color=button_color, focus=True, bind_return_key=True), + PopupButton('Cancel', size=(5,1), button_color=button_color)) elif button_type is POPUP_BUTTONS_NO_BUTTONS: pass else: - form.AddRow(Text('', size=(pad, 1), auto_size_text=False, background_color=background_color), PopupButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True)) + window.AddRow(PopupButton('OK', size=(5,1), button_color=button_color, focus=True, bind_return_key=True, pad=((20,0),3))) if non_blocking: - button, values = form.ReadNonBlocking() + button, values = window.ReadNonBlocking() else: - button, values = form.Show() + button, values = window.Show() return button @@ -4773,6 +4916,61 @@ def PopupNonBlocking(*args, **_3to2kwargs): PopupNoWait = PopupNonBlocking + +# --------------------------- PopupQuick - a NonBlocking, Self-closing Popup --------------------------- +def PopupQuick(*args, **_3to2kwargs): + if 'location' in _3to2kwargs: location = _3to2kwargs['location']; del _3to2kwargs['location'] + else: location = (None,None) + if 'keep_on_top' in _3to2kwargs: keep_on_top = _3to2kwargs['keep_on_top']; del _3to2kwargs['keep_on_top'] + else: keep_on_top = False + if 'grab_anywhere' in _3to2kwargs: grab_anywhere = _3to2kwargs['grab_anywhere']; del _3to2kwargs['grab_anywhere'] + else: grab_anywhere = False + if 'no_titlebar' in _3to2kwargs: no_titlebar = _3to2kwargs['no_titlebar']; del _3to2kwargs['no_titlebar'] + else: no_titlebar = False + if 'font' in _3to2kwargs: font = _3to2kwargs['font']; del _3to2kwargs['font'] + else: font = None + if 'line_width' in _3to2kwargs: line_width = _3to2kwargs['line_width']; del _3to2kwargs['line_width'] + else: line_width = None + if 'icon' in _3to2kwargs: icon = _3to2kwargs['icon']; del _3to2kwargs['icon'] + else: icon = DEFAULT_WINDOW_ICON + if 'non_blocking' in _3to2kwargs: non_blocking = _3to2kwargs['non_blocking']; del _3to2kwargs['non_blocking'] + else: non_blocking = True + if 'auto_close_duration' in _3to2kwargs: auto_close_duration = _3to2kwargs['auto_close_duration']; del _3to2kwargs['auto_close_duration'] + else: auto_close_duration = 1 + if 'auto_close' in _3to2kwargs: auto_close = _3to2kwargs['auto_close']; del _3to2kwargs['auto_close'] + else: auto_close = True + if 'text_color' in _3to2kwargs: text_color = _3to2kwargs['text_color']; del _3to2kwargs['text_color'] + else: text_color = None + if 'background_color' in _3to2kwargs: background_color = _3to2kwargs['background_color']; del _3to2kwargs['background_color'] + else: background_color = None + if 'button_color' in _3to2kwargs: button_color = _3to2kwargs['button_color']; del _3to2kwargs['button_color'] + else: button_color = None + if 'button_type' in _3to2kwargs: button_type = _3to2kwargs['button_type']; del _3to2kwargs['button_type'] + else: button_type = POPUP_BUTTONS_OK + """ + Show Popup box that doesn't block and closes itself + :param args: + :param button_type: + :param button_color: + :param background_color: + :param text_color: + :param auto_close: + :param auto_close_duration: + :param non_blocking: + :param icon: + :param line_width: + :param font: + :param no_titlebar: + :param grab_anywhere: + :param keep_on_top: + :param location: + :return: + """ + Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=button_type, + auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, + font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) + + # --------------------------- PopupNoTitlebar --------------------------- def PopupNoTitlebar(*args, **_3to2kwargs): if 'location' in _3to2kwargs: location = _3to2kwargs['location']; del _3to2kwargs['location'] diff --git a/docs/index.md b/docs/index.md index 65a8ba65..2e9e386b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,9 +21,9 @@ ## Now supports both Python 2.7 & 3 -![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.9.0-red.svg?longCache=true&style=for-the-badge) +![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.9.1-red.svg?longCache=true&style=for-the-badge) - ![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.1.0-blue.svg?longCache=true&style=for-the-badge) + ![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.1.2-blue.svg?longCache=true&style=for-the-badge) [Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142) @@ -2774,6 +2774,8 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it | 03.08.04 | Sept 30, 2018 - See release notes | 03.09.00 | Oct 1, 2018 | | 2.7 01.01.00 | Oct 1, 2018 +| 2.7 01.01.02 | Oct 8, 2018 +| 03.09.01 | Oct 8, 2018 @@ -2905,6 +2907,20 @@ It's official. There is a 2.7 version of PySimpleGUI! * Python 2.7 got a TON of features . Look back to 1.0 release for the list * Tab locations - Can place Tabs on top, bottom, left, right now instead of only the top +### 3.9.1 & 1.1.2 +* Tab features + * Themes + * Enable / Disable + * Tab text colors + * Selected tab color +* New GetListValues method for Listbox +* Can now have multiple progress bars in 1 window +* Fix for closing debug-output window with other windows open +* Topanga Look and Feel setting +* User can create new look and feel settings / can access the look and feel table +* New PopupQuick call. Shows a non-blocking popup window with auto-close +* Tree Element partially done (don't use despite it showing up) + ### Upcoming Make suggestions people! Future release features @@ -2943,6 +2959,9 @@ Want to view your form's results as a dictionary instead of a list... no problem You can also look up elements using their keys. This is an excellent way to update elements in reaction to another element. Call `form.FindElement(key)` to get the Element. +**Named / Optional Parameters** +This is a language feature that is featured **heavily** in all of the API calls, both functions and classes. Elements are configured, in-place, by setting one or more optional parameters. For example, a Text element's color is chosen by setting the optional `text_color` parameter. + ## Author MikeTheWatchGuy @@ -2970,7 +2989,7 @@ GNU Lesser General Public License (LGPL 3) + * one of the most critical constructs in PySimpleGUI * [venim](https://github.com/venim) code to doing Alt-Selections in menus, updating Combobox using index, request to disable windows (a really good idea), checkbox and tab submits on change, returning keys for elements that have change_submits set, ... * [rtrrtr](https://github.com/rtrrtr) Helped get the 2.7 and 3.x code unified (big damned deal) - +* Tony Crewe (anthony.crewe@gmail.com) Generously provided his classroom materials that he has written to teach a GUI course. If you're an educator and want to trade materials with Tony, he would like to hear from you. ## How Do I Finally, I must thank the fine folks at How Do I. diff --git a/readme.md b/readme.md index 65a8ba65..2e9e386b 100644 --- a/readme.md +++ b/readme.md @@ -21,9 +21,9 @@ ## Now supports both Python 2.7 & 3 -![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.9.0-red.svg?longCache=true&style=for-the-badge) +![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.9.1-red.svg?longCache=true&style=for-the-badge) - ![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.1.0-blue.svg?longCache=true&style=for-the-badge) + ![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.1.2-blue.svg?longCache=true&style=for-the-badge) [Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142) @@ -2774,6 +2774,8 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it | 03.08.04 | Sept 30, 2018 - See release notes | 03.09.00 | Oct 1, 2018 | | 2.7 01.01.00 | Oct 1, 2018 +| 2.7 01.01.02 | Oct 8, 2018 +| 03.09.01 | Oct 8, 2018 @@ -2905,6 +2907,20 @@ It's official. There is a 2.7 version of PySimpleGUI! * Python 2.7 got a TON of features . Look back to 1.0 release for the list * Tab locations - Can place Tabs on top, bottom, left, right now instead of only the top +### 3.9.1 & 1.1.2 +* Tab features + * Themes + * Enable / Disable + * Tab text colors + * Selected tab color +* New GetListValues method for Listbox +* Can now have multiple progress bars in 1 window +* Fix for closing debug-output window with other windows open +* Topanga Look and Feel setting +* User can create new look and feel settings / can access the look and feel table +* New PopupQuick call. Shows a non-blocking popup window with auto-close +* Tree Element partially done (don't use despite it showing up) + ### Upcoming Make suggestions people! Future release features @@ -2943,6 +2959,9 @@ Want to view your form's results as a dictionary instead of a list... no problem You can also look up elements using their keys. This is an excellent way to update elements in reaction to another element. Call `form.FindElement(key)` to get the Element. +**Named / Optional Parameters** +This is a language feature that is featured **heavily** in all of the API calls, both functions and classes. Elements are configured, in-place, by setting one or more optional parameters. For example, a Text element's color is chosen by setting the optional `text_color` parameter. + ## Author MikeTheWatchGuy @@ -2970,7 +2989,7 @@ GNU Lesser General Public License (LGPL 3) + * one of the most critical constructs in PySimpleGUI * [venim](https://github.com/venim) code to doing Alt-Selections in menus, updating Combobox using index, request to disable windows (a really good idea), checkbox and tab submits on change, returning keys for elements that have change_submits set, ... * [rtrrtr](https://github.com/rtrrtr) Helped get the 2.7 and 3.x code unified (big damned deal) - +* Tony Crewe (anthony.crewe@gmail.com) Generously provided his classroom materials that he has written to teach a GUI course. If you're an educator and want to trade materials with Tony, he would like to hear from you. ## How Do I Finally, I must thank the fine folks at How Do I.