Reputation: 126
I am a newbie at programming. I'm using Tkinter in Python. I am trying to make it so the labels in my program will be side by side with one another (with a little space in between, maybe like 50 pixels). The two labels I would like to have side by side are: "ingredients" and "steps". I have tried creating a frame so that they could be next to each other, but the ingredients is always above the steps, not side by side. I looked at other questions on StackOverflow but I couldn't quiet apply them to my program. So can I make it so my two labels, steps and ingredients, are side by side with some space in between. Would I continue using the frame or would I use .grid or something else?
Any help is greatly appreciated!! And if you could add comments in your code so I know what you are doing, that would be great! Thank you!
import Tkinter
class Cookbook(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.title("Cookbook")
self.geometry("500x500+0+0")
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("550x500")
def title_box(self):
#Frame for the Title Label and the Title Entry Box
test = Tkinter.Frame(self, height=100, relief=Tkinter.SUNKEN)
test.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
#putting in a Title LABEL and ENTRY BOX
Tkinter.Label(test,text="Title:").pack(anchor=Tkinter.NW,side=Tkinter.LEFT)
self.entry1 = Tkinter.Entry(test,width=450)
self.entry1.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
def ingredients_box(self):
#Frame for the Ingredients Label and the Ingredients Entry Boxes
self.test2 = Tkinter.Frame(self, height=100,width=20, relief=Tkinter.SUNKEN)
self.test2.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
#Put an Ingredients label at the top of the window and anchor it there
Tkinter.Label(self.test2,text="Ingredients:").pack(anchor=Tkinter.NW,side=Tkinter.TOP)
def steps_box(self):
#Frame for the Steps Label and the Steps Textbox
test3 = Tkinter.Frame(self, height=100,width=50, relief=Tkinter.SUNKEN)
test3.pack(anchor=Tkinter.NE,side=Tkinter.RIGHT)
#putting in an entry box and Steps label for the steps of the recepie
Tkinter.Label(test3,text="Steps:").pack(anchor=Tkinter.N,side=Tkinter.TOP)
self.entry2 = Tkinter.Text(test3,width=40,height=33,font="helvetica 12",padx=5,pady=5).pack(anchor=Tkinter.NE,side=Tkinter.TOP)
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.test2)
entry.pack(anchor=Tkinter.NW,side=Tkinter.TOP)
self.ingredient_entries.append(entry)
# get contents of all entry boxes
def save_recipe(self):
for words in self.title_entries:
print words.get()
for ingredient in self.ingredient_entries:
print ingredient.get()
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
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_recipe, 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()
Upvotes: 1
Views: 9037
Reputation: 386315
The first thing you need to do is change your style of programming slightly. You are putting the requirement to pack a widget within the function that creates the widget, which makes managing your code really difficult. Instead, the caller of a function that creates a widget should be responsible for packing (placing, gridding) it.
For example, instead of:
def make_window(self):
...
popwindow.ingredients_box()
popwindow.steps_box()
...
def steps_box(self):
#Frame for the Steps Label and the Steps Textbox
test3 = Tkinter.Frame(self, height=100,width=50, relief=Tkinter.SUNKEN)
test3.pack(anchor=Tkinter.NE,side=Tkinter.RIGHT)
You should do something like this:
def make_window(self):
...
ingredients_box = popwindow.ingredients_box(self)
steps_box = popwindow.steps_box(self)
...
ingredients_box.pack(side="left")
steps_box.pack(side="right")
def ingredients_box(self, parent):
#Frame for the Steps Label and the Steps Textbox
test3 = Tkinter.Frame(parent, height=100,width=50, relief=Tkinter.SUNKEN)
test3.pack(anchor=Tkinter.NE,side=Tkinter.RIGHT)
return test3
That by itself won't solve your problem, but it will make it easier to solve. The next step is to take a look at your overall layout, and realize that using a grid is a more natural layout than using pack.
When you do that, it becomes pretty simple to change just the one function that is responsible for laying out the GUI rather than the myriad of functions that try to both create widgets and lay them out.
With that, you can then do:
def make_window(self):
ingredients_box = ...
steps_box = ...
...
ingredients_box.grid(row=1, column=0, sticky="nsew")
steps_box.grid(row=1, column=1, sticky="nsew")
...
The overall layout becomes much easier to visualize in the code, and much easier to reconfigure (which will inevitiably happen)
Notes:
You have a bug in that you are creating more than one instance of Tk
. If you need to create a popup window, create an instance of Toplevel
. Tk
should be reserved for the root window, and only the root window.
You also have a bug in this statement:
self.entry2 = Tkinter.Text(test3,...).pack(...)
In python, when you do x=y().z()
, x
gets the value of .z()
. In Tkinter, pack
always returns None
, so self.entry2
will be set to None
.
Upvotes: 0
Reputation: 704
If you wish for two labels to be side by side you can simply use the pack manager to pack them to the same side like so:
testlabel.pack(side=Tkinter.LEFT)
testlabel2.pack(side=Tkinter.LEFT)
However the preferred way would be to use the grid manager for things like this. To align two labels you would do something like this:
testlabel.grid(row=0, column=0)
testlabel2.grid(row=0, column=1)
If you are talking about how to use them with frames, it would be something like this:
labelframe = Tkinter.Frame()
testlabel = Tkinter.Label(labelframe)
testlabel2 = Tkinter.Label(labelframe)
testlabel.grid(row=0, column=0)
testlabel2.grid(row=0, column=1)
labelframe.pack()
This would group the two labels together inside of that frame which you can then align in your main window. However if you have a bunch of labels and you all want them side by side like a table you could probably just get away with using grid for the main window. You tend to use frames when you want to group widgets together and move them to specific places in relation to other widgets.
Upvotes: 0