-1

I have an entry widget in a class (StartPage) where I have to put numbers, the input is saved in a general class (Variabili) which is accessible from another class (FirstPage). Based on that number I have to istanciate n labels (where n is the number i put in the previous page). To do that I used a for loop: for i in range(0, int(number)). And here's the problem: I keep getting this error: TypeError: IntVar() missing 1 required positional argument: 'name'

Down here's the code:

import tkinter as tk                # python 3
from tkinter import font as tkfont
from typing_extensions import IntVar  # python 3


class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        

        self.frames = {}
        for F in (StartPage, PageOne):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name, *args):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()

    def get_page(self, classname):
        '''Returns an instance of a page given it's class name as a string'''
        for page in self.frames.values():
            if str(page.__class__.__name__) == classname:
                return page
        return None



class Variabili: 
    numero_finanziatori = tk.IntVar()
    
class StartPage(tk.Frame, Variabili):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        
        #label = tk.Label(self, text="Start Page: insert value")
        #label.pack(side="top", fill="x", pady=10)
        #self.some_input = tk.IntVar()
        #self.some_entry = tk.Entry(self, width=8, textvariable=self.some_input).pack()
        

        self.some_input = tk.StringVar()
        self.some_entry = tk.Entry(self, width=8, textvariable=Variabili.numero_finanziatori)
        self.some_entry.insert(0, "1")
        self.some_entry.pack()
        Variabili.numero_finanziatori = self.some_entry.get()
        
        button1 = tk.Button(self, text='Next Page', command=lambda: controller.show_frame("PageOne"))
        button1.pack()

class PageOne(tk.Frame, Variabili):   

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        
        labels_finanziatori = {
        'principale': [],
        'capitale_investito': [], 
        'tasso': [], 
        'tempo': []
        }
        dict_finanziatori = {
        'numero': [],
        'capitale_investito': [], 
        'tasso': [], 
        'tempo': [],
        }
        Finanziatore_Semplice = []

        k = 0

        for i in range(0, int(Variabili.numero_finanziatori)): 
            #MAIN label del finanziatore
            labels_finanziatori['principale'].append(tk.Label(self, text="Dati finanziatore numero "+str(i+1) +":\n"))
            labels_finanziatori['principale'][i].grid(row=i*(k+1), column = 0)
            k = k+1
            button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage")).grid()

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

And here's the traceback i get:

File "c:/Users/trevi/Documents/WorkInProgress/Python/V0_3/backbone4.py", line 50, in <module>
    class Variabili:
  File "c:/Users/trevi/Documents/WorkInProgress/Python/V0_3/backbone4.py", line 51, in Variabili
    numero_finanziatori = tk.IntVar()
  File "C:\Users\trevi\Anaconda\Anaconda3\lib\tkinter\__init__.py", line 502, in __init__
    Variable.__init__(self, master, value, name)
  File "C:\Users\trevi\Anaconda\Anaconda3\lib\tkinter\__init__.py", line 317, in __init__
    self._root = master._root()
AttributeError: 'NoneType' object has no attribute '_root'

2 Answers2

0

IntVar inherits from the Variable class.


from inspect import signature
import tkinter


print("\n----- IntVar Method Resolution Order -----\n")

print(tkinter.IntVar.mro())

print("\n----- __init__ signature -----\n")

print("Variable:", signature(tkinter.Variable.__init__))
print("IntVar:", signature(tkinter.IntVar.__init__))

Output:


----- IntVar Method Resolution Order -----

[<class 'tkinter.IntVar'>, <class 'tkinter.Variable'>, <class 'object'>]

----- __init__ signature -----

Variable: (self, master=None, value=None, name=None)
IntVar: (self, master=None, value=None, name=None)

The point is that calling IntVar() requires a master (or root window).

From the Variable class:


if not master:
    master = _get_default_root('create variable')
self._root = master._root()
self._tk = master.tk

The reason for this error is that the default root was not found when calling IntVar. If the root is already declared in the script, it is usually not specified as an IntVar parameter.


import tkinter


print("\n----- root -----\n")

root = tkinter.Tk()
print(root.tk)
print("is _default_root:", tkinter._default_root is root)

print("\n----- IntVar -----\n")

var = tkinter.IntVar()
print(var._tk)

Output:


----- root -----

<_tkinter.tkapp object at 0x00000080E160E7B0>
is _default_root: True

----- IntVar -----

<_tkinter.tkapp object at 0x00000080E160E7B0>

The analogue of root = tkinter.Tk() in your script is app = SampleApp(). This is why these variables work in the classes associated with the SampleApp.


But the problem is not this error, but the fact that the labels in the PageOne class are formed depending on the value entered in the Entry in the StartPage class.

In your application, all frames are initialized in the SampleApp class's __init__ method. This way you can access the frames through the controller (self.controller.frames[page_name]).

In this example, I am manipulating elements of one class from another. There are other options as well.


import tkinter as tk                # python 3
from tkinter import font as tkfont
#from typing_extensions import IntVar  # python 3


class SampleApp(tk.Tk):
    # same
    ...


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        
        # TypeError is thrown for self.some_input.get() if the value entered is not a number
        # see: https://stackoverflow.com/questions/4140437/interactively-validating-entry-widget-content-in-tkinter
        # https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/entry-validation.html
        self.some_input = tk.IntVar()
        # set the default to 1
        self.some_input.set(1)
        self.some_entry = tk.Entry(self, width=8, textvariable=self.some_input)
        self.some_entry.pack()
        # button to open the next page with certain conditions
        button1 = tk.Button(self, text='Next Page', command=self.show_next_frame)
        button1.pack()

    def show_next_frame(self):
        if self.some_input.get() == 0:
            pass
        else:
            # create labels in the PageOne class using the entered value
            self.controller.frames["PageOne"].create_labels(self.some_input.get())
            # reset the default to 1
            self.some_input.set(1)
            # show the prepared page
            self.controller.show_frame("PageOne")


class PageOne(tk.Frame):   

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        
        self.labels_finanziatori = {
        'principale': [],
        'capitale_investito': [], 
        'tasso': [], 
        'tempo': []
        }
        dict_finanziatori = {
        'numero': [],
        'capitale_investito': [], 
        'tasso': [], 
        'tempo': [],
        }
        Finanziatore_Semplice = []

    def create_labels(self, some_input):
        k = 0

        for i in range(0, some_input): 
            # create new labels
            label = tk.Label(self, text="Dati finanziatore numero "+str(i+1) +":\n")
            label.grid(row=i*(k+1), column = 0)
            # you can save labels if needed
            self.labels_finanziatori['principale'].append(label)
            k = k+1
        # button on the side of the labels
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: self.controller.show_frame("StartPage")).grid(row=0, column=1)


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

8349697
  • 415
  • 1
  • 6
  • 11
0

File "C:\Users\trevi\Anaconda\Anaconda3\lib\tkinter_init_.py", line 317, in init self._root = master._root() AttributeError: 'NoneType' object has no attribute '_root'

You must start root = tk.TK() before class StartPage(....

In line 109, add root.withdraw() in if __name__ == "__main__":

Code:

root = tk.Tk()

class SampleApp(tk.Tk):

:
:
:
if __name__ == "__main__":
    root.withdraw()
:
:

Screenshot:

enter image description here

toyota Supra
  • 3,181
  • 4
  • 15
  • 19