4
votes

Previous thread: Python 3.4 tkinter checkbutton variable handling not working / responding

Following a long thread the problem appears to be related to the declaration of an IntVar before root.mainloop() is run. Apparently the code from the previous thread works with Python 2.6.6 (thanks to PM 2Ring) once syntactical changes are made. You can see the full code on the previous thread. Here is a (roughly) Minimal, Complete, and Verifiable example:

import tkinter as tk

class Thing(tk.Frame):

    def Switch(self):
        if self.anyVar.get():
            state = "disabled"
        else:
            state = "normal"
        print(state)

        self.entry.configure(state=state)

    def createWidgets(self):

        ### This is the problem.
        print("testbefore")
        self.anyVar = tk.IntVar()
        print("testafter")
        ### End of problem. testafter is never printed. BUT WHY?!?!

        tk.Label(self,text="Test",font=("Times New Roman",15)).grid(row=0,column=0,sticky="W",padx=5,pady=5)
        self.box = tk.Checkbutton(self,variable=self.anyVar,command=self.Switch)
        self.box.grid(row=1,column=1,sticky="W",padx=0,pady=5)
        self.entry = tk.Entry(self,width=2)
        self.entry.grid(row=2,column=1,sticky="W",padx=2,pady=5)

    def __init__(self, parent):

        tk.Frame.__init__(self, parent)
        self.pack()
        self.parent = parent
        self.createWidgets()

class Framework(tk.Frame):

    def __init__(self, parent):

        tk.Frame.__init__(self, parent)
        self.instances = []
        self.parent = parent
        thing = Thing(self)
        self.instances.append(thing)

    def Activity(self):

        self.Clear()
        self.instances[0].pack()


def Initialise(window):
    window.master = tk.Frame(window)
    window.master.grid()
    window.instances = Framework(window.master)
    window.instances.grid()

root = tk.Tk()
Initialise(root)
root.mainloop()
root.destroy()

The code will execute until self.anyVar = tk.IntVar() is reached, at which point the program freezes but no error message is given. "testafter" is never printed. Any idea why this is? Thanks.

1
Nice MCVE. :) This works as expected for me on Python 2.6.6 (once I change import tkinter to import Tkinter). - PM 2Ring
What happens if you change self.pack() to self.grid(row=0, column=0) in the Thing.__init__ method ? - PM 2Ring
@PM2Ring No change :( This is a really confusing one... - Rob Murray

1 Answers

4
votes

(note: my original answer was related to the use of grid and pack. That answer was incorrect. This is the correct answer)

You have stumbled on a very obscure edge case that doesn't exist in python 2.6, but does exist in at least some versions of python 3.

I'm testing it on 3.4. In that version there's been some new code introduced in the variable handling code. Your code causes this new code to go into an infinite loop. The problem revolves around your choice to use master as the name of a widget attribute. This is a built-in attribute that you are overwriting, causing the code to go into an infinite loop.

The workaround is simple: rename window.master to be just about anything other than master. For example:

window._master = tk.Frame(window)