diff --git a/Demo_Canvas.py b/Demo_Canvas.py new file mode 100644 index 00000000..35eec494 --- /dev/null +++ b/Demo_Canvas.py @@ -0,0 +1,22 @@ +import PySimpleGUI as gui + +canvas = gui.Canvas(size=(100,100), background_color='red') + +layout = [ + [canvas], + [gui.T('Change circle color to:'), gui.ReadFormButton('Red'), gui.ReadFormButton('Blue')] + ] + +form = gui.FlexForm('Canvas test') +form.Layout(layout) +form.ReadNonBlocking() + +cir = canvas.TKCanvas.create_oval(50, 50, 100, 100) + +while True: + button, values = form.Read() + if button is None: break + if button is 'Blue': + canvas.TKCanvas.itemconfig(cir, fill = "Blue") + elif button is 'Red': + canvas.TKCanvas.itemconfig(cir, fill = "Red") diff --git a/Demo_Keypad.py b/Demo_Keypad.py index 3ca2afb4..124f34d0 100644 --- a/Demo_Keypad.py +++ b/Demo_Keypad.py @@ -2,22 +2,32 @@ import PySimpleGUI as g # g.SetOptions(button_color=g.COLOR_SYSTEM_DEFAULT) # because some people like gray buttons +# Demonstrates a number of PySimpleGUI features including: +# Default element size +# auto_size_buttons +# ReadFormButton +# Dictionary return values +# Update of elements in form (Text, Input) +# do_not_clear of Input elements + + # create the 2 Elements we want to control outside the form out_elem = g.Text('', size=(15, 1), font=('Helvetica', 18), text_color='red') in_elem = g.Input(size=(10,1), do_not_clear=True, key='input') -layout = [[g.Text('Choose Test'), g.DropDown(values=['Input', 'Output', 'Some option']), g.ReadFormButton('Input Option', size=(10,1))], +layout = [[g.Text('Choose Test'), g.DropDown(values=['Input', 'Output', 'Some option']), g.ReadFormButton('Input Option', auto_size_button=True)], [in_elem], - [g.ReadFormButton('1', size=(5,2)), g.ReadFormButton('2', size=(5,2)), g.ReadFormButton('3', size=(5,2))], - [g.ReadFormButton('4', size=(5,2)), g.ReadFormButton('5', size=(5,2)), g.ReadFormButton('6', size=(5,2))], - [g.ReadFormButton('7', size=(5,2)), g.ReadFormButton('8', size=(5,2)), g.ReadFormButton('9', size=(5,2))], - [g.ReadFormButton('Submit', size=(5,2)),g.ReadFormButton('0', size=(5,2)), g.ReadFormButton('Clear', size=(5,2))], + [g.ReadFormButton('1'), g.ReadFormButton('2'), g.ReadFormButton('3')], + [g.ReadFormButton('4'), g.ReadFormButton('5'), g.ReadFormButton('6')], + [g.ReadFormButton('7'), g.ReadFormButton('8'), g.ReadFormButton('9')], + [g.ReadFormButton('Submit'),g.ReadFormButton('0'), g.ReadFormButton('Clear')], [out_elem], ] -form = g.FlexForm('Keypad', auto_size_buttons=False) +form = g.FlexForm('Keypad', default_element_size=(5,2), auto_size_buttons=False) form.Layout(layout) +# Loop forever reading the form's values, updating the Input field keys_entered = '' while True: button, values = form.Read() # read the form @@ -26,10 +36,10 @@ while True: if button == 'Clear': # clear keys if clear button keys_entered = '' elif button in '1234567890': - keys_entered = 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 = in_elem.Get() + keys_entered = values['input'] out_elem.Update(keys_entered) # output the final string in_elem.Update(keys_entered) # change the form to reflect current key string diff --git a/Demo_PNG_Viewer.py b/Demo_PNG_Viewer.py index 4729d9c3..7d6bcd7d 100644 --- a/Demo_PNG_Viewer.py +++ b/Demo_PNG_Viewer.py @@ -4,54 +4,62 @@ import os # Simple Image Browser based on PySimpleGUI # Get the folder containing the images from the user -rc, folder = sg.GetPathBox('Image Browser', 'Image folder to open', default_path='A:/TEMP/PDFs') +rc, folder = sg.GetPathBox('Image Browser', 'Image folder to open', default_path='') if rc is False or folder is '': sg.MsgBoxCancel('Cancelling') exit(0) # get list of PNG files in folder png_files = [folder + '\\' + f for f in os.listdir(folder) if '.png' in f] +filenames_only = [f for f in os.listdir(folder) if '.png' in f] if len(png_files) == 0: sg.MsgBox('No PNG images in folder') exit(0) # create the form that also returns keyboard events -form = sg.FlexForm('Image Browser', return_keyboard_events=True) +form = sg.FlexForm('Image Browser', return_keyboard_events=True, location=(0,0), use_default_focus=False ) # make these 2 elements outside the layout because want to "update" them later # initialize to the first PNG file in the list image_elem = sg.Image(filename=png_files[0]) filename_display_elem = sg.Text(png_files[0], size=(80, 3)) -file_num_display_elem = sg.Text('File 1 of {}'.format(len(png_files)), size=(10,1)) +file_num_display_elem = sg.Text('File 1 of {}'.format(len(png_files)), size=(15,1)) # define layout, show and read the form -layout = [[filename_display_elem], +col = [[filename_display_elem], [image_elem], [sg.ReadFormButton('Next', size=(8,2)), sg.ReadFormButton('Prev', size=(8,2)), file_num_display_elem]] -form.LayoutAndRead(layout) # Shows form on screen +col_files = [[sg.Listbox(values=filenames_only, size=(60,30), key='listbox')], + [sg.ReadFormButton('Read')]] +layout = [[sg.Column(col_files), sg.Column(col)]] +button, values = form.LayoutAndRead(layout) # Shows form on screen # loop reading the user input and displaying image, filename i=0 while True: - f = png_files[i] - # update window with new image - image_elem.Update(filename=f) - # update window with filename - filename_display_elem.Update(f) - # update page display - file_num_display_elem.Update('File {} of {}'.format(i+1, len(png_files))) - # read the form - button, values = form.Read() # perform button and keyboard operations if button is None: break - elif button in ('Next', 'MouseWheel:Down', 'Down:40', 'Next:34') and i < len(png_files): + elif button in ('Next', 'MouseWheel:Down', 'Down:40', 'Next:34') and i < len(png_files)-1: i += 1 elif button in ('Prev', 'MouseWheel:Up', 'Up:38', 'Prior:33') and i > 0: i -= 1 + if button == 'Read': + filename = folder + '\\' + values['listbox'][0] + # print(filename) + else: + filename = png_files[i] + # update window with new image + image_elem.Update(filename=filename) + # update window with filename + filename_display_elem.Update(filename) + # update page display + file_num_display_elem.Update('File {} of {}'.format(i+1, len(png_files))) + # read the form + button, values = form.Read() diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 49ed1e5b..f7103fd7 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -139,6 +139,7 @@ ELEM_TYPE_INPUT_CHECKBOX = 8 ELEM_TYPE_INPUT_SPIN = 9 ELEM_TYPE_BUTTON = 3 ELEM_TYPE_IMAGE = 30 +ELEM_TYPE_CANVAS = 40 ELEM_TYPE_INPUT_SLIDER = 10 ELEM_TYPE_INPUT_LISTBOX = 11 ELEM_TYPE_OUTPUT = 300 @@ -542,12 +543,13 @@ class TKProgressBar(): # Scroll bar will span the length of the frame # # ---------------------------------------------------------------------- # class TKOutput(tk.Frame): - def __init__(self, parent, width, height, bd, background_color=None, text_color=None): - frame = tk.Frame(parent, width=width, height=height) + def __init__(self, parent, width, height, bd, background_color=None, text_color=None, font=None): + frame = tk.Frame(parent) tk.Frame.__init__(self, frame) - self.output = tk.Text(frame, width=width, height=height, bd=bd) + self.output = tk.Text(frame, width=width, height=height, bd=bd, font=font) if background_color and background_color != COLOR_SYSTEM_DEFAULT: self.output.configure(background=background_color) + frame.configure(background=background_color) if text_color and text_color != COLOR_SYSTEM_DEFAULT: self.output.configure(fg=text_color) self.vsb = tk.Scrollbar(frame, orient="vertical", command=self.output.yview) @@ -586,7 +588,7 @@ class TKOutput(tk.Frame): # Routes stdout, stderr to a scrolled window # # ---------------------------------------------------------------------- # class Output(Element): - def __init__(self, scale=(None, None), size=(None, None), background_color=None, text_color=None, pad=None): + def __init__(self, scale=(None, None), size=(None, None), background_color=None, text_color=None, pad=None, font=None): ''' Output Element - reroutes stdout, stderr to this window :param scale: Adds multiplier to size (w,h) @@ -597,7 +599,7 @@ class Output(Element): bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR - super().__init__(ELEM_TYPE_OUTPUT, scale=scale, size=size, background_color=bg, text_color=fg, pad=pad) + super().__init__(ELEM_TYPE_OUTPUT, scale=scale, size=size, background_color=bg, text_color=fg, pad=pad, font=font) def __del__(self): try: @@ -807,6 +809,28 @@ class Image(Element): def __del__(self): super().__del__() + +# ---------------------------------------------------------------------- # +# Canvas # +# ---------------------------------------------------------------------- # +class Canvas(Element): + def __init__(self, background_color=None, scale=(None, None), size=(None, None), pad=None): + ''' + Image Element + :param filename: + :param scale: Adds multiplier to size (w,h) + :param size: Size of field in characters + ''' + self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR + self.TKCanvas = None + + super().__init__(ELEM_TYPE_CANVAS, background_color=background_color, scale=scale, size=size, pad=pad) + return + + def __del__(self): + super().__del__() + + # ---------------------------------------------------------------------- # # Slider # # ---------------------------------------------------------------------- # @@ -1168,11 +1192,14 @@ class UberForm(): # ====================================================================== # # ------------------------- INPUT TEXT Element lazy functions ------------------------- # -def In(default_text ='', scale=(None, None), size=(None, None), auto_size_text=None, password_char='', background_color=None, text_color=None, do_not_clear=False, key=None, focus=False): - return InputText(default_text=default_text, scale=scale, size=size, auto_size_text=auto_size_text, password_char=password_char, background_color=background_color, text_color=text_color, do_not_clear=do_not_clear, focus=focus, key=key) +In = InputText +Input = InputText +#### TODO REMOVE THESE COMMENTS - was the old way, but want to keep around for a bit just in case +# def In(default_text ='', scale=(None, None), size=(None, None), auto_size_text=None, password_char='', background_color=None, text_color=None, do_not_clear=False, key=None, focus=False): +# return InputText(default_text=default_text, scale=scale, size=size, auto_size_text=auto_size_text, password_char=password_char, background_color=background_color, text_color=text_color, do_not_clear=do_not_clear, focus=focus, key=key) -def Input(default_text ='', scale=(None, None), size=(None, None), auto_size_text=None, password_char='', background_color=None, text_color=None, do_not_clear=False, key=None, focus=False): - return InputText(default_text=default_text, scale=scale, size=size, auto_size_text=auto_size_text, password_char=password_char, background_color=background_color, text_color=text_color, do_not_clear=do_not_clear, focus=focus, key=key) +# def Input(default_text ='', scale=(None, None), size=(None, None), auto_size_text=None, password_char='', background_color=None, text_color=None, do_not_clear=False, key=None, focus=False): +# return InputText(default_text=default_text, scale=scale, size=size, auto_size_text=auto_size_text, password_char=password_char, background_color=background_color, text_color=text_color, do_not_clear=do_not_clear, focus=focus, key=key) # ------------------------- CHECKBOX Element lazy functions ------------------------- # CB = Checkbox @@ -1180,20 +1207,29 @@ CBox = Checkbox Check = Checkbox # ------------------------- INPUT COMBO Element lazy functions ------------------------- # -def Combo(values, scale=(None, None), size=(None, None), auto_size_text=None, background_color=None): - return InputCombo(values=values, scale=scale, size=size, auto_size_text=auto_size_text, background_color=background_color) -def DropDown(values, scale=(None, None), size=(None, None), auto_size_text=None): - return InputCombo(values=values, scale=scale, size=size, auto_size_text=auto_size_text) +Combo = InputCombo +DropDown = InputCombo +Drop = InputCombo -def Drop(values, scale=(None, None), size=(None, None), auto_size_text=None): - return InputCombo(values=values, scale=scale, size=size, auto_size_text=auto_size_text) +# def Combo(values, scale=(None, None), size=(None, None), auto_size_text=None, background_color=None): +# return InputCombo(values=values, scale=scale, size=size, auto_size_text=auto_size_text, background_color=background_color) +# +# def DropDown(values, scale=(None, None), size=(None, None), auto_size_text=None): +# return InputCombo(values=values, scale=scale, size=size, auto_size_text=auto_size_text) +# +# def Drop(values, scale=(None, None), size=(None, None), auto_size_text=None): +# return InputCombo(values=values, scale=scale, size=size, auto_size_text=auto_size_text) # ------------------------- TEXT Element lazy functions ------------------------- # -def Txt(display_text, scale=(None, None), size=(None, None), auto_size_text=None, font=None, text_color=None, justification=None): - return Text(display_text, scale=scale, size=size, auto_size_text=auto_size_text, font=font, text_color=text_color, justification=justification) -def T(display_text, scale=(None, None), size=(None, None), auto_size_text=None, font=None, text_color=None, justification=None): - return Text(display_text, scale=scale, size=size, auto_size_text=auto_size_text, font=font, text_color=text_color, justification=justification) +Txt = Text +T = Text + +# def Txt(display_text, scale=(None, None), size=(None, None), auto_size_text=None, font=None, text_color=None, justification=None): +# return Text(display_text, scale=scale, size=size, auto_size_text=auto_size_text, font=font, text_color=text_color, justification=justification) +# +# def T(display_text, scale=(None, None), size=(None, None), auto_size_text=None, font=None, text_color=None, justification=None): +# return Text(display_text, scale=scale, size=size, auto_size_text=auto_size_text, font=font, text_color=text_color, justification=justification) # ------------------------- FOLDER BROWSE Element lazy function ------------------------- # def FolderBrowse(target=(ThisRow, -1), button_text='Browse', scale=(None, None), size=(None, None), auto_size_button=None, button_color=None, font=None, pad=None): @@ -1469,7 +1505,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): stringvar = tk.StringVar() element.TKStringVar = stringvar stringvar.set(display_text) - if element.AutoSizeText: + if auto_size_text: width = 0 if element.Justification is not None: justification = element.Justification @@ -1500,7 +1536,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.AutoSizeButton is not None: auto_size = element.AutoSizeButton else: auto_size = toplevel_form.AutoSizeButtons - if auto_size is False: width=element_size[0] + if auto_size is False or element.Size[0] is not None: width=element_size[0] else: width = 0 height=element_size[1] lines = btext.split('\n') @@ -1702,8 +1738,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): # ------------------------- OUTPUT element ------------------------- # elif element_type == ELEM_TYPE_OUTPUT: width, height = element_size - element.TKOut = TKOutput(tk_row_frame, width=width, height=height, bd=border_depth, background_color=element.BackgroundColor, text_color=text_color) - element.TKOut.pack(side=tk.LEFT,padx=element.Pad[0], pady=element.Pad[1]) + element.TKOut = TKOutput(tk_row_frame, width=width, height=height, bd=border_depth, background_color=element.BackgroundColor, text_color=text_color, font=font) + element.TKOut.pack(side=tk.LEFT) # ------------------------- IMAGE Box element ------------------------- # elif element_type == ELEM_TYPE_IMAGE: if element.Filename is not None: @@ -1723,6 +1759,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.tktext_label.image = photo # tktext_label.configure(anchor=tk.NW, image=photo) element.tktext_label.pack(side=tk.LEFT, padx=element.Pad[0],pady=element.Pad[1]) + # ------------------------- Canvas element ------------------------- # + elif element_type == ELEM_TYPE_CANVAS: + width, height = element_size + element.TKCanvas = tk.Canvas(tk_row_frame, width=width, height=height, bd=border_depth) + if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: + element.TKCanvas.configure(background=element.BackgroundColor) + element.TKCanvas.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # ------------------------- SLIDER Box element ------------------------- # elif element_type == ELEM_TYPE_INPUT_SLIDER: slider_length = element_size[0] * CharWidthInPixels() @@ -1954,7 +1997,7 @@ def MsgBox(*args, button_color=None, button_type=MSG_BOX_OK, auto_close=False, a # height = _GetNumLinesNeeded(message, width_used) height = message_wrapped_lines # print('Msgbox width, height', width_used, height) - form.AddRow(Text(message_wrapped, auto_size_text=True, size=(width_used, height))) + form.AddRow(Text(message_wrapped, auto_size_text=True)) total_lines += height pad = max_line_total-15 if max_line_total > 15 else 1