Skip to content

The steps to design a PNG viewer and selector #119

@jason990420

Description

@jason990420

Before design a script for PNG viewer and selector, some steps for window layout considered.

  • Left frame
    • Top: directory + browse button, The length of directory maybe to long to fit viewable length of directory.
    • Middle: PNG thumbnail viewer, the number of PNG maybe different as in different directory, so new window for it.
      • The number of selected PNG files maybe different, so use border color for selected or not, and by '<Control-Button-1>'
    • Bottom: file list for selected in listbox
  • Right frame
    • Expand frame to be with the same size of left frame
    • Get size for right frame for PNG resize
    • Show image by event '<Button-1>' on thumbnail.
from io import BytesIO
from pathlib import Path
from PIL import Image
import PySimpleGUI as sg

def move_center(window):
    screen_width, screen_height = window.get_screen_dimensions()
    win_width, win_height = window.size
    x, y = (screen_width - win_width)//2, (screen_height - win_height)//2
    window.move(x, y)

def resize(file, new_size):
    try:
        im = Image.open(file)
        w, h = im.size
        if w >= h:
            size = (new_size, int(new_size/w*h))
        else:
            size = (int(new_size/h*w), new_size)
        new_im = im.resize(size)                    # , Image.ANTIALIAS
        with BytesIO() as buffer:
            new_im.save(buffer, format="PNG")
            data = buffer.getvalue()
    except:
        data = None
    return data

def new_window(directory=''):

    path = Path(directory)
    if directory and path.is_dir():
        files = list(map(lambda file:str(file), path.glob(pattern)))
    else:
        files = []

    if files:
        layout_thumbnail = []
        row = []
        length = len(files)
        size = (thumbnail_width, thumbnail_width)
        for i, file in enumerate(files):
            data = resize(file, thumbnail_width)
            if (i % columns) == 0:
                pad = ((0, gap), gap)
            elif (i % columns) == columns - 1:
                pad = ((gap, gap*2), gap)
            else:
                pad = (gap, gap)
            frame = sg.Frame("",
                [[sg.Image(data=data, size=size, pad=(gap, gap),
                    key=("Thumbnail", i), metadata=False)]],
                pad=pad, background_color=sg.theme_background_color(),
                key=("Thumbnail_Frame", i))
            row.append(frame)
            if (i % columns) == columns-1 or i == length - 1:
                layout_thumbnail.append(row)
                row = []
    else:
        layout_thumbnail = [[]]

    width  = (thumbnail_width + 4*gap + 4) * columns + 2*gap + 16
    height = (thumbnail_width + 4*gap + 4) * columns
    layout_thumbnail_frame = [
        [sg.Column(layout_thumbnail, expand_x=True, expand_y=True,
            scrollable=True, vertical_scroll_only=True, pad=(0, 0))],
    ]
    layout_left_frame = [
        [sg.Input(directory, size=10, disabled=True, expand_x=True, key='Directory'),
         sg.Button('Browse')],
        [sg.Frame("", layout_thumbnail_frame, size=(width, height), border_width=0)],
        [sg.Listbox(selected_files, size=(10, 5), expand_x=True, key='Select_Files')],
    ]
    layout_right_frame = [
        [sg.Image(expand_x=True, expand_y=True, key='View')],
    ]
    layout = [
        [sg.Frame('', layout_left_frame),
         sg.Frame('', layout_right_frame, size=(10, 10), expand_y=True, key='Right Frame')],
    ]
    window = sg.Window('PNG Thumbnail Viewer', layout, alpha_channel=0, finalize=True)
    w, h = window['Right Frame'].get_size()
    window['Right Frame'].set_size((h, h))
    window.refresh()
    move_center(window)
    window.set_alpha(1)
    for key, element in window.key_dict.items():
        if isinstance(key, tuple) and key[0]=='Thumbnail':
            element.bind("<Control-Button-1>", "Control")
            element.bind("<Button-1>", "B1")
    return window, h, files, []

font = ("Courier New", 11)
sg.theme('DarkBlue3')
sg.set_options(font=font, dpi_awareness=True)

gap = 3
columns = 6
directory = ''
thumbnail_width = 90
selected_files = []
default_root = 'D:/'
pattern = '*.png'
bg = {True:'yellow', False:sg.theme_background_color()}

window, view_width, files, selected_files = new_window(default_root)

while True:

    event, values = window.read()

    if event == sg.WINDOW_CLOSED:
        break
    elif event == 'Browse':
        directory = sg.popup_get_folder('', no_window=True)
        if directory:
            new_win = new_window(directory)
            window.close()
            window, view_width, files, selected_files = new_win
            window['Select_Files'].update(values=[])
    elif isinstance(event, tuple) and len(event)==2:
        (element, index), bind = event
        if bind == 'B1':
            data = resize(files[index], view_width)
            window['View'].update(data=data)
        elif bind == 'Control':
            elem = window[event[0]]
            border = elem.metadata = not elem.metadata
            window[("Thumbnail_Frame", index)].Widget.configure(bg=bg[border])
            if border:
                selected_files.append(files[index])
            else:
                selected_files.remove(files[index])
            window['Select_Files'].update(values=selected_files)

window.close()

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions