Using Tkinter widgets on child window - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: Using Tkinter widgets on child window (/thread-24097.html) |
Using Tkinter widgets on child window - chewy1418 - Jan-30-2020 Main/Root Window My issue is in the TopLevel/Secondary Window. In that class, I have a ListBox which I can declare successfully and will appear, but my end goal is to have a button on that screen call a secondary function which will then populate the Listbox with some data from a DB. Before tackling the database logic I tried to simply just put some data in manually using the below method: self.Lb1.insert(END, "Entry Value")But for some reason, it doesn't recognize that command which results in the following error AttributeError: 'NoneType' object has no attribute 'insert' Any help would be appreciated :) from tkinter import * from tkinter import ttk class Application(object): def __init__(self, master): self.topColor = '#f2f2f2' self.bottomColor = '#e6e6e6' self.master = master # Configure our menu menu = Menu(self.master) self.master.config(menu = menu) file = Menu(menu, tearoff = 0) file.add_command(label = 'About', command = self.aboutMessage) file.add_command(label = 'Exit', command = self.client_exit) menu.add_cascade(label = 'File', menu = file) edit = Menu(menu, tearoff = 0) edit.add_command(label = 'Undo') menu.add_cascade(label = 'Edit', menu = edit) rules = Menu(menu, tearoff = 0) rules.add_command(label = 'Add Table & Function', command = self.addFuncTable) rules.add_command(label = 'Search', command = self.search) menu.add_cascade(label = 'Rules', menu = rules) # ---- Top Frame ---- # # Configure frames self.top = Frame(master, height = 71, bg = self.topColor) self.top.pack(fill = X) self.bottom = Frame(master, height = 530, bg = self.bottomColor) self.bottom.pack(fill = X) self.top_image = PhotoImage(file ='Images/Logo.png') Label(self.top, image = self.top_image).place(x = -1, y = -1) Label(self.top, text = "H03 & HF9 Mosaic Script Generation Tool", bg = self.topColor, font = ('Calbri', 11)).place(x = 70, y = 5) Label(self.top, text = 'Use the below entry boxes to fill in the necessary information about your ITR', bg = self.topColor).place(x = 70, y = 30) Label(self.top, text = 'This will include your Version Number(s), GUID, etc', bg = self.topColor).place(x = 70, y = 48) # ---- Bottom Frame ---- # # Define var's for each of our fields so we can get the value self.entry_appendixPath = StringVar() self.entry_rateSheetPath = StringVar() Label(self.bottom, text = 'File Path for Appendix:', bg = self.bottomColor).place(x = 4, y = 20) self.appendix = ttk.Entry(self.bottom, width = 30, textvariable = self.entry_appendixPath).place(x = 7, y = 40) Label(self.bottom, text = "File Path for Rate Sheet:", bg = self.bottomColor).place(x = 250, y = 20) self.rateSheet = ttk.Entry(self.bottom, width = 30, textvariable = self.entry_rateSheetPath).place(x = 253, y = 40) Label(self.bottom, text = "Script Author:", bg = self.bottomColor).place(x = 4, y = 80) ttk.Entry(self.bottom).place(x = 7, y = 100) Label(self.bottom, text = "GUID Identifier:", bg = self.bottomColor).place(x = 170, y = 80) ttk.Entry(self.bottom).place(x = 173, y = 100) self.StateCodeVal = StringVar() Label(self.bottom, text = "State Code:", bg = self.bottomColor).place(x = 350, y = 80) ttk.Combobox(self.bottom, textvariable = self.StateCodeVal, width = 10, values = [ "PA", "AK", "AZ", "AR", "CA", "CO", "CT", "DC", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY" ]).place(x = 353, y = 100) Label(self.bottom, text = "Current Version", bg = self.bottomColor).place(x = 4, y = 135) ttk.Entry(self.bottom).place(x = 7, y = 155) Label(self.bottom, text = "New Version:", bg = self.bottomColor).place(x = 170, y = 135) ttk.Entry(self.bottom).place(x = 173, y = 155) Label(self.bottom, text = "UW Company:", bg = self.bottomColor).place(x = 350, y = 135) ttk.Entry(self.bottom, width = 10).place(x = 353, y = 155) Button(self.bottom, text="Lookup Version", command=self.lookupOldVersion).place(x=6, y=180) # Not an easy way to execute a stored proc in python with OUTPUT params # Button(self.bottom, text="Generate").place(x = 173, y = 180) Label(self.bottom, text="Above button call requires that both State Code and Apex Flag are valued!", bg = self.bottomColor, fg="Red").place(x = 4, y = 210) self.ApexCheck = StringVar() Label(self.bottom, text="Apex Flag ( 1 -> is Apex, 0 -> Legacy):", bg=self.bottomColor).place(x = 4, y = 250) ttk.Combobox(self.bottom, textvariable=self.ApexCheck, width = 10, values = [ 1, 2 ]).place(x = 4, y = 272) Label(self.bottom, text = "Do we need to create new procedure(s) or table(s) for this ITR?", bg = self.bottomColor).place(x = 4, y = 310) # Set style for ttk.RadioButton since bg= is not supported s = ttk.Style() s.configure( 'myStyle.TRadioButton', background = self.bottomColor ) self.newCheck = IntVar() ttk.Radiobutton(self.bottom, text = "Yes", variable = self.newCheck, value = 1).place(x = 5, y = 335) ttk.Radiobutton(self.bottom, text = "No", variable = self.newCheck, value = 0).place(x = 5, y = 360) # Radiobutton(self.bottom, text = "Yes", bg = self.bottomColor, variable = newCheck, value = 1).place(x = 4, y = 270) # Radiobutton(self.bottom, text = "No", bg = self.bottomColor, variable = newCheck, value = 0).place(x = 4, y = 290) # Checkbutton(self.bottom, bg = self.bottomColor, text = "Yes", variable = newCheck).place(x = 4, y = 270) Button(self.bottom, text = 'Submit', fg = 'white', bg = '#00802b', command = self.getEntries).place(x = 4 , y = 400) def search(self): S = Search.Search() def main(): root = Tk() app = Application(root) root.title('Main Window') root.geometry('500x600') root.resizable(False, False) root.mainloop() if __name__ == '__main__': main()Second Window # Tkinter modules from tkinter import * from tkinter import ttk from tkinter import messagebox class Search(Toplevel): def __init__(self): Toplevel.__init__(self) self.geometry('500x500') self.title('Search') self.resizable(False, False) self.topColor = '#f2f2f2' self.bottomColor = '#e6e6e6' # Configure frames self.top = Frame(self, height=71, bg=self.topColor) self.top.pack(fill=X) self.bottom = Frame(self, height=430, bg=self.bottomColor) self.bottom.pack(fill=X) self.top_image = PhotoImage(file='Images/Logo.png') Label(self.top, image=self.top_image).place(x=-1, y=-1) Label(self.bottom, text="Current Version:", bg=self.bottomColor).place(x = 5, y = 15) ttk.Entry(self.bottom).place(x = 7, y = 35) Label(self.bottom, text="New Version:", bg=self.bottomColor).place(x = 150, y = 15) ttk.Entry(self.bottom).place(x = 153, y = 35) Button(self.bottom, text = "Get Existing Rules ..").place(x = 5, y = 65) self.Lb1 = Listbox(self.bottom).place(x = 5, y = 140) def updateListBox(self): pass RE: Using Tkinter widgets on child window - Larz60+ - Jan-30-2020 you are missing a pack command for self.Lb1 RE: Using Tkinter widgets on child window - chewy1418 - Jan-31-2020 I tried using the .pack() method, but I still can't get the .insert() to work (Usually the methods associated with the Listbox comes up after I type variableName.). I can, however, do this in my main.py file without any issue. I am guessing this is because I define root = Tk() and then pass that to my Application class. Is my other class not inheriting the Tk()? RE: Using Tkinter widgets on child window - Larz60+ - Jan-31-2020 I don't see anywhere in your code where one class creates an instance of the other. in addition, the module containing the class must be imported. -- Edit -- I see here: def search(self): S = Search.Search()but still no import, and this is not the proper way to create the instance of search as a new instance will be created every time search is called RE: Using Tkinter widgets on child window - chewy1418 - Jan-31-2020 Totally forgot to include my imports in the original post which is below: # Misc & load functions from other file import pyodbc import AddTableAndFunction, Search import RatingRuleWhat would be the proper way to create an instance of my Search class? RE: Using Tkinter widgets on child window - Larz60+ - Jan-31-2020 instantiate in the __init__ clause of 1st program (you never specified name): from tkinter import * from tkinter import ttk from Search import Search class Application(object): def __init__(self, master): self.search = Search()but you also need to separate the __init__ stuff from procedure. create a method (def) (in Search.py) for the actual search operation then once instantiated as above, to search something use self.search.new_method_name(attributes) (use whatever you called new method)
RE: Using Tkinter widgets on child window - Marbelous - Feb-25-2020 This thread is a bit stale but since I just wasted over an hour on the same issue I feel I should remind all us Tkinter users (Guido help us!) about this gotcha. self.Lb1 = Listbox(self.bottom).place(x = 5, y = 140)Does NOT assign self.Lb1 to the Listbox object! It assigns it to the output of the .place() function. Which is "None", so pretty useless. Always do your Geometry Manager stuff (.grid, .pack or .place) on a separate line when you're assigning the object so you don't fall into this trap: self.Lb1 = Listbox(self.bottom) self.Lb1.place(x = 5, y = 140)It means more: But much less: RE: Using Tkinter widgets on child window - Larz60+ - Feb-26-2020 Quote:Does NOT assign self.Lb1 to the Listbox object! It assigns it to the output of the .place() function. Which is "None"I find this hard to believe as I have been using tkinter for years and have never seen this. That being said, I never combine a widget definition and a geometry on the same line but rather like your second snippet. RE: Using Tkinter widgets on child window - Marbelous - Feb-27-2020 Yeah, strange but true: https://stackoverflow.com/questions/28555295/python3-tkinter-grid-and-pack-inline-packing-syntax-elegance It's also the reason why the OP is getting his: AttributeError: 'NoneType' object has no attribute 'insert' Because on line 34 in his Second Window code he's in-lining the .place() function so now his self.Lb1 object is of type: None. self.Lb1 = Listbox(self.bottom).place(x = 5, y = 140)It's bitten me several times since I tend to favor compact, in-lined code. Quick example code: from tkinter import * # Just quick example code. Star imports are not a good idea! master = Tk() btn1 = Button(master, text="ONE") btn1.pack() btn2 = Button(master, text="TWO").pack() print(type(btn1)) print(type(btn2)) <class 'tkinter.Button'> <class 'NoneType'> Process finished with exit code 0 |