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

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Marc

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

    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(s elf):
    self.e = IntVar()

    for part, list in info.masterList .items():
    obj = setattr( self.e, part, IntVar() )

    That allowed me to save bundles of info without having to create
    another large dictionary or list. I was using the variable in entry
    boxes to store the amount of parts ordered:

    Entry( cscGroup.interi or(), width=3, textvariable =
    getattr(self.e, part),
    text=e.get()).g rid(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(sel f):
    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.mas ter, 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?

    Thanks ahead of time,
    Marc
  • Peter Otten

    #2
    Re: Confusing problem between Tkinter.Intvar( ) and self declared variable class

    Marc wrote:
    [color=blue]
    > 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(s elf):
    > self.e = IntVar()
    >
    > for part, list in info.masterList .items():
    > obj = setattr( self.e, part, IntVar() )[/color]

    It seems odd to use an IntVar as a container for IntVar instances.
    obj will always be set to None; just use setattr().
    [color=blue]
    >
    > That allowed me to save bundles of info without having to create
    > another large dictionary or list. I was using the variable in entry[/color]

    A Python object is just a dictionary in disguise.
    [color=blue]
    > boxes to store the amount of parts ordered:
    >
    > Entry( cscGroup.interi or(), width=3, textvariable =
    > getattr(self.e, part),
    > text=e.get()).g rid(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(sel f):
    > 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.mas ter, 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?[/color]

    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__(se lf):
    d = dict(self.__dic t__)
    for k in d:
    d[k] = d[k].get()
    return d
    def __setstate__(se lf, 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.pick le"

    class LoadError(Excep tion): pass

    class Main(tk.Frame):
    def __init__(self, master=None):
    tk.Frame.__init __(self, master)
    self.grid()
    try:
    self.loadVariab les()
    except LoadError:
    self.initVariab les()
    self.saveVariab les()
    self.initContro ls()

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

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

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

    def initControls(se lf):
    interior = self # cscGroup.interi or()
    x = 0
    for part, lst in info.masterDict .iteritems():
    e = tk.Entry(interi or, width=3,
    textvariable=ge tattr(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.sa veVariables)
    self.button.gri d(row=x, column=2, padx=4)

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

    Peter

    Comment

    • Marc

      #3
      Re: Confusing problem between Tkinter.Intvar( ) and self declared variable class

      Thanks Peter. That worked great! I was able to shoe horn that into my
      main program with hardly any changes at all, and it was exactly what I
      was looking for.

      I was afraid my post was a little confusing, so I started another
      thread on the general subject of Tk support for pickling. But
      basically you answered both questions with one shot.

      Thanks again,
      Marc

      Comment

      Working...