I have a program that is suppose to create a new Toplevel widget and then add a frame to it. Both the toplevel and frame classes are already created separately so when they are called my window fills automatically. But when the button is clicked the Toplevel window pops up but the frame adds itself to the main window and not the new Toplevel
Main window code
class MainWindow(Tkinter.Tk):
def __init__(self,version):
Tkinter.Tk.__init__(self) # creates the main window
self.title('Awana Control ' + version) # names the main window
topframe = Tkinter.Frame(self)
topframe.grid(column=0,row=0)
openNewFamilyWindowButton = Tkinter.Button(topframe, text='Add a new family',command=partial(newWindow,'NewFamilyWindow'))
openNewFamilyWindowButton.grid(row=0, column=0)
#openEditStudentWindowButton = Tkinter.Button(topframe, text='edit current repository', command=partial(newWindow,'studentFinderWindow'))
#openEditStudentWindowButton.grid(row=0, column=1)
openTotalsWindowButton = Tkinter.Button(topframe, text='Total Shipping Orders', command=partial(newWindow,'totalsWindow'))
openTotalsWindowButton.grid(row=0, column=1)
openTotalsWindowButton = Tkinter.Button(topframe, text='Lists By Grade', command=partial(newWindow,'gradeList'))
openTotalsWindowButton.grid(row=0, column=2)
#bottomframe = Tkinter.Frame(self)
#bottomframe.grid(column=0,row=1)
right here is when it adds the student
finder window class to the main
window. This class is responsible for
opening the new toplevel windows
StudentFinderWindow().grid(column=0,row=1)
self.mainloop()
here is the StudentFinderWindow class
class StudentFinderWindow(Tkinter.Frame):
def __init__(self):
Tkinter.Frame.__init__(self) # Create Window
##### window attributes
#self.title('Edit Families') #sets window title
##### puts stuff into the window
# text
editStudentInfoLabel = Tkinter.Label(self,text='Select the family from the list below or search for one in the search box provided')
editStudentInfoLabel.grid(row=0, column=0)
# entry box
self.searchRepositoryEntry = Tkinter.Entry(self)
self.searchRepositoryEntry.grid(row=1, column=0)
# list box
self.searchResults = Tkinter.Listbox(self,selectmode='SINGLE')
self.searchResults.grid(row=2, column=0)
# create a vertical scrollbar to the right of the listbox
#yscroll = Tkinter.Scrollbar(self, command=self.searchResults.yview, orient=Tkinter.VERTICAL)
#yscroll.grid(row=0, column=1, sticky=Tkinter.N+Tkinter.S)
#self.searchResults.configure(yscrollcommand=yscroll.set)
# search results initial updater
self.getStudentList()
for student in self.studentList:
self.searchResults.insert(Tkinter.END, student)
##### event handler
self.searchResults.bind('<Double-Button-1>',self.editStudentWindowInit )
self.searchRepositoryEntry.bind('<KeyRelease>', self.updateSearch)
def updateSearch(self, event):
parameters = self.searchRepositoryEntry.get()
parameters = parameters.lower()
length = len(parameters)
self.searchResults.delete(0, Tkinter.END)
for i in self.studentList:
if i[0:length].lower() == parameters:
self.searchResults.insert(Tkinter.END, i)
def getStudentList(self):
global fileDirectory # gets the directory that all the files are in
fileList = os.listdir(fileDirectory) # makes a list of files from the directory
self.studentList = [] # makes a new list
for file in fileList: # for loop that adds each item from the file list to the student list
if file[-3:] == 'txt':
self.studentList.append(file[:-4])
This is the function that opens the new window which is suppose to fill itself with a frame
def editStudentWindowInit(self,mevent):
index = self.searchResults.curselection()
student = self.searchResults.get(index)
editStudentWindow = EditStudentWindow(student)
Here is the class that is opened
class EditStudentWindow(Tkinter.Toplevel):
def __init__(self,student):
Tkinter.Toplevel.__init__(self)
self.title('Edit Family Info')
Tkinter.Button(self,text='Edit Info',command=partial(self.fillInfo,student)).grid(column=0,row=0)
Tkinter.Button(self,text='Edit Orders',command=partial(self.fillOrder,student)).grid(column=1,row=0)
self.fillInfo(student)
def fillInfo(self,student):
try:
self.order.grid_forget()
except:
pass
self.info = EditFamilyWindow(student)
self.info.grid(column=0,row=1)
def fillOrder(self,student):
try:
self.info.grid_forget()
except:
pass
self.order = EditShippingWindow(student)
self.order.grid(column=0,row=1)
and here is the init of the frame class
class EditFamilyWindow(Tkinter.Frame):
def __init__(self,student):
Tkinter.Frame.__init__(self)
The bottom line is, your frame must be created as a descendant of a specific toplevel. You can't reparent a frame from one toplevel to another. So, for your code to work you must create the toplevel first, and then create your frame and tell it which toplevel to be created in.
Related
I'm writing a portion of code which is supposed to behave the following way:
Display a listbox of items.
The user selects one or more items from the listbox.
The user clicks a seperate button widget to confirm the selection.
The toplevel window closes once the user clicked the button.
The selection is saved so that other portions of the program can access it.
I have the following code (code not relevant to the question is omitted):
class MainWin(tk.Tk):
# ... omitted code
def dia(self):
'''
This creates a toplevel window that displays the listbox.
'''
TL = dialogWin(self)
MainWin.wait_window(TL)
class dialogWin(tk.Toplevel):
'''
This window creates and displays the listbox.
'''
def __init__(self, MainWin):
# ... omitted code
# ...
B = tk.Button(self, text = 'Confirm', command = self.getChoices).grid(row = 3) #This is the button that the user clicks to confirm the selection
#create listbox
self.LB = tk.Listbox(self, height = 10, width = 45, selectmode = 'multiple')
# ... code to configure the listbox appearence
def getChoices(self):
'''
This is the callback function the listbox uses.
'''
choice = self.LB.curselection()
self.destroy()
return choice
That's the code that I have but I can't seem to find a way to actually access the information stored in choice. For instance if I edit dia(self) to confirm the return value, like so:
def dia(self):
TL = dialogWin(self)
MainWin.wait_window(TL)
print(TL.getChoices())
I get the error _tkinter.TclError: invalid command name ".!dialogwin.!listbox". TL.getChoices().get() gives me the same error. What I want is the selected information to be saved as something like (1, 2, 3) where I can then access the tuple from the main window. Is there something I've done wrong here?
You are very close. You can no longer use tkinter widget methods after a window is destroyed, but you can use your own methods and attributes:
import tkinter as tk
class MainWin(tk.Tk):
def __init__(self):
super().__init__()
tk.Button(self, text='click me', command=self.dia).pack()
self.geometry('200x200')
def dia(self):
TL = dialogWin(self)
MainWin.wait_window(TL)
print(TL.choice)
class dialogWin(tk.Toplevel):
def __init__(self, MainWin):
super().__init__(MainWin)
B = tk.Button(self, text = 'Confirm', command = self.getChoices).grid(row = 3) #This is the button that the user clicks to confirm the selection
#create listbox
self.LB = tk.Listbox(self, height = 10, width = 45, selectmode = 'multiple')
self.LB.grid()
for x in range(10):
self.LB.insert(tk.END, f"this is item {x}")
def getChoices(self):
self.choice = self.LB.curselection() # <== save the choice as an attribute
self.destroy()
MainWin().mainloop()
You could also save it as an attribute of the main window if you wanted to:
def getChoices(self):
self.master.choice = self.LB.curselection()
self.destroy()
Or any other place really.
Since you have used .wait_window(), it means that you want the Toplevel() acts like a modal dialog.
Below is modified dialogWin() to act like a modal dialog:
class dialogWin(tk.Toplevel):
'''
This window creates and displays the listbox.
'''
def __init__(self, MainWin):
super().__init__(MainWin)
# initialize empty selected choice
self.choice = ()
# ... omitted code
# ...
tk.Button(self, text='Confirm', command=self.getChoices).grid(row=3) #This is the button that the user clicks to confirm the selection
#create listbox
self.LB = tk.Listbox(self, height=10, width=45, selectmode='multiple')
# ... code to configure the listbox appearence
def getChoices(self):
'''
This is the callback function the listbox uses.
'''
# save the selected choices
self.choice = self.LB.curselection()
self.destroy()
# added function to be called like a dialog
def show(self):
self.wait_visibility()
self.grab_set()
self.master.wait_window(self)
# return the selected choices
return self.choice
Then you can use dialogWin as a modal dialog inside MainWin:
class MainWin(tk.Tk):
def __init__(self):
super().__init__()
# ... omitted code
def dia(self):
'''
This creates a toplevel window that displays the listbox.
'''
choice = dialogWin(self).show()
print(choice)
This is my first real Python project. I am currently developing a GUI in Tkinter that allows the user to select Tasks and CVs to automatically compile documents using standard predefined task and CV texts from a database.
I have created two "Add" buttons in the main window to add Tasks and CVs that show a popup Listbox that allow the user to select the Tasks and CVs they want to have included in the commercial proposal. I have managed to create the popup window as a separate Class and it stores the selected Tasks in a list, but now I need to pass the list with the selected items to the Listbox in the main window when the user clicks the Select button in the popup window, but I cannot get my head around on how to do that.
I have researched on different fora and watched a variety of Youtube videos, but all focus on entry popups or some sort.
This is the code for the main window:
from tkinter import *
from Add import *
# make main window
root = Tk()
theLabel = Label(root, text="ProposalBuilder")
theLabel.grid(row=0)
# make frames
taskFrame = Frame(root)
taskFrame.grid(row=1, column=0)
CVFrame = Frame(root)
CVFrame.grid(row=1, column=1)
buildFrame = Frame(root)
buildFrame.grid(row=2, columnspan=2)
# add labels to frames
taskLabel = Label(taskFrame, text="Tasks")
taskLabel.pack()
CVLabel = Label(CVFrame, text="CVs")
CVLabel.pack()
# add listboxes to frames
scrollTask = Scrollbar(taskFrame, orient=VERTICAL)
listTask = Listbox(taskFrame, selectmode=MULTIPLE, yscrollcommand=scrollTask.set)
scrollTask.config(command=listTask.yview)
scrollTask.pack(side=RIGHT, fill=Y)
listTask.pack()
scrollCV = Scrollbar(CVFrame, orient=VERTICAL)
listCV = Listbox(CVFrame, selectmode=MULTIPLE, yscrollcommand=scrollCV.set)
scrollCV.config(command=listCV.yview)
scrollCV.pack(side=RIGHT, fill=Y)
listCV.pack()
# add commands to buttons
def addTask():
taskBox = Add('C:\\Users\\204703\\ProposalBuilder\\Database')
sel_test = taskBox.selection
def addCV():
CVBox = Add('C:\\Users\\204703\\ProposalBuilder\\Database')
# add buttons to frames
buttonAddTask = Button(taskFrame, text="Add", command=addTask)
buttonAddTask.pack(fill=X)
buttonDelTask = Button(taskFrame, text="Delete")
buttonDelTask.pack(fill=X)
buttonUpTask = Button(taskFrame, text="Up")
buttonUpTask.pack(fill=X)
buttonDownTask = Button(taskFrame, text="Down")
buttonDownTask.pack(fill=X)
buttonAddCV = Button(CVFrame, text="Add", command=addCV)
buttonAddCV.pack(fill=X)
buttonDelCV = Button(CVFrame, text="Delete")
buttonDelCV.pack(fill=X)
buttonUpCV = Button(CVFrame, text="Up")
buttonUpCV.pack(fill=X)
buttonDownCV = Button(CVFrame, text="Down")
buttonDownCV.pack(fill=X)
buttonBuild = Button(buildFrame, text="Build Proposal")
buttonBuild.pack(side=RIGHT)
root.mainloop()
This is the code for the separate class I created for the popup window:
from tkinter import*
from os import *
class Add:
def __init__(self, path):
# the slected tasks
self.selection = []
# make a frame
top = Toplevel()
# get file names from the directory (path) and save in list
self.path = path
self.dirList = listdir(self.path)
# add listbox to frames and populate with file names
self.scrollList = Scrollbar(top, orient=VERTICAL)
self.listbox = Listbox(top, selectmode=MULTIPLE, yscrollcommand=self.scrollList.set)
self.scrollList.config(command=self.listbox.yview)
self.scrollList.pack(side=RIGHT, fill=Y)
for item in self.dirList:
self.listbox.insert(END,item)
self.listbox.pack()
# add buttons to frame
self.selectButton = Button(top, text="Select", command=self.select)
self.selectButton.pack()
self.quitButton = Button(top, text="Quit", command=top.destroy)
self.quitButton.pack()
# identify selected rows and return a list with the selection
def select(self):
selectedRows = self.listbox.curselection()
for item in selectedRows:
self.selection.append(self.dirList[item])
print(self.selection)
return self.selection
Question: pass the list with the selected items to the Listbox in the main window
You need a reference of the main window Listbox.
I show, how to using listTask
Extend your __init__ to accept the reference target_listbox
class Add:
def __init__(self, target_listbox, path):
self.target_listbox = target_listbox
Insert the selected items into .target_listbox
Note: Your, return self.selection is useless, a Button.command can't process returns.
def select(self):
selectedRows = self.listbox.curselection()
for item in selectedRows:
self.target_listbox.insert(tk.END, self.dirList[item])
Pass the reference listTask to Add(...
taskBox = Add(listTask, ...)
I have been studying very hard to learn OOP. I understand that objects can be an instance of a class. Classes have parameters and methods and are like an 'object constructor' which the object is created from. I am reorganizing the code in my first project to allow whatever possible to be part of a class. Right now I am working on the GUI but I am having trouble understanding the process in constructing the GUI with classes. Particularly having tabs inside the class and adding objects into each tab.
Here is an example of how my code currently looks:
import tkinter
from tkinter import ttk
class Win:
def __init__(self, master):
nb = ttk.Notebook(master, width=390, height=470)
nb.pack()
tab = ttk.Frame(nb)
nb.add(tab, text='title')
tab2 = ttk.Frame(nb)
nb.add(tab2, text='Graphs')
tab3 = ttk.Frame(nb)
nb.add(tab3, text='Messages')
tab4 = ttk.Frame(nb)
nb.add(tab4, text='Instructions')
label = tkinter.Label(tab, text='text')
label.grid(row=0, column=0, sticky=tkinter.N, pady=10)
menu = tkinter.Menu(master, tearoff=False)
master.config(menu=menu)
subMenu = tkinter.Menu(menu, tearoff=False)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_separator()
subMenu.add_command(label='Exit', command=master.destroy)
root = tkinter.Tk()
root.title("SC")
root.geometry('400x500')
root.resizable(width=False, height=False)
main_win = Win(root)
root.mainloop()
To put objects in each tab within main_win, what do I do? I tried putting objects below main_win and then passing the parameter main_win in the object but that does not seem to work. Should I have a class for making tabs then create an object tab and pass new objects into that?
Thanks in advance for the help. Was unable to find this specific answer anywhere.
This code shows one way of adding things to the Notebook tabs. It implements some of abarnert's suggestions, plus a few of my own ideas. I've separated the Notebook off into its own class, and moved the Tk root initialization code into the main GUI class.
I don't claim that this is the best way to do these things, I'm just illustrating a few possibilities to inspire you. ;)
import tkinter as tk
from tkinter import ttk
class GUI(tk.Tk):
def __init__(self):
super().__init__()
self.title("SC")
self.geometry('400x500')
self.resizable(width=False, height=False)
names = ['Title', 'Graphs', 'Messages', 'Instructions']
self.nb = self.create_notebook(names)
self.menu = self.create_menus()
# We can also add items to the Notebook here
tab = self.nb.tabs['Instructions']
tk.Label(tab, text='You should\nread these\ninstructions').pack()
self.mainloop()
def create_notebook(self, names):
nb = MyNotebook(self, names)
nb.pack()
def add_label(parent, text, row, column):
label = tk.Label(parent, text=text)
label.grid(row=row, column=column, sticky=tk.N, pady=10)
return label
# Add some labels to each tab
tab = nb.tabs['Title']
for i in range(3):
add_label(tab, 't' + str(i), i, 0)
tab = nb.tabs['Graphs']
for i in range(3):
add_label(tab, 'g' + str(i), 0, i)
tab = nb.tabs['Messages']
for i in range(3):
add_label(tab, 'm' + str(i), i, i)
return nb
def create_menus(self):
menu = tk.Menu(self, tearoff=False)
self.config(menu=menu)
subMenu = tk.Menu(menu, tearoff=False)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_separator()
subMenu.add_command(label='Exit', command=self.destroy)
return menu
class MyNotebook(ttk.Notebook):
''' A customised Notebook that remembers its tabs in a dictionary '''
def __init__(self, master, names):
super().__init__(master, width=390, height=470)
# Create tabs & save them by name in a dictionary
self.tabs = {}
for name in names:
self.tabs[name] = tab = ttk.Frame(self)
self.add(tab, text=name)
GUI()
I do most of the work of creating the Notebook and the Menu in separate methods of GUI. I could have put that code inside GUI.__init__ but it's more modular to do it in separate methods, and it stops the .__init__ method from getting huge.
I've saved the Notebook & Menu as instance attributes self.nb and self.menu. That's not really necessary here, they could just be local variables of GUI.__init__, eg, nb and menus. But storing them as attributes makes them accessible from other methods of GUI, which may be necessary when you add more stuff to the class.
When you derive a class from a parent class, like MyNotebook from ttk.Notebook (or GUI from tk.Tk), if the child class doesn't have its own __init__ method then the parent's __init__ will automatically get called when you create a child instance. But if the child has its own __init__ then the parent __init__ won't get called automatically. But we need the stuff in the parent __init__ to get done to our new instance of MyNotebook in order for the stuff that inherits from ttk.Notebook to be initialized. So the MyNotebook.__init__ does the super call to make that happen.
Generally, if a child class doesn't define a method that the parent class defines then when that method is called on a child instance the version from the parent will be called. And if the child does redefine an inherited method you will often want to call the parent method inside the child method at same stage, and it's usual to use super to do that. __init__ is a bit special because it normally gets called automatically to initialize the instance after it's been created.
Here's a simpler version that doesn't use child classes. It also has a Button widget on the root window which prints a string when you click it.
import tkinter as tk
from tkinter import ttk
class GUI:
def __init__(self):
root = tk.Tk()
root.title("SC")
root.geometry('400x500')
root.resizable(width=False, height=False)
names = ['Title', 'Graphs', 'Messages', 'Instructions']
self.nb = self.create_notebook(root, names)
self.menu = self.create_menus(root)
# We can also add items to the Notebook here
tab = self.nb.tabs['Instructions']
tk.Label(tab, text='You should\nread these\ninstructions').pack()
btn = tk.Button(root, text='Click', command=self.button_command)
btn.pack()
root.mainloop()
def button_command(self):
print('The button was clicked')
def create_notebook(self, root, names):
nb = ttk.Notebook(root, width=390, height=450)
nb.pack()
# Create tabs & save them by name in a dictionary
nb.tabs = {}
for name in names:
nb.tabs[name] = tab = ttk.Frame(root)
nb.add(tab, text=name)
def add_label(parent, text, row, column):
label = tk.Label(parent, text=text)
label.grid(row=row, column=column, sticky=tk.N, pady=10)
return label
# Add some labels to each tab
tab = nb.tabs['Title']
for i in range(3):
add_label(tab, 't' + str(i), i, 0)
tab = nb.tabs['Graphs']
for i in range(3):
add_label(tab, 'g' + str(i), 0, i)
tab = nb.tabs['Messages']
for i in range(3):
add_label(tab, 'm' + str(i), i, i)
return nb
def create_menus(self, root):
menu = tk.Menu(root, tearoff=False)
root.config(menu=menu)
subMenu = tk.Menu(menu, tearoff=False)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_separator()
subMenu.add_command(label='Exit', command=root.destroy)
return menu
GUI()
I have a Tkinter GUI having 2 entry fields, 2 buttons ( initialization of these not shown in code). There is one more button (initialized in code) which performs the main task of performing change detection on two images. Also there is a progress bar.
Now, when the task of change detection has been completed, I want to display the 4 images(pre, post, aligned, chng) returned by wave.changedetection() in a separate Tkinter window. I want the new window to come only after changedetection() has completed.(wave.py is my own file, not some module)
Unfortunately, if I try to add code to make new window, Tk.Toplevel() ,after the wave.changedetection() call, nothing happens and the main GUI window becomes unresponsive and has to be killed.
There is no way to know when the new created thread (start_thread)completes it's work, so that I can do Tk.Toplevel() there.
How can I do what I require?
class GUI(Tkinter.Tk):
def __init__(self, parent)
Tkinter.Tk.__init__(self, parent)
self.parent = parent
self.initialize()
def initialize(self):
self.button = Tkinter.Button(text = "Start")
self.button.bind('<Button-1>', self.OnButtonClick)
self.button.pack()
self.int = Tkinter.IntVar()
self.pgbar = Tkinter.ProgressBar(variable = self.int, mode = determinate)
def OnButtonClick(self,event):
#this func has been made since I have more buttons.It may seem redundant here
self.button['command'] = self.start_thread()
self.update_idletasks()
def start_thread(self):
self.int_var.set(1)
q = queue.Queue()
self.secondary_thread = threading.Thread(target = self.change)
self.secondary_thread.start()
self.after(50, self.check_queue, q)
def check_queue(self, q):
while True:
try:
x = wave.q.get_nowait()
except queue.Empty :
self.after(50,self.check_queue,q)
break
else:
self.int_var.set(x)
if x == 6:
self.button3['state'] = 'normal'
break
def change(self):
'''The 6 functions of wave.changedetection() change the value of self.int
due to which progress bar progresses.'''
pre, post, aligned, chng = wave.changedetection(self.entry_1.get(),
self.entry_2.get())
if __name__ == '__main__':
gui = GUI(None)
gui.mainloop()
code to update progress bar taken from here (2nd answer,Honest Abe's answer)
You have to be able to differentiate name spaces, i.e. this is in the main window and this is in the Toplevel. I would suggest that you get the Toplevels working first and then decide if you want to add threading or not. The code below is a simple example of creating Toplevels and shows how to place widgets in a specific name space (window in this case). You may or may not want a separate "create a Toplevel" class if there are functions you want to associate with each Toplevel's namespace. Also there are examples on the web on using Tkinter's "after" to update a progressbar. That is a different question so start another thread if you have questions about the progressbar.
try:
import Tkinter as tk ## Python 2.x
except ImportError:
import tkinter as tk ## Python 3.x
from functools import partial
class OpenToplevels():
""" open and close additional Toplevels with a button
"""
def __init__(self):
self.root = tk.Tk()
self.button_ctr=0
## in the "root" namespace *********************
but=tk.Button(self.root, text="Open a Toplevel",
command=self.open_another)
but.grid(row=0, column=0)
tk.Button(self.root, text="Exit Tkinter", bg="red",
command=self.root.quit).grid(row=1, column=0, sticky="we")
self.root.mainloop()
def close_it(self, id):
## destroy the window in this id's namespace ***********
id.destroy()
## id.withdraw()
## id.iconify()
def open_another(self):
self.button_ctr += 1
id = tk.Toplevel(self.root)
id.title("Toplevel #%d" % (self.button_ctr))
## in the "id for this Toplevel" namespace ***********
tk.Button(id, text="Close Toplevel #%d" % (self.button_ctr),
command=partial(self.close_it, id),
bg="orange", width=20).grid(row=1, column=0)
Ot=OpenToplevels()
Hi I am new to programming in Tkinter. I have written this program, which is in the making. I made a class called IngredientAdder() and within that class under the method def steps_box I have a variable self.entry2, which calls upon the Text Widget. When I run the program, the text box works fine. However, under my method def save_recipie I wrote for it to print words.get('1.0', 'end') into the terminal window when I press the button in the init.gui method (words.get corresponds with the text entered by the user in the text box called self.entry2). However, when I run the program and enter text into text box and press the save button, nothing is printed into my terminal window. How can I modify my code so that the user entered text in the text box is printed into my terminal window? Help?
If you could possibly add comments in your code, it would be very helpful!! Thanks.
import Tkinter
class Cookbook(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.title("Cookbook")
self.geometry("500x500+0+22")
self.button = []
for r in range(1):
for c in range(1):
b = Button(self).grid(row=r,column=c)
self.button.append(b)
class Button(Tkinter.Button):
def __init__(self,parent):
b = Tkinter.Button.__init__(self, parent, text="Add A New Recipie", height=8, width=15, command=self.make_window)
def make_window(self):
popwindow = IngredientAdder()
popwindow.title_box()
popwindow.ingredients_box()
popwindow.steps_box()
popwindow.init_gui()
class IngredientAdder(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.title("Recipie")
self.geometry("555x500")
def title_box(self):
#Frame for the Title Label and the Title Entry Box
self.frame1 = Tkinter.Frame(self, height=50, width=550, relief=Tkinter.SUNKEN)
self.frame1.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
self.frame1.pack_propagate(False)
#putting in a Title LABEL and ENTRY BOX
Tkinter.Label(self.frame1,text="Title:").pack(anchor=Tkinter.NW,side=Tkinter.LEFT)
self.entry1 = Tkinter.Entry(self.frame1,width=550)
self.entry1.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
def ingredients_box(self):
#Frame for the Ingredients Label and the Ingredients Entry Boxes & Steps label and Steps Textbox
self.frame2 = Tkinter.Frame(self, height=412,width=550, relief=Tkinter.SUNKEN)
self.frame2.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
self.frame2.pack_propagate(False)
# put an Ingredients label at the top of the window and anchor it there
ingredients_label = Tkinter.Label(self.frame2,text="Ingredients:").pack(anchor=Tkinter.NW,side=Tkinter.LEFT) #.grid(row=100, column=0)
def steps_box(self):
self.entry2 = Tkinter.Text(self.frame2,width=40,height=33,font="helvetica 12",padx=5,pady=5).pack(anchor=Tkinter.NW,side=Tkinter.RIGHT)
#putting in an entry box and Steps label for the steps of the recepie
steps_label = Tkinter.Label(self.frame2,text="Steps:").pack(anchor=Tkinter.NW,side=Tkinter.RIGHT) #.grid(row=100,column=1)
def title_save(self):
self.title_entries.append(self.entry1)
def text_box(self):
self.text_entries.append(self.entry2)
# function to add new ingredients
def add_ingredient_entry(self):
entry = Tkinter.Entry(self.frame2)
entry.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
self.ingredient_entries.append(entry)
# get contents of all entry boxes
def save_recipie(self):
print("Title:")
for words in self.title_entries:
print words.get()
print("Ingredients:")
for ingredient in self.ingredient_entries:
print ingredient.get()
print("Steps:")
for text in self.text_entries:
print text.get('1.0', 'end')
print "[Recipie saved]"
# build initial widgets
def init_gui(self):
# title saved in this array, hopefully...
self.title_entries = []
# this is a list of ingredients entry boxes
self.ingredient_entries = []
#this saves the list in this array, hopefully..
self.text_entries = []
#Making a frame at the bottom to put both buttons in line
self.test4 = Tkinter.Frame(self,height=10, relief=Tkinter.SUNKEN)
self.test4.pack(side=Tkinter.BOTTOM)
# Put these two buttons at the bottom of the window and anchor them there
Tkinter.Button(self.test4,text="Save recipe",command=self.save_recipie, width=15).pack(anchor=Tkinter.SE,side=Tkinter.RIGHT)
Tkinter.Button(self.test4,text="Add ingredient",command=self.add_ingredient_entry, width=15).pack(anchor=Tkinter.NW,side=Tkinter.LEFT)
# new ingredients will be added between the label and the buttons
self.add_ingredient_entry()
top = Cookbook()
top.mainloop()
The code
def steps_box(self):
self.entry2 = Tkinter.Text(self.frame2,width=40,height=33,font="helvetica 12",padx=5,pady=5).pack(anchor=Tkinter.NW,side=Tkinter.RIGHT)
register None into self.entry2. You should put
def steps_box(self):
self.entry2 = Tkinter.Text(self.frame2, width=40, height=33, font="helvetica 12", padx=5, pady=5)
self.entry2.pack(anchor=Tkinter.NW, side=Tkinter.RIGHT)
However, you didn't register self.entry2 into self.text_entries because you don't call your method text_box.