Tuesday, January 25, 2022

Mike Driscoll: PySimpleGUI - An Intro to Laying Out Elements

PySimpleGUI is a Python GUI that wraps other Python GUI toolkits (Tkinter, PySide, wxPython). By abstracting away the complexities of the other GUIs into a common API, you can quickly write code that can be rendered using any of those other toolkits just by changing the import at the top of your program.

If you were to use wxPython and you wanted to layout your widgets, you would use a wx.Sizer. In PySide or PyQt, you would use Layout object. Tkinter uses geometry managers. The general concept is the same. When you use these tools, the GUI toolkit uses relative positioning of the widgets to arrange them onscreen.

In PySimpleGUI, the same thing is done using nested lists. You will look at a couple of different examples in this tutorial that will give you a general idea of how this all works.

Creating a Horizontal Layout

Creating a series of Elements that are horizontally oriented (left-to-right) is done with a small list of lists in PySimpleGUI.

Horizontal Layout

Open up a Python editor and add the following code:

import PySimpleGUI as sg

# Horizontal layout
layout = [[sg.Button(f"OK {num}") for num in range(1, 6)]]

# Create the window
window = sg.Window("Demo", layout)

# Create an event loop
while True:
    event, values = window.read()
    # End program if user closes window or
    # presses the OK button
    if event == "OK" or event == sg.WIN_CLOSED:
        break

window.close()

Here you use a Python list comprehension to create a nested list that contains five Button objects in it. When you run this code, you will see the buttons aligned horizontally, with one next to the other going from left-to-right.

Now you are ready to see how you can rewrite the code to create a vertical layout!

Creating a Vertical Layout

To create a vertically oriented layout with PySimpleGUI, you need to make the layout contain a series of nested lists that each contain a one or more Elements in them.

Vertically Oriented Layout

Create a new Python file and add this code to it:

import PySimpleGUI as sg

layout = [[sg.Button("OK")],
          [sg.Button("OK 2")],
          [sg.Button("OK 3")],
          [sg.Button("OK 4")],
          [sg.Button("OK 5")]]

# Create the window
window = sg.Window("Demo", layout)

# Create an event loop
while True:
    event, values = window.read()
    # End program if user closes window or
    # presses the OK button
    if event == "OK" or event == sg.WIN_CLOSED:
        break

window.close()

When you run this code, the Button Elements will be stacked from top to bottom vertically, instead of horizontally.

Using Columns for Complex Layouts

If you need to add two or more columns of Elements next to each other in PySimpleGUI, you can use a sg.Column Element. It is a type of container Element specifically made for creating stacked sets of Elements!

Using Columns

Create another Python file and add the following code:

import PySimpleGUI as sg
import os.path


# First the window layout in 2 columns
file_list_column = [
    [sg.Text("Image Folder"),
     sg.In(size=(25, 1), enable_events=True, key="-FOLDER-"),
     sg.FolderBrowse(),],
    [sg.Listbox(values=[], enable_events=True, size=(40, 20), key="-FILE LIST-")],
]


# For now will only show the name of the file that was chosen
image_viewer_column = [
    [sg.Text("Choose an image from list on left:")],
    [sg.Text(size=(40, 1), key="-TEXT-")],
    [sg.Image(key="-IMAGE-")],
]

# ----- Full layout -----
layout = [
    [sg.Column(file_list_column),
     sg.VSeperator(),
     sg.Column(image_viewer_column),]
]


window = sg.Window("Column Demo", layout)


# Run the Event Loop
while True:
    event, values = window.read()

    if event == "Exit" or event == sg.WIN_CLOSED:
        break

    # Folder name was filled in, make a list of files in the folder
    if event == "-FOLDER-":
        folder = values["-FOLDER-"]
        try:
            # Get list of files in folder
            file_list = os.listdir(folder)
        except:
            file_list = []

        fnames = [
            f
            for f in file_list
            if os.path.isfile(os.path.join(folder, f))
            and f.lower().endswith((".png", ".gif"))
        ]

        window["-FILE LIST-"].update(fnames)

    elif event == "-FILE LIST-":  # A file was chosen from the listbox

        try:
            filename = os.path.join(values["-FOLDER-"], values["-FILE LIST-"][0])
            window["-TEXT-"].update(filename)
            window["-IMAGE-"].update(filename=filename)
        except:
            pass

window.close()

In this example, you create two layouts! The first layout is called file_list_column and contains four Elements in it. The second layout is called image_viewer_column and contains three Elements. Then you put these layouts inside of Columns that are themselves inside a layout. As you can see, PySimpleGUI layouts are lists inside of lists all the way down!

Wrapping Up

PySimpleGUI removes some of the complexity of creating layouts by using Python lists. The PyQt / PySide and wxPython GUI toolkits use an object-oriented approach which includes a significant amount of boilerplate and flags to do much the same thing. They each have their tradeoffs, but PySimpleGUI's learning curve is that much flatter because of their design choice.

Related Reading

The post PySimpleGUI - An Intro to Laying Out Elements appeared first on Mouse Vs Python.



from Planet Python
via read more

No comments:

Post a Comment

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...