B.Gra B.Gra - 28 days ago 9
Python Question

Why aren't my Tkinter Labels updating?

It's my understanding that the class

DiceRoller
should be inheriting from the class
die
, however every time I run I get the error:

self.display.config(text = str(self.value))
AttributeError: 'DiceRoller' object has no attribute 'display'


The value of
self.value
is updating, but the Tkinter label is not.

import Tkinter
import random

class die(object):
def __init__(self,value,display):
self.value = random.randint(1,6)
self.display = Tkinter.Label(display,
text = str(self.value),
font = ('Garamond', 56),
bg = 'white',
relief = 'ridge',
borderwidth = 5)
self.display.pack(side = 'left')

class DiceRoller(die):
def __init__(self):
self.gameWin = Tkinter.Tk()
self.gameWin.title('Dice Roller')
self.gameFrame = Tkinter.Frame(self.gameWin)
self.dice = []
self.Row1 = Tkinter.Frame(self.gameWin)
for i in range(1,4):
self.dice.append(die(i,self.Row1))
self.topFrame = Tkinter.Frame(self.gameWin)
self.rollBtn = Tkinter.Button(self.topFrame,
text = 'Roll Again',
command = self.rollDice,
font = ('Garamond', 56))
self.rollBtn.pack(side = 'bottom')

self.gameFrame.pack()
self.Row1.pack()
self.topFrame.pack()
self.gameWin.mainloop()
def rollDice(self):
self.value = random.randint(1,6)
print self.value #to show value is in fact changing
self.display.config(text = str(self.value))

varName = DiceRoller()

Answer

You get that

AttributeError: 'DiceRoller' object has no attribute 'display' 

error because DiceRoller doesn't actually have a .display attribute.

You may expect it to have one because the die class has a .display attribute, but that attribute gets created when die.__init__ gets called, and DiceRoller won't automatically call die.__init__ because you've overridden that method with DiceRoller's own .__init__ method.

If you want to call die.__init__ inside DiceRoller.__init__ you can do that, the suggested way is to use the super function. But you have to be careful to call die.__init__ with the correct arguments!

However, there's no need for DiceRoller to inherit from die. I've moved DiceRoller's old rollDice method to die & created a new rollDice method for DiceRoller. So when the 'Roll Again' button is pressed all the dice in DiceRoller.dice get rolled.

import Tkinter as tk
import random

class die(object):
    def __init__(self, value, display):
        self.value = random.randint(1,6)
        self.display = tk.Label(display,
          text = str(self.value),
          font = ('Garamond', 56),
          bg = 'white',
          relief = 'ridge',
          borderwidth = 5)
        self.display.pack(side = 'left')

    def rollDice(self):
        self.value = random.randint(1,6)
        print self.value  #to show value is in fact changing
        self.display.config(text = str(self.value))

class DiceRoller(object):
    def __init__(self):
        self.gameWin = tk.Tk()
        self.gameWin.title('Dice Roller')
        self.gameFrame = tk.Frame(self.gameWin)
        self.dice = []
        self.Row1 = tk.Frame(self.gameWin)
        for i in range(1,4):
            self.dice.append(die(i, self.Row1))  
        self.topFrame = tk.Frame(self.gameWin)
        self.rollBtn = tk.Button(self.topFrame,
            text = 'Roll Again',
            command = self.rollDice,
            font = ('Garamond', 56))
        self.rollBtn.pack(side = 'bottom')

        self.gameFrame.pack()
        self.Row1.pack()
        self.topFrame.pack()
        self.gameWin.mainloop()

    def rollDice(self):
        for die in self.dice:
            die.rollDice()

DiceRoller()