Python Forum
Tkinter object scope
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tkinter object scope
#1
New to Python but really new to Tkinter...

Working on a simple app that has multiple child pages and one 'home' page that dispatches to the 'child' pages. Each one of the child pages is defined as a class inherited from Toplevel. In that class there is a constructor (__init__) that does some setup and defines the controls on the page (Button and Entry). One of the Buttons calls a second function in the class named SaveData. The idea is that this function will collect data from the Entry objects and save it in a custom class(Book). So far, so good... my problem arises when I try to access the data in the Entry object inside the SaveData function. The Entry object was declared in the __init__ function. I get an error indicating that the Entry object is None. This makes perfect sense to me given that the Entry object was defined in a different function. The question is how do I make it Global so that it is available in all the functions of the class or is there some other way? I've done some experimenting with making the Entry object global in __init__ but with no success.

Thanks for any advice/suggestions. Code Below

rivers
from tkinter import *
from tkinter import ttk
from Book import *

class EnterBookWindow(Toplevel):

    [color=#2980B9]def __init__(self):[/color]
        Toplevel.__init__(self)
        self.title("Enter a Book in xx Data Structure")
        self.geometry('400x400')
        frameLeft = Frame(self, width=40, padx=20, pady=20)
        frameLeft.pack(side=LEFT)
        frameRight = Frame(self, width=40, padx=20, pady=20)
        frameRight.pack(side=RIGHT)

        lblTitle = ttk.Label(frameRight, text="Title:").pack(padx=10, pady=0)
        [color=#C0392B]global entBookTitle[/color]
        entBookTitle = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)

        lblISBN = ttk.Label(frameRight, text="ISBN:").pack(padx=10, pady=0)
        entBookISBN = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
        
        lblAuthor = ttk.Label(frameRight, text="Author:").pack(padx=10, pady=0)
        entBookAuthor = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
        
        lblYear = ttk.Label(frameRight, text="Year:").pack(padx=10, pady=0)
        entBookYear = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)

        btnSave = ttk.Button(frameRight, text="Save Data", command=self.SaveBook).pack(padx=20, pady=10)

    def SaveBook(self):
        book = Book(entBookTitle.get(), entBookISBN.get(), entBookAuthor.get(), entBookYear.get())
#!!!Error occurs here when trying to get data from entBookTitle
Gribouillis write Feb-16-2023, 07:51 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
I couldn't get the code snippet to post correctly so the indentation looks wrong in my code. That part is OK, so please ignore that.

rivers
Reply
#3
The solution is to make the widgets that you want to access later members of the EnterBookWindow instance, for example in __init__()
self.entBookTitle = ttk.Entry(...)
Later
    def SaveBook(self):
        book = Book(
            self.entBookTitle.get(), self.entBookISBN.get(), self.entBookAuthor.get(), self.entBookYear.get())
Don't use the global keyword. It generally means that you are not organizing the data correctly.
Reply
#4
Thank you so much for the very quick reply. As soon as I saw it, I knew, "I should have thought of that", but I didn't Shy Now to the bad news...
I made those changes but still have the same problem.

The error is:
  File "D:\Projects\Pycharm\DSAFinalProject\EnterBook.py", line 27, in SaveBook
    book = Book(self.entBookTitle.get(), self.entBookISBN.get(), self.entBookAuthor.get(), self.entBookYear.get())
                ^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
What am I missing?


My updated code:

from tkinter import *
from tkinter import ttk
from Book import *

