I am trying to persist the state of my app and so far have found the pickle library.
I found out how to set and get config parameters into a dictionary from When using Python classes as program configuration structures (which includes inherited class attributes), a good way to save/restore?
I have managed to get it to save to an external config file but i don't think I'm doing it right and it all feels a bit clunky.
here is a cut down version to demo:
Config.py
# https://stackoverflow.com/questions/50613665/when-using-python-classes-as-program-configuration-structures-which-includes-in
import pickle
from pathlib import Path
filename = 'config'
class Config(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
def __init__(self):
# Load config from file
my_file = Path(filename)
if my_file.is_file():
infile = open(filename, 'rb')
self.update(pickle.load(infile))
infile.close()
def __getstate__(self):
return self
def __setstate__(self, state):
self.update(state)
def save(self):
# filename = 'config'
outfile = open(filename, 'wb')
pickle.dump(self, outfile)
outfile.close()
App.py
import tkinter as tk
import pickle
from Config import Config
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
# Init config
self.config = Config()
# initalise variables from config
param0 = tk.BooleanVar()
self.getConfig(param0)
param1 = tk.StringVar()
self.getConfig(param1)
param2 = tk.StringVar()
self.getConfig(param2, "one")
# Build config page
cb = tk.Checkbutton(self, text = "Param", variable=param0)
cb.pack()
e = tk.Entry(self, textvariable=param1)
e.pack()
om = tk.OptionMenu(self, param2, "one", "two", "three")
om.pack()
def getConfig(self, object, default=None):
if str(object) in self.config:
object.set(self.config[str(object)])
else:
if default:
object.set(default)
object.trace("w", lambda name, index, mode, object=object: self.setConfig(object))
def setConfig(self, object):
self.config[str(object)] = object.get()
self.config.save()
if __name__ == "__main__":
app=App()
app.mainloop()
This works the way I would expect it to however I do not know how to save the variable object name, instead the python generated name is stored in the config file, this is only OK if I only ever append more parameters but would mess everything up if I inserted a new parameter in between the existing ones.
example output of config file:
{'PY_VAR0': False, 'PY_VAR1': 'test string', 'PY_VAR2': 'three'}
I would like to know if there is a better way of doing this?
I think it is better if you give your parameters meaningful names by setting yourself the names of the variables instead of using the default ones:
e.g.
param0 = tk.BooleanVar(name='boolean_param')
param1 = tk.StringVar(name='string_param')
param2 = tk.StringVar(name='user_choice')
will give you the config
{'string_param': 'test string', 'boolean_param': False, 'user_choice': 'three'}
So even if you change the order in which the variables are created, it will not change their names and you will still be able to retrieve the correct value in the config file.