0

I am wanting to make a script (that is re-usable on all of my python projects) that loads and saves values to all existing Tkinter variables to/from a pickle file. I could easily move the load and save functions into the first file but this is what I'm trying to avoid. Right now, the 2 functions in the second file (separate.py) don't work because they are trying to access variables within the first file (project.py) using the globals() function. Is there a different way I could go about making this work or do I not have a choice but to combine the 2 files?

project.py:

from os import getcwd
from separate import load_tkinter_variables_from_pickle, save_tkinter_variables_to_pickle
from tkinter import BooleanVar, Button, Checkbutton, DoubleVar, Entry, IntVar, Label, StringVar, Tk

cwd = getcwd()
settings_file = cwd + '\\' + 'settings.pkl'

main_window = Tk()
main_window.title('House Listing')
main_window.attributes('-toolwindow', True)

city_str = StringVar()
Label(master=main_window, text='City').pack()
Entry(master=main_window, textvariable=city_str).pack()

bedrooms_int = IntVar()
Label(master=main_window, text='Bedrooms').pack()
Entry(master=main_window, textvariable=bedrooms_int, width=5).pack()

furnished_bool = BooleanVar()
Label(master=main_window, text='Furnished?').pack()
Checkbutton(master=main_window, onvalue=True, offvalue=False, variable=furnished_bool).pack()

acres_dbl = DoubleVar()
Label(master=main_window, text='Acres of Land').pack()
Entry(master=main_window, textvariable=acres_dbl, width=5).pack()

Button(master=main_window, text='Load', command=lambda: load_tkinter_variables_from_pickle(pickle_file_path=settings_file)).pack(side='left')
Button(master=main_window, text='Save', command=lambda: save_tkinter_variables_to_pickle(pickle_file_path=settings_file)).pack(side='right')

main_window.mainloop()

separate.py:

from os import path
from pickle import dump, load


def save_tkinter_variables_to_pickle(pickle_file_path):
    """ save all existing tkinter variables to a pickle file """
    data = {}
    for i in globals():
        if i.endswith('_bool') or i.endswith('_dbl') or i.endswith('_int') or i.endswith('_str'):
            print(f'{i} \t= \t{globals()[i].get()}')
            data[i] = globals()[i].get()
    with open(pickle_file_path, 'wb') as file:
        dump(data, file)

def load_tkinter_variables_from_pickle(pickle_file_path):
    """ load all variables from a pickle, create the appropriate Tk variables and set their values """
    if path.exists(pickle_file_path):
        with open(pickle_file_path, 'rb') as file:
            data = load(file)
        for i in data:
            if i.endswith('_bool') or i.endswith('_dbl') or i.endswith('_int') or i.endswith('_str'):
                globals()[i].set(data[i])
                print(f'{i} = {data[i]}')
  • 1
    The main script would have to explicitly pass its `globals()` dict to both the load and save functions, as the second script otherwise has no access to it. Note: `isinstance(X, tkinter.Variable)` would be a way of identifying all of the Var types without requiring a specific naming scheme for them. – jasonharper Jul 05 '23 at 03:16
  • 1
    You can also ask the variable classes for a list of all subclasses using introspection. For example, [Printing all instances of a class](https://stackoverflow.com/questions/328851/printing-all-instances-of-a-class) – Bryan Oakley Jul 05 '23 at 04:09

0 Answers0