Home > Net >  Why are attributes of a tk object being 'retroactively' changed?
Why are attributes of a tk object being 'retroactively' changed?

Time:12-03

Personal project, I'm thinking it would be cool to be able to create a one to has many relationship between windows, so when a "parent" window is closed all of its "children" are also also closed.

So here is the window class that creates new windows via the Tk() function:

from tkinter import *

class Window:
    def __init__(self, title):
        self.create(title)

    def create(self,title):
        self.window = Tk()
        self.window.title(title)
        self.window.protocol("WM_DELETE_WINDOW",self.delete)

    def child(self, title):
        self.create(title)

    def delete(self):
        print(f'Destroying: {self.window.title()}')
        self.window.destroy()


parentclass1 = Window("ParentClass1")
parentclass2 = Window("ParentClass2")
parentclass3 = Window("ParentClass3")

print(parentclass1.window.title())
print(parentclass2.window.title())
print(parentclass3.window.title())
mainloop()

This works fine. Each window opens, and when its title is queried each instance returns the correct title:

print(parentclass1.window.title()) #=\> "ParentClass1"
print(parentclass2.window.title()) #=\> "ParentClass2"
print(parentclass3.window.title()) #=\> "ParentClass3"

What I want to be able to do is call the child method on the parentclass2 instance and instantly set up a relationship between parentclass2 and the newly created instance. I.e parentclass2 is the parent and the newly created instance is the child of parentclass2.

However before I get even to setting up this relationship via an array, a very weird thing happens when I use the child method:

parentclass2.child("ChildOfParentClass2")

print(parentclass1.window.title()) #=> "ParentClass1"
print(parentclass2.window.title()) #=> "ChildOfParentClass2"
print(parentclass3.window.title()) #=> "ParentClass1"

parentclass2.window.title() now returns the string "ChildOfParentClass2".

This is odd. self.window = Tk() is clearly being called twice, separately, and yet somehow setting the title of "ChildOfParentClass2" is "going up the stack" and is renaming ParentClass2 to ChildOfParentClass2?

I don't think its the .title method that's doing this. I think parentclass2.window is literally being turned into childofparentclass2.window.

I am aware that tkinter is behaving weirdly because I'm trying to force it into my object orientated approach...but it would be cool to use it this way so would appreciate an answer.

Can any one explain this weird behaviour, and maybe how it could be solved and I'll be able to call parentclass2.child("ChildOfParentClass2") and have it work as expected?

I've tried using Toplevel() in child and Tk() in init but exactly the same weird behavior occurs:

def __init__(self, title):
    self.window = Tk()
    self.create(title)

def create(self,title):
    self.window.title(title)
    self.window.protocol("WM_DELETE_WINDOW",self.delete)

def child(self, title):
    self.window = Toplevel() # thought this would work tbh
    self.create(title)

CodePudding user response:

The reason for the odd behavior is that in create you're redefining self.window to be the newly created window. It no longer represents the original window. So, when you print the title of what you think is the main window you actually are printing the title of the child window.

If you want to create a child of a root window, you need to create instances of Toplevel. You can then pass the root window in as the master of the Toplevel to create the parent/child relationship.

def child(self, title):
    new_window = Toplevel(master=self.window)
    new_window.title(title)

When you do this, child windows will automatically be deleted when the parent dies. You don't have to do anything at all to make that happen, that's the default behavior of tkinter widgets.

Bear in mind that if you create more than one instance of Tk, each is isolated from the other. Images, variables, fonts, and other widgets created in one cannot communicate with or be moved to another. Each gets their own separate internal tcl interpreter.

  • Related