【问题标题】:Tkinter / Python grid layout with listboxes带有列表框的 Tkinter / Python 网格布局
【发布时间】:2013-01-11 20:08:22
【问题描述】:

我在使用带有 Tkinter 和 Python 的网格正确排列所有内容时遇到了一些麻烦。我想让菜单栏在最顶部,然后是两个列表框(每侧一个),在窗口中间有几个按钮。

目前,两个列表框都出现在窗口的右下角,按钮位于左上角,与菜单按钮重叠。

考虑到列表框的大小,如何处理列表框的网格布局。它们可以占据多个网格单元吗?例如,如果我在 (row=1, column = 1) 中放置一个列表框,在行 (row = 1, column = 2) 中放置另一个列表框,Tkinter 会自动加宽单元格,使其成为列表框的宽度,还是会只是重叠列表框?

def __init__(self,root):
    self.frame = Frame(root, width=500)
    self.frame.pack()
    self.BuildMainWindow(self.frame)
    self.ListboxSet = 0 
    self.frame.grid()
    return

#displays the menu bar and options
def BuildMainWindow(self, frame):
    menubar = Frame(frame,relief=RAISED,borderwidth=1)
    menubar.pack()

    mb_file = Menubutton(menubar,text='file')
    mb_file.menu = Menu(mb_file)
    mb_file.menu.add_command(label='open', command = self.openfile)
    mb_file.grid(row = 1, column = 1)

    mb_edit = Menubutton(menubar,text='edit')
    mb_edit.menu = Menu(mb_edit)
    mb_edit.grid(row=1, column = 3)

    mb_file['menu'] = mb_file.menu
    mb_edit['menu'] = mb_edit.menu

#upon selecting a directory from the menu and listboxes/buttons are created
def BuildListbox(self, directory):
    self.listbox1 = Tkinter.Listbox()
    self.listbox2 = Tkinter.Listbox()
    self.listbox1.grid(row=2, column=1)
    self.listbox2.grid(row=2 ,column=10)
    self.listbox2.bind('<<ListboxSelect>>', lambda e:SortActions.GetWindowIndex(self,e))
    self.listbox2.bind('<B1-Motion>', lambda e:SortActions.MoveWindowItem(self,e))

    i = 0
    for filename in sorted(os.listdir(directory)):
        self.listbox1.insert(i, filename)
        i = i + 1

    self.bAddToListTwo = Button(self.frame, text = "->", command = lambda:SortActions.AddToListTwo(self,self.listbox1.curselection()))
    self.bAddToListTwo.grid(row=5, column = 5)
    self.bAddAll = Button(self.frame, text = "Add All To Playlist", command = lambda:SortActions.AddAllFiles(self))
    self.bAddAll.grid(row=6, column = 5)
    self.bRemoveFromListTwo = Button(self.frame, text = "Remove From Playlist", command = lambda:SortActions.RemoveFromListTwo(self,self.listbox2.curselection()))
    self.bRemoveFromListTwo.grid(row=7, column = 5)
    self.bSavePlaylist = Button(self.frame, text = "Save Playlist", command = lambda:SortActions.SaveList(self))
    self.bSavePlaylist.grid(row=8, column = 5)

更新 - 我让它工作了。正如我所怀疑的,我在初始化期间有一些奇怪的框架配置。

def __init__(self,root):
    self.BuildMainWindow(root)
    self.ListboxSet = 0 
    return

#displays the menu bar and options
def BuildMainWindow(self, root):
    menubar = Menu(root)
    root.config(menu=menubar)

    # Create a menu button labeled "File" that brings up a menu
    filemenu = Menu(menubar)
    menubar.add_cascade(label='File', menu=filemenu)

    # Create entries in the "File" menu
    # simulated command functions that we want to invoke from our menus
    filemenu.add_command(label='Open', command=self.openfile)
    filemenu.add_separator(  )
    filemenu.add_command(label='Quit', command=sys.exit)