class EnterBookWindow(Toplevel):

    def __init__(self):
        Toplevel.__init__(self)
        self.title("Enter a Book in xx Data Structure")
        self.geometry('400x400')
        frameLeft = Frame(self, width=40, padx=20, pady=20)
        frameLeft.pack(side=LEFT)
        frameRight = Frame(self, width=40, padx=20, pady=20)
        frameRight.pack(side=RIGHT)

        lblTitle = ttk.Label(frameRight, text="Title:").pack(padx=10, pady=0)
        self.entBookTitle = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
        lblISBN = ttk.Label(frameRight, text="ISBN:").pack(padx=10, pady=0)
        self.entBookISBN = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
        lblAuthor = ttk.Label(frameRight, text="Author:").pack(padx=10, pady=0)
        self.entBookAuthor = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
        lblYear = ttk.Label(frameRight, text="Year:").pack(padx=10, pady=0)
        self.entBookYear = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
        btnSave = ttk.Button(frameRight, text="Save Data", command=self.SaveBook).pack(padx=20, pady=10)

    def SaveBook(self):
        book = Book(self.entBookTitle.get(), self.entBookISBN.get(), self.entBookAuthor.get(), self.entBookYear.get())
Reply
#5
(Feb-16-2023, 08:14 PM)riversr54 Wrote: Now to the bad news...
It is because the .pack() method returns None. Do
self.entBookTitle = ttk.Entry(frameRight, font=('Helvetica', 12), width=20)
self.entBookTitle.pack(padx=10, pady=10)
Reply
#6
Thanks, that did the trick. I would likely never have figured that one out, but it does make sense, wasn't really a scope problem at all.

Have a good day!
Reply
#7
This is easy to figure out if you let Python help.

First you look at the error message:
Error:
book = Book(self.entBookTitle.get(), self.entBookISBN.get(), self.entBookAuthor.get(), self.entBookYear.get()) ^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'get'
The next thing I would do is put a breakpoint on line 32 and run the program in the debugger, or add a print command before line 32 to display the value of self.entBookTitle.
    def SaveBook(self):
        print(self.entBookTitle)
        book = Book(self.entBookTitle.get(), self.entBookISBN.get(), self.entBookAuthor.get(), self.entBookYear.get())
This would verify that self.entBookTitle is indeed None.

Next search for every line that includes entBookTitle and focus on lines that assign a value to entBookTitle. In your posted code this only happens on line 17.
        self.entBookTitle = ttk.Entry(frameRight, font=('Helvetica', 12), width=20).pack(padx=10, pady=10)
Using the debugger I would set a breakpoint on line 18, or add a print statement right after line 17 to see the value of self.entBookTitle right after the assignment. The value would indeed be Null. Now you have isolated the problem to 1 line which contains an assignment and two function calls. These are the two function calls:
ttk.Entry(frameRight, font=('Helvetica', 12), width=20)
.pack(padx=10, pady=10)
One of these returns None. I would rewrite like this:
        self.entBookTitle
temp = ttk.Entry(frameRight, font=('Helvetica', 12), width=20)
print("entry", temp)
temp.pack(padx=10, pady=10)
print("pack", temp)
self.entBookTitle = temp
Run the code and you would see that "ttk.Entry(frameRight, font=('Helvetica', 12), width=20)" returns a ttkEntry object and pack() returns None. Armed with that information you would quickly realize that you need to break up creating and packing the entry widget.
self.entBookTitle = ttk.Entry(frameRight, font=('Helvetica', 12), width=20)
self.entBooktitle.pack(padx=10, pady=10)
I'm confident that you would have solved this problem quite quickly if you did a little poking around instead of immediately throwing up your hands in frustration. Give yourself some credit.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  tkinter AttributeError: 'GUI' object has no attribute pfdjhfuys 3 1,584 May-18-2023, 03:30 PM
Last Post: pfdjhfuys
  Key Binding scope angus1964 1 1,223 Jun-30-2022, 08:17 PM
Last Post: deanhystad
  tkinter moving an class object with keybinds gr3yali3n 5 3,299 Feb-10-2021, 09:13 PM
Last Post: deanhystad
  Scope of variable when using two classes AyJay 2 2,185 Jan-23-2020, 10:09 AM
Last Post: AyJay

Forum Jump:

User Panel Messages

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