问题
Is it even possible to set the absolute position of a grid within Tkinter? I am trying to create a GUI that looks like the one below, but I am probably going about it the wrong way. So if it is possible, how do you set the grid position?
Target GUI:
This is how my GUI is turning out, so far:
As you can see, my New Contact needs to be on the right, while the Contact List should be on the left. I understand how to move the Contact List using absolute values, but can I do the same for my grid elements? Or should I use absolute values with all of them, combined with padding?
Currently, this is my code:
from tkinter import *
contacts=['Justin Day']
class Contact_manager (Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Contact Manager")
self.pack(fill=BOTH, expand=1)
#New contact grid
Label (self, text = "New Contact").grid (row=0, columnspan=2)
Label (self, text = "First Name:").grid (row=1, sticky=E)
Label (self, text = "Last Name:").grid (row=2, sticky=E)
Label (self, text = "Phone#").grid (row=3, sticky=E)
self.entry1 = Entry(self)
self.entry2 = Entry(self)
self.entry3 = Entry(self)
self.entry1.grid (row=1, column=1)
self.entry2.grid (row=2, column=1)
self.entry3.grid (row=3, column=1)
friend_check = IntVar()
self.friend_check = Checkbutton (self, variable = friend_check,
command = self.friend_box,
text = "Friend")
self.friend_check.grid (row=4, columnspan=2)
Label (self, text = "Email:").grid (row=5, sticky=E)
Label (self, text = "Birthday:").grid (row=6, sticky=E)
self.entry4 = Entry(self)
self.entry5 = Entry(self)
self.entry4.grid (row=5, column=1)
self.entry5.grid (row=6, column=1)
#Contact listbox
Label (self, text = "Contact List").place(x=20, y=190)
contact_lb = Listbox(self)
for i in contacts:
contact_lb.insert(END, i)
contact_lb.bind("<<ListboxSelect>>", self.onSelect)
contact_lb.place(x=20, y=210)
def onSelect(self, val):
sender = val.widget
idk = sender.curselection()
value = sender.get(idx)
self.var.set(value)
def friend_box():
if friend_check.get() == 1:
contacts.append(Friend(f, l, p, e, bd))
else:
contacts.append(Person(f, l, p))
def main():
root = Tk()
ex = Contact_manager(root)
root.geometry('600x700+200+100')
root.mainloop()
if __name__ == '__main__':
main()
回答1:
You should take a divide-and-conquer approach to laying out widgets in a GUI. Don't try to do everything at once or use one geometry manager to coordinate everything in one window. Be methodical, and tackle one small problem at a time.
For example, in your target GUI it appears you have four sections: the contact list, a search box and button, a new contact form, and something in the lower right corner (search results?). If I am correct that those are four distinct areas, start by creating four frames. Use grid to place them in the four corners of the main window. Give each frame a distinct color (for debugging purposes). Now, fiddle with options until those four areas grow and shrink in the way that you want. Make sure you give the columns and rows weight so that they all resize properly.
Now that you've done that, you have four smaller, more manageable layout problems. Now, it could be that I'm wrong -- maybe you have two areas, left and right. Or maybe you have three -the left, and then the upper right and the lower right. For now we'll assume I'm right but the technique remains the same regardless.
It looks like you already have the layout for the contact form, so move those into the upper-right frame. Make sure they all expand and shrink properly when you grown and shrink the window (and thus, you grow and shrink the containing frame).
Once you have done that, work on the next section -- put the contact list in the upper left corner. Again, make sure it all resizes properly. At this point you shouldn't have to worry about the widgets on the right because you already have those sorted out. For this section you don't need grid, you can use pack since it's just a couple widgets stacked on top of each other. However, you can use whichever makes the most sense.
Continue on this way, working on the remaining two corners of the GUI. Be methodical, and tackle small independent sections one at a time.
回答2:
Here is something that looks much closer to what you need:
from tkinter import *
contacts=['Justin Day']
class Contact_manager (Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Contact Manager")
self.pack(fill=BOTH, expand=1)
#New contact grid
Label (self, text = "New Contact").grid (row=0, column=2, columnspan=2, sticky=W)
Label (self, text = "First Name:").grid (row=1, column=1, sticky=E)
Label (self, text = "Last Name:").grid (row=2, column=1, sticky=E)
Label (self, text = "Phone#").grid (row=3, column=1, sticky=E)
self.entry1 = Entry(self)
self.entry2 = Entry(self)
self.entry3 = Entry(self)
self.entry1.grid (row=1, column=2)
self.entry2.grid (row=2, column=2)
self.entry3.grid (row=3, column=2)
friend_check = IntVar()
self.friend_check = Checkbutton (self, variable = friend_check,
command = self.friend_box,
text = "Friend")
self.friend_check.grid (row=4, column=2, columnspan=2)
Label (self, text = "Email:").grid (row=5, column=1, sticky=E)
Label (self, text = "Birthday:").grid (row=6, column=1, sticky=E)
self.entry4 = Entry(self)
self.entry5 = Entry(self)
self.entry4.grid (row=5, column=2)
self.entry5.grid (row=6, column=2)
#Contact listbox
Label (self, text = "Contact List").grid(row=0)
contact_lb = Listbox(self)
for i in contacts:
contact_lb.insert(END, i)
contact_lb.bind("<<ListboxSelect>>", self.onSelect)
contact_lb.grid(row=1, rowspan=5)
def onSelect(self, val):
sender = val.widget
idk = sender.curselection()
value = sender.get(idx)
self.var.set(value)
def friend_box():
if friend_check.get() == 1:
contacts.append(Friend(f, l, p, e, bd))
else:
contacts.append(Person(f, l, p))
def main():
root = Tk()
ex = Contact_manager(root)
root.geometry('600x700+200+100')
root.mainloop()
if __name__ == '__main__':
main()
I am not sure if you should mix .grid() and .place(), as far as I know, you shouldn't mix .pack() and .grid(). Anyway I would try not to mix any of them.
And about main question 'how do you set position of a grid', well, just try to draw what you expect on paper, and try to divide it into rows and columns...
回答3:
I did something similar, check it out:
from Tkinter import Tk, N, S, W, E, BOTH, Text, Frame,Label, Button,Checkbutton, IntVar,Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Windows")
Label(text="Contact List").grid(row=0,column=0,columnspan=2)
Text(width=30,height=15).grid(row=1,rowspan=9, column=0,columnspan=2,padx=20)
Button(text="Display Contact").grid(row=10, column=0,columnspan=2,pady=10)
Label(text="Last Name:").grid(row=11, column=0,pady=10)
Entry().grid(row=11,column=1)
Button(text="Search").grid(row=12,column=0,columnspan=2)
Label(text="New Contact").grid(row=0,column=2,columnspan=2)
Label(text="First Name:").grid(row=1,column=2,sticky=E)
Entry().grid(row=1,column=3)
Label(text="Last Name:").grid(row=2,column=2,sticky=E)
Entry().grid(row=2,column=3)
Label(text="Phone #:").grid(row=3,column=2,sticky=E)
Entry().grid(row=3,column=3)
friend_check = IntVar()
Checkbutton(variable=friend_check, command = self.friend_box, text = "Friend").grid(row=4,column=3,sticky=W)
#Label(text="Friend").grid(row=4,column=3,padx=20,sticky=W)
Label(text="Email:").grid(row=5,column=2,sticky=E)
Entry().grid(row=5,column=3)
Label(text="Birthday:").grid(row=6,column=2,sticky=E)
Entry().grid(row=6,column=3)
Button(text="Add Contact").grid(row=7,column=3,sticky=E)
def friend_box(self):
if friend_check.get() == 1:
print '1'
else:
print '0'
def main():
root = Tk()
root.geometry("600x450+900+300")
root.resizable(0,0)
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
来源:https://stackoverflow.com/questions/16315732/how-do-you-set-the-position-of-a-grid-using-tkinter