Python Forum
Scope of variable when using two classes
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Scope of variable when using two classes
#1
I have written a program (Python V3.7.4) for a games timer and there is a bug in it that I have not been able to fix. It contains one instance of class 'ButtonClass' and (potentially) multiple instances of 'DisplayClass'. This is so that I can have multiple clock displays set to different timezones, yet all working as one clock. Because it is a large and complex program, I have produced a much simplified example to show the problem (see attached). When I press the 'reset' button, the counter does not reset to zero. I have studied other questions relating to linking of classes, and this is how far it has got me. As an aside, when I produced a variant of this, where everything was in just one class, it worked as I wanted. I suspect that the problem may be one of scope of my variable 'old_day', but cannot see how to fix it. I also tried another variant, where DisplayClass is called from within the initialisation of ButtonClass, but that would not reset either. Can someone point out how to put it right. Thanks.


from tkinter import *
from time import strftime

class ButtonClass:
    def __init__(self, master):
        master.geometry("500x200")
        master.resizable(0, 0)
        frame1 = Frame(master)
        frame1.pack()
        resetbutton = Button(frame1, text="Reset", font=('Courier', 10, 'bold'), relief=RAISED,
                             width=10, command=self.reset_counter)
        resetbutton.grid(row=1, column=2)

    def reset_counter(self):
        print("reset_counter method")
        DisplayClass.reset(self)

        

class DisplayClass:
    def __init__(self, master, ButtonClass):
        old_day = 0
        self.old_day = old_day
        frame2 = Frame(master)
        frame2.pack()
        label1 = Label(frame2, font=('Courier', 10, 'bold'), relief=RAISED, width=10, height=5)
        label1.grid(row=1, column=1, padx=1, pady=1)
        self.counter_label(label1)
        
    def counter_label(self, label):
        print("this is the counter_label method")
        print("old day = ",self.old_day)
        def counter():
            print("This is counter method")
            self.old_day += 1
            print("old day = ",self.old_day)
            string = str(self.old_day)
            label.config(text=string)
            label.after(2000, counter)
        counter()

    def reset(self):
        print("this is the reset method")
        #self.old_day = 0
        DisplayClass.old_day = 0
        

def main():
    root = Tk()
    a = ButtonClass(root)
    b = DisplayClass(root, a)
    print("End")
    root.mainloop()


if __name__ == '__main__':
    main()
Reply
#2
You call the counter function twice each time.
            label.after(2000, counter)
        counter()
And you want to create an instance of the class and don't use the class itself. This is a very simple example.
import tkinter as tk

class ButtonClass:
    def __init__(self, master):
        master.geometry("600x300")
        master.resizable(0, 0)
        frame1 = tk.Frame(master)
        frame1.grid()
        resetbutton = tk.Button(frame1, text="Reset all clocks",
                      font=('Courier', 10, 'bold'), bg="orange",
                             width=10, command=self.reset_all_counters)
        resetbutton.grid(row=1, column=0)
  
        ## create 2 instances/clocks
        self.first_instance=ClockClass(master, "lightblue", grid_column=1)
        self.second_instance=ClockClass(master, "yellow", grid_column=2)

    def reset_all_counters(self):
        print("reset_counter method")
        for each_instance in [self.first_instance,
                              self.second_instance]:
            each_instance.reset_counter()

class ClockClass:
    def __init__(self, master, bg_color, grid_column):
        self.old_day=0
        frame1 = tk.Frame(master)
        frame1.grid(row=0, column=grid_column)
        resetbutton = tk.Button(frame1, text="  Reset this clock  ",
                             font=('Courier', 14, 'bold'),
                             bg=bg_color,
                             command=self.reset_counter)
        resetbutton.grid(row=20)

        self.counter_label(frame1,  bg_color)

    def reset_counter(self):
        print("reset_counter method")
        self.old_day=0


    def counter_label(self, frame1, bg_color):
        print("this is the counter_label method")
        print("old day = ",self.old_day)
        self.lab=tk.Label(frame1, font=('Courier', 14, 'bold'),
                bg=bg_color)
        self.lab.grid(row=10)
        self.counter()

    def counter(self):
        print("This is counter method")
        self.old_day += 1
        print("old day = ",self.old_day)
        self.lab.config(text=str(self.old_day))
        self.lab.after(2000, self.counter)

master=tk.Tk()
BV=ButtonClass(master)
master.mainloop()
Reply
#3
Thank you woooee! Your code works correctly and I particularly like your idea of calling (is that the right word?)instances of the second class from within the initialisation of the first; I would never have thought of that.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Tkinter object scope riversr54 6 1,865 Feb-17-2023, 05:40 AM
Last Post: deanhystad
  Key Binding scope angus1964 1 1,168 Jun-30-2022, 08:17 PM
Last Post: deanhystad
  How can import variable beteen classes in same module johnjh 1 1,908 Apr-19-2020, 09:41 PM
Last Post: deanhystad
  How to share a variable between two Python classes? robin1992 2 3,246 Nov-27-2019, 09:42 AM
Last Post: robin1992

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020