From c7a695d2a66d29d3ea8899b8df0823aea6fa85a7 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Mon, 3 Sep 2018 14:20:22 -0400 Subject: [PATCH] Changed button update method so can change only color if desired, tweaks to scrollable columns, fixed bug in size of OptionMeny element, initial check-in of image viewer demo by Jorj --- Demo_Img_Viewer.py | 115 +++++++++++++++++++++++++++++++++++++++++++++ PySimpleGUI.py | 14 ++++-- 2 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 Demo_Img_Viewer.py diff --git a/Demo_Img_Viewer.py b/Demo_Img_Viewer.py new file mode 100644 index 00000000..f09dc561 --- /dev/null +++ b/Demo_Img_Viewer.py @@ -0,0 +1,115 @@ +import PySimpleGUI as sg +import os +from PIL import Image, ImageTk +import io +""" +Simple Image Browser based on PySimpleGUI +-------------------------------------------- +There are some improvements compared to the PNG browser of the repository: +1. Paging is cyclic, i.e. automatically wraps around if file index is outside +2. Supports all file types that are valid PIL images +3. Limits the maximum form size to the physical screen +4. When selecting an image from the listbox, subsequent paging uses its index +5. Paging performance improved significantly because of using PIL + +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: + sg.MsgBoxCancel('Cancelling') + raise SystemExit() + +# PIL supported image types +img_types = (".png", ".jpg", "jpeg", ".tiff", ".bmp") + +# get list of files in folder +flist0 = os.listdir(folder) + +# create sub list of image files (no sub folders, no wrong file types) +fnames = [f for f in flist0 if os.path.isfile(os.path.join(folder,f)) and f.lower().endswith(img_types)] + +num_files = len(fnames) # number of iamges found +if num_files == 0: + sg.MsgBox('No files in folder') + raise SystemExit() + +del flist0 # no longer needed + +#------------------------------------------------------------------------------ +# use PIL to read data of one image +#------------------------------------------------------------------------------ +def get_img_data(f, maxsize = (1200, 850), first = False): + """Generate image data using PIL + """ + img = Image.open(f) + img.thumbnail(maxsize) + if first: # tkinter is inactive the first time + bio = io.BytesIO() + img.save(bio, format = "PNG") + del img + return bio.getvalue() + return ImageTk.PhotoImage(img) +#------------------------------------------------------------------------------ + + +# create the form that also returns keyboard events +form = sg.FlexForm('Image Browser', return_keyboard_events=True, + location=(0, 0), use_default_focus=False) + +# make these 2 elements outside the layout as we want to "update" them later +# initialize to the first file in the list +filename = os.path.join(folder, fnames[0]) # name of first file in list +image_elem = sg.Image(data = get_img_data(filename, first = True)) +filename_display_elem = sg.Text(filename, size=(80, 3)) +file_num_display_elem = sg.Text('File 1 of {}'.format(num_files), size=(15,1)) + +# define layout, show and read the form +col = [[filename_display_elem], + [image_elem]] + +col_files = [[sg.Listbox(values = fnames, select_submits=True, size=(60,30), key='listbox')], + [sg.ReadFormButton('Next', size=(8,2)), sg.ReadFormButton('Prev', + size=(8,2)), file_num_display_elem]] + +layout = [[sg.Column(col_files), sg.Column(col)]] + +form.Layout(layout) # Shows form on screen + +# loop reading the user input and displaying image, filename +i=0 +while True: + # 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'): + i += 1 + if i >= num_files: + i -= num_files + filename = os.path.join(folder, fnames[i]) + elif button in ('Prev', 'MouseWheel:Up', 'Up:38', 'Prior:33'): + i -= 1 + if i < 0: + i = num_files + i + filename = os.path.join(folder, fnames[i]) + elif button in ('Read', ''): # 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 + else: + filename = os.path.join(folder, fnames[i]) + + # update window with new image + image_elem.Update(data=get_img_data(filename)) + # update window with filename + filename_display_elem.Update(filename) + # update page display + file_num_display_elem.Update('File {} of {}'.format(i+1, num_files)) + + diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 7438608a..17ce24ea 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -866,9 +866,10 @@ class Button(Element): _my_windows.Decrement() return - def Update(self, new_text, button_color=(None, None)): + def Update(self, new_text=None, button_color=(None, None)): try: - self.TKButton.configure(text=new_text) + if new_text is not None: + self.TKButton.configure(text=new_text) if button_color != (None, None): self.TKButton.config(foreground=button_color[0], background=button_color[1]) except: @@ -1618,6 +1619,7 @@ def BuildResults(form, initialize_only, top_level_form): form.ReturnValuesDictionary = {} form.ReturnValuesList = [] BuildResultsForSubform(form, initialize_only, top_level_form) + top_level_form.LastButtonClicked = None return form.ReturnValues def BuildResultsForSubform(form, initialize_only, top_level_form): @@ -1801,7 +1803,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): PackFormIntoFrame(element, col_frame.TKFrame, toplevel_form) col_frame.TKFrame.update() if element.Size == (None, None): - col_frame.canvas.config(width=col_frame.TKFrame.winfo_reqwidth(),height=col_frame.TKFrame.winfo_reqheight()) + col_frame.canvas.config(width=col_frame.TKFrame.winfo_reqwidth()/2,height=col_frame.TKFrame.winfo_reqheight()/2) else: col_frame.canvas.config(width=element.Size[0],height=element.Size[1]) @@ -1971,11 +1973,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): # ------------------------- OPTION MENU (Like ComboBox but different) element ------------------------- # elif element_type == ELEM_TYPE_INPUT_OPTION_MENU: max_line_len = max([len(str(l)) for l in element.Values]) + if auto_size_text is False: width=element_size[0] + else: width = max_line_len element.TKStringVar = tk.StringVar() default = element.DefaultValue if element.DefaultValue else element.Values[0] element.TKStringVar.set(default) - element.TKOptionMenu = tk.OptionMenu(tk_row_frame, element.TKStringVar ,*element.Values ) - element.TKOptionMenu.config(highlightthickness=0, font=font) + element.TKOptionMenu = tk.OptionMenu(tk_row_frame, element.TKStringVar ,*element.Values) + element.TKOptionMenu.config(highlightthickness=0, font=font, width=width ) element.TKOptionMenu.config(borderwidth=border_depth) if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: element.TKOptionMenu.configure(background=element.BackgroundColor)