Question

Python 3.1, tkinter/ttk

I wrote something very simple to try and understand how tkinter's variables linked to widgets can be stored in a different class to the widget. Code below.

Questions:

1) why doesn't pressing the button change the label?

2) do I need quite so many selfs? Can the variables within each method manage without self. on the start?

Hopefully the answer will be a useful learning exercise for other tkinter newbies...

from tkinter import *
from tkinter.ttk import *

root = Tk()

class Store:

    def __init__(self):
        self.v = IntVar()
        self.v.set(0)

    def set(self, v):
        self.v.set(v)

class Main:

    def __init__(self):

        self.counter = 0

        self.label = Label(root, textvariable = a.v)
        self.label.pack()

        self.button = Button(root, command = self.counter, text = '+1')
        self.button.pack()

    def counter(self):

        self.counter = self.counter + 1
        a.set(self.counter)

a = Store()
b = Main()

root.mainloop()
Was it helpful?

Solution 2

If I were you, I will do this:

import tkinter

root = tkinter.Tk()
var  = tkinter.IntVar()

label  = tkinter.Label(root, textvariable=var)
button = tkinter.Button(root, command=lambda: var.set(var.get() + 1), text='+1')

label.pack()
button.pack()

root.mainloop()

UPDATE:

But, if you insist doing this with two classes (where the first class is only a somewhat pointless interface), then I would do this:

import tkinter

class Store:
    def __init__(self):
        self.variable = tkinter.IntVar()

    def add(self, value):
        var = self.variable
        var.set(var.get() + value)
        return var.get()

class Main(tkinter.Tk):
    def __init__(self, *args, **kwargs):
        tkinter.Tk.__init__(self, *args, **kwargs)
        var = Store()
        self.label  = tkinter.Label(self, textvariable=var.variable)
        self.button = tkinter.Button(self, command=lambda: var.add(1), text='+1')
        self.label.pack()
        self.button.pack()


root = Main()
root.mainloop()

As you may notice, I used in both times the get() and set() methods of the IntVar (in your version I do this thru the Store interface we made), therefore you don't need to use a new variable (like self.counter) because the variable we instantiated is storing the data.

The other thing I used is a lambda expression instead of a full-blown function definition, since we only want to get the current value, add 1 to it, and store it as the new value.

And in my version, the Main class is a subclass of the original tkinter.Tk class -- that's why I call it's __init__ method inside the Main's __init__ method.

OTHER TIPS

Your problem is that you have both a method and a variable named counter. When you click the button, your function isn't being called so the variable isn't being set. At the time you create the button, tkinter thinks that self.counter is a variable rather than a command.

The solution to this particular problem is to rename either the function or the variable. It then should work as you expect.

To answer the question about "too many selfs": you need to use self so that python knows that the object you are referring to should be available everywhere within a specific instance of the object. So, yes, you need all those self's, if you want to refer to variables outside of the function they are defined in.

As for self in the definition of a method, those too are necessary. When you do object.method(), python will automatically send a reference to the object as the first argument to a method, so that the method knows specifically which method is being acted upon.

If you want to know more about the use of "self", there's a specific question related to self here: What is the purpose of self?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top