Search code examples
pythonpython-3.xtkintertk-toolkittoplevel

Tkinter custom class error


I've been trying to make a class named vwin which makes either a Tk or Toplevel window. Unfortunately it returns an error:

Traceback (most recent call last):
  File "C:\Users\RELIC\Desktop\textpad.py", line 17, in <module>
    sub = vwin(['Sub Window','640x480-25-25','normal','window'],root)
  File "C:\Users\RELIC\Desktop\textpad.py", line 9, in __init__
    window = Toplevel(master)
  File "C:\Python33\lib\tkinter\__init__.py", line 2136, in __init__
    BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)
  File "C:\Python33\lib\tkinter\__init__.py", line 2086, in __init__
    BaseWidget._setup(self, master, cnf)
  File "C:\Python33\lib\tkinter\__init__.py", line 2064, in _setup
    self.tk = master.tk
AttributeError: 'vwin' object has no attribute 'tk'

Here is my code:

###############################################################################
from tkinter import *

class vwin():
    def __init__(self,args,master=None):
        if args[3].lower() == 'tk':
            window = Tk()
        else:
            window = Toplevel(master)
        window.title(args[0])
        window.geometry(args[1])
        window.state(args[2])



root = vwin(['Main Window','640x480+25+25','normal','Tk'])
sub = vwin(['Sub Window','640x480-25-25','normal','window'],root)

Solution

  • I see lots of issues.

    1. In your custom class, you are just creating the Tk() object and assigning it to local variable window whose scope ends once the the __init__() function ends , and is most probably garbage collected. You should save the Tk() object as an instance variable.

    2. You are sending in object of type vwin as master to Sub window vwin constructor. And then you are trying to call Toplevel() on the vwin object , which would not work. You need to use the previously saved Tk() object there.

    3. You are never starting the mainloop() for Tk() so when you run the program as a script, it would end before it starts.

    I think there may be tons of better way to do this , but one way to get it working for you is -

    from tkinter import *
    
    class vwin():
        def __init__(self,args,master=None):
            if args[3].lower() == 'tk':
                self.window = Tk()
            else:
                self.window = Toplevel(master.window)
            self.window.title(args[0])
            self.window.geometry(args[1])
            self.window.state(args[2])
    
        def mainloop(self):
            self.window.mainloop()
    
    
    
    root = vwin(['Main Window','640x480+25+25','normal','Tk'])
    sub = vwin(['Sub Window','640x480-25-25','normal','window'],root)
    root.mainloop()