#upon selecting a directory from the menu and listboxes/buttons are created
def BuildListbox(self, directory):
    self.listbox1 = Tkinter.Listbox()
    self.listbox2 = Tkinter.Listbox()
    self.listbox1.grid(row=1, column=1, rowspan = 4, columnspan = 5)
    self.listbox2.grid(row=1 ,column=15, rowspan = 4, columnspan = 5)
    self.listbox2.bind('<<ListboxSelect>>', lambda e:SortActions.GetWindowIndex(self,e))
    self.listbox2.bind('<B1-Motion>', lambda e:SortActions.MoveWindowItem(self,e))

    i = 0
    for filename in sorted(os.listdir(directory)):
        self.listbox1.insert(i, filename)
        i = i + 1

    self.bAddToListTwo = Button(text = "->", command = lambda:SortActions.AddToListTwo(self,self.listbox1.curselection()))
    self.bAddToListTwo.grid(row=1, column = 6)
    self.bAddAll = Button(text = "Add All To Playlist", command = lambda:SortActions.AddAllFiles(self))
    self.bAddAll.grid(row=2, column = 6)
    self.bRemoveFromListTwo = Button(text = "Remove From Playlist", command = lambda:SortActions.RemoveFromListTwo(self,self.listbox2.curselection()))
    self.bRemoveFromListTwo.grid(row=3, column = 6)
    self.bSavePlaylist = Button(text = "Save Playlist", command = lambda:SortActions.SaveList(self))
    self.bSavePlaylist.grid(row=4, column = 6)

【问题讨论】:

  • 您知道创建菜单栏的更好方法吗? (即:menu 根窗口和顶层窗口上的选项)

标签: python user-interface widget tkinter


【解决方案1】:

Tkinter 小部件可以占据超过 1 个网格单元,但您需要自己管理布局,使用 columnspanrowspan 关键字到 .grid

例如获取布局:

 --------------------------------------------
 |      Button1      |  Button2 |           |
 --------------------------------  Button3  |
 | Label1  |  Label2 |  Label3  |           |
 --------------------------------------------

您需要执行以下操作:

Button1.grid(row=0,column=0,columnspan=2)
Button2.grid(row=0,column=2)
Button3.grid(row=0,column=4,rowspan=2)
Label1.grid(row=1,column=0)
Label2.grid(row=1,column=1)
Label3.grid(row=1,column=2)

极简脚本

import Tkinter as tk

root = tk.Tk()
Button1 = tk.Button(root,text="Button1")
Button2 = tk.Button(root,text="Button2")
Button3 = tk.Button(root,text="Button3")
Label1 = tk.Label(root,text="Label1")
Label2 = tk.Label(root,text="Label2")
Label3 = tk.Label(root,text="Label3")

Button1.grid(row=0,column=0,columnspan=2)
Button2.grid(row=0,column=2)
Button3.grid(row=0,column=4,rowspan=2)
Label1.grid(row=1,column=0)
Label2.grid(row=1,column=1)
Label3.grid(row=1,column=2)

root.mainloop()

【讨论】:

  • 我是否以同样的方式处理菜单,还是默认情况下它总是放在顶部?
  • 不确定菜单——我需要看一下文档。但是,无论如何,您的代码有点奇怪,因为您似乎在混合 .grid.pack(例如,self.frame 被打包和网格化——这可能导致非常奇怪且可能未定义的行为)——请注意我认为您可以在同一个应用程序中混合使用 gridpack,而不是在同一个框架/顶层。
  • 根据effbot,菜单总是放在当前顶层的顶部(OS-X除外)
  • 感谢您指出这一点。我什至没有意识到我仍在使用 .pack 作为菜单栏。我将其更改为 .grid ,现在按钮不再重叠。我还需要打包框架吗,或者我也可以使用 .grid 吗?
  • @user1104854:拿出一些纸和一支铅笔,画一个网格,然后将小部件放入其中。这是您刚刚学习时解决布局问题的最简单方法。
猜你喜欢
  • 2013-05-03
  • 2020-10-18
  • 1970-01-01
  • 2013-03-24
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多