When building a slightly more complex application using PySimpleGUI, you may run into the need to store user preferences to a file. This allow persisting some information or custom settings for the next time the user runs the application.


UPDATE: 08/12/2020

Not sure how I missed this the first time, but the PySimpleGUI cookbook documentation has an example of saving user preferences. Check it out at this link: PySimpleGUI Cookbook Example


While not terribly difficult, when first learning to build applications, this is something you may run into early in your development. This article covers how to:

  • Open a dialog box from your main application window
  • Read a dictionary from a json file
  • Easily fill a PySimpleGUI form with values from a dictionary
  • Store the form values back in a preferences dictionary
  • Save the dictionary to a json file

Running the Application

The application is split into two files, main.py and dialog.py. To run the application, you will need to have an activated virtual environment set up with PySimpleGUI installed. To run the app, enter python main.py.

psg_pref_main

On the Edit menu, there is a Preferences... selection. Click that to open the dialog box.

For something simple to illustrate the concept, the dialog just uses an address form. Fill in the form and click the save button.

psg_pref_dialog

This will save your information into a preferences.json file in the same folder as your application files. Here is how that json file looks.

{
    "name": "Robin Robinson",
    "address": "123 Main Street",
    "city": "Kansas City",
    "state": "MO",
    "zip": "64111"
}

If you exit the application and come back in, when you go to the dialog, you will see that the saved values have been loaded into the dialog.

Looking at main.py

Note in main.py the call to load the preferences (dialog.load_preferences()) in the main function. This loads the preferences.json file prior to displaying the user interface.

Also in the user interface loop, if the Preferences... menu item is selected, then show_pref_dialog() is called.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""
Sample application to demonstrate a preferences dialog.  This shows a main form,
and then displays a modal dialog to collect user preferences.  The results are
saved to a json file.
Another good alternative to saving preferences as json is to use the python
configparser library.

Author: Shakiestnerd

"""
import PySimpleGUI as sg
import dialog


def ui():
    """ Main user interface window. """
    menu = [
        [
            "&File",
            [
                "E&xit",
            ],
        ],
        [
            "&Edit",
            [
                "!Cut",
                "!Copy",
                "!Paste",
                "---",
                "Preferences...",

            ],
        ],
    ]

    sg.theme("LightGrey6")
    sg.SetOptions(element_padding=(5, 5))

    layout = [
        [sg.Menu(menu)],
        [sg.Text("Preferences Dialog Example")],
        [sg.Text("Choose Preferences from the Edit menu.")],
        [sg.Button("Close")],
    ]

    window = sg.Window("PSG_Pref", layout, font=("Ubuntu", 12), size=(400, 200))

    while True:
        event, values = window.read()

        if event in ("Exit", "Close", sg.WIN_CLOSED):
            break
        elif "Preferences..." in event:
            show_pref_dialog()
    window.close()


def show_pref_dialog():
    dialog.Dialog()


def main():
    dialog.load_preferences()
    ui()


if __name__ == "__main__":
    main()

Looking at dialog.py

In dialog.py, a global dictionary named PREF is used. This stores the preferences values while the application is running. It gets populated when the load_preferences() function is called.

The key to load_preferences() is the json.load() call. The first time you run load_preferences, preferences.json will not exist. So, there is a try / except block to catch that issue.

For saving the json file in the save_preferences() function, the key is simply calling json.dump().

sg.fill_form_with_values(window=window, values_dict=PREF) is also a nifty function. It loads the PREF dictionary values into the dialog form. The tags on the form must match the dictionary keys in order for this to work.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""
This file contains a Dialog class that handles the preferences dialog.
It also contains two utility functions to load and save the preferences to a json file.

"""

import PySimpleGUI as sg
import json

PREF = {}


class Dialog:
    """Preferences dialog class"""
    def __init__(self):

        self.layout = [[sg.Text("Name:")],
                    [sg.InputText(key='name')],
                    [sg.Text("Address:")],
                    [sg.InputText(key='address')],
                    [sg.Text("City", size=(20, 1)), sg.Text("State", size=(5, 1)),
                        sg.Text("Zip", size=(10, 1))],
                    [sg.InputText(key='city', size=(20, 1)),
                        sg.InputText(key='state', size=(5, 1)),
                        sg.InputText(key='zip', size=(10, 1))],
                    [sg.Button("Save"), sg.Button("Close")]
                    ]

        window = sg.Window("Preferences", self.layout, font=("Ubuntu", 12), size=(400, 250),
                        finalize=True, modal=True, keep_on_top=True)

        sg.fill_form_with_values(window=window, values_dict=PREF)
        while True:
            event, values = window.read()
            if event in ("Close", sg.WIN_CLOSED):
                break
            elif event == "Save":
                # load the PREF dictionary with the fields values.
                PREF['name'] = values['name']
                PREF['address'] = values['address']
                PREF['city'] = values['city']
                PREF['state'] = values['state']
                PREF['zip'] = values['zip']
                save_preferences()
                break

        window.close()


def load_preferences():
    """ Load the json preferences file if it exists.  Otherwise, set some defaults.
    The PREF dictionary keys have the same values as the form input keys."""
    global PREF
    try:
        with open("preferences.json", "r") as in_file:
            PREF = json.load(in_file)
    except FileNotFoundError:
        PREF = {'name': 'Name', 'address': 'Address', 'city': 'City', 'state': 'TX',
                'zip': '12345'}


def save_preferences():
    """Write out the PREF dictionary to a json preferences file"""
    with open("preferences.json", "w") as out_file:
        json.dump(PREF, out_file, indent=4)


if __name__ == '__main__':
    load_preferences()
    Dialog()