Confusing problem between Tkinter.Intvar() and self declared variable class

Peter Otten __peter__ at web.de
Tue Jan 27 10:48:07 CET 2004


Marc wrote:

> Hi all,
> 
> I was using Tkinter.IntVar() to store values from a large list of
> parts that I pulled from a list. This is the code to initialize the
> instances:
> 
>     def initVariables(self):
>         self.e = IntVar()
> 
>         for part, list in info.masterList.items():
>             obj = setattr( self.e, part, IntVar() )

It seems odd to use an IntVar as a container for IntVar instances.
obj will always be set to None; just use setattr().

> 
> That allowed me to save bundles of info without having to create
> another large dictionary or list. I was using the variable in entry

A Python object is just a dictionary in disguise.

> boxes to store the amount of parts ordered:
> 
>      Entry( cscGroup.interior(), width=3, textvariable =
> getattr(self.e, part),
>                            text=e.get()).grid(row=x, column=2, padx=4
> )
> 
> However, I ran into problems when I tried to pickle the instances in
> order to recall them later. To fix that problem I created my own
> simple data class that allowed me to save the data the same way while
> also having the ability to pickle it:
> 
> class DataVar:
>     def __init__(self):
>         self.data = 0
>         self.partName = ""
> 
>     def set(self, value):
>         self.data = value
> 
>     def get(self):
>         return self.data
> 
> But I just discovered another problem. It doesn't appear to hold data
> the same way. The information appeared global when it was IntVar().
> Now when I go outside the class that set up the entry boxes, the
> information does not appear to be in DataVar. I print out the info the
> following way:
> 
>     def printValues(self):
>         for part, list in info.masterList.items():
>             e = getattr(self.e, part)
>             print str(part) + " --->" + str( e.get() )
> 
> This function is in the same class that initialized the DataVar
> variables and also that called the class that setup the window to
> enter the amount of parts. When I call that class I pass in the
> variable in the following way:
> 
>        spares = Spares(self.master, self.e)
> 
> So obviously there's something about Tkinter that causes the info to
> be global. But even though the DataVar class is an independent class,
> for some reason the information is not being maintained.
> 
> Does anyone have any idea why this is happening and how to fix it?

I wasn't able to completely follow the last part of your post, so below is a
working version of what I /think/ you are trying to do. The important part
is a pickle-enhanced container for IntVars that stores their values instead
of the instances. It could easily be enhanced to support, say, StringVar by
inspecting the type of the values in the __setstate__() method.

<crocodile.py>
import Tkinter as tk
import pickle

class Namespace:
    pass

class IntVars:
    """ Every attribute is suposed to be a TKinter.IntVar instance """
    def __getstate__(self):
        d = dict(self.__dict__)
        for k in d:
            d[k] = d[k].get()
        return d
    def __setstate__(self, d):
        for k, v in d.iteritems():
            iv = tk.IntVar()
            iv.set(v)
            setattr(self, k, iv)

info = Namespace()

info.masterDict = {
    "bird": 1,
    "elephant": 2,
    "crocodile": 3,
}

FILENAME = "crocodile.pickle"

class LoadError(Exception): pass

class Main(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.grid()
        try:
            self.loadVariables()
        except LoadError:
            self.initVariables()
            self.saveVariables()
        self.initControls()

    def loadVariables(self):
        try:
            f = file(FILENAME)
        except IOError:
            raise LoadError
        else:
            # error handling is *incomplete*
            try:
                self.e = pickle.load(f)
            finally:
                f.close()

    def saveVariables(self):
        f = file(FILENAME, "wb")
        try:
            pickle.dump(self.e, f)
        finally:
            f.close()

    def initVariables(self):
        self.e = IntVars()
        for part, lst in info.masterDict.iteritems():
            iv = tk.IntVar()
            iv.set(lst)
            setattr(self.e, part, iv)

    def initControls(self):
        interior = self # cscGroup.interior()
        x = 0
        for part, lst in info.masterDict.iteritems():
            e = tk.Entry(interior, width=3,
                textvariable=getattr(self.e, part)) # text=... has no effect
            e.grid(row=x, column=2, padx=4)
            x += 1

        self.button = tk.Button(self, text="Save values",
            command=self.saveVariables)
        self.button.grid(row=x, column=2, padx=4)

m = Main()
m.mainloop()
</crocodile.py>

Peter



More information about the Python-list mailing list