强制 TKinter 按钮输出到 window 的底部?

Forcing TKinter button output to bottom of window?

我对使用 TKinter 还很陌生。我正在制作一个显示 wine quality data sets 的描述性统计信息的 TKinter window。我遇到的问题是定位。即使使用 pack(side=BOTTOM),直方图按钮也会显示在我拥有的列选项按钮旁边,如下所示:

理想情况下,我希望 window 看起来像这样:

我尝试在制作标签“描述性统计”的同一位置制作按钮,然后稍后对其进行配置,但是虽然按钮保持在我想要的位置,但直方图最终还是一样地点。

编辑: 我最初使用 grid() 手动放置所有内容,但是出于美观原因,我不喜欢按钮之间的空格随着更多对象添加到 window 进行调整。我也收到了“不能使用 pack()grid()”的警告,即使我已将所有 pack() 更改为 grid(),特别是因为我的绘图功能,我想不通。所以最后我只是从 grid() 切换到 pack() 以避免不断出现该错误。

我的代码:

import tkinter as tk
from matplotlib.figure import Figure 
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)

#the main window
root = tk.Tk()

root.title('Descriptive statistics for vinho verde datasets') 

#generate some labels    
lbl1 = tk.Label(root, text = "Wine choice:")
lbl1.pack(side=TOP)

lbl2 = tk.Label(root, text = "Descriptive statistics:")
lbl2.pack(side=BOTTOM)

def wine_choice(opt):
    #functions determining for which columns to output descriptive statistics
    def describe(colm):
        if opt == 'white':
            res = white[colm].describe()
        else:
            res = red[colm].describe()
        txt = "\nDescriptive statistics for {0} wine, {1}:\n\n{2}"
        lbl2.config(text = txt.format(opt,colm,res)) 
    
        def b_plot(): 
            #figure that will contain the plot 
            fig = Figure(figsize = (5, 5), dpi = 75) 
            p1 = fig.add_subplot() 
        
            if opt == 'white':
                p1.hist(white[colm])
            else:
                p1.hist(red[colm])
        
            #creating the canvas containing figure and placing on the window 
            canvas = FigureCanvasTkAgg(fig, root)   
            canvas.draw() 
            canvas.get_tk_widget().pack(side=BOTTOM)
        
        btn_p = tk.Button(root, command = b_plot, width=10, height=3, text = "Histogram").pack(side=BOTTOM)
    
    lbl3 = tk.Label(root, text = "Pick an attribute to investigate:")
    lbl3.pack(side=TOP)

    #spawn attribute buttons after user chooses a wine
    #generate buttons
    btn3 = tk.Button(root, text='fixed acidity', width=10, height=3)
    btn3.pack(side=LEFT)
    btn3.bind('<Button-1>', lambda e: describe('fixed acidity'))

    btn4 = tk.Button(root, text='volatile\nacidity', width=10, height=3)
    btn4.pack(side=LEFT)
    btn4.bind('<Button-1>', lambda e: describe('volatile acidity'))

    btn5 = tk.Button(root, text='citric\nacid', width=10, height=3)
    btn5.pack(side=LEFT)
    btn5.bind('<Button-1>', lambda e: describe('citric acid'))

    btn6 = tk.Button(root, text='residual\nsugar', width=10, height=3)
    btn6.pack(side=LEFT)
    btn6.bind('<Button-1>', lambda e: describe('residual sugar'))

    btn7 = tk.Button(root, text='chlorides', width=10, height=3)
    btn7.pack(side=LEFT)
    btn7.bind('<Button-1>', lambda e: describe('chlorides'))

    btn8 = tk.Button(root, text='free\nsulfur\ndioxide', width=10, height=3)
    btn8.pack(side=LEFT)
    btn8.bind('<Button-1>', lambda e: describe('free sulfur dioxide'))

    btn9 = tk.Button(root, text='total\nsulfur\ndioxide', width=10, height=3)
    btn9.pack(side=LEFT)
    btn9.bind('<Button-1>', lambda e: describe('total sulfur dioxide'))

    btn10 = tk.Button(root, text='density', width=10, height=3)
    btn10.pack(side=LEFT)
    btn10.bind('<Button-1>', lambda e: describe('density'))

    btn11 = tk.Button(root, text='pH', width=10, height=3)
    btn11.pack(side=LEFT)
    btn11.bind('<Button-1>', lambda e: describe('pH'))

    btn12 = tk.Button(root, text='sulphates', width=10, height=3)
    btn12.pack(side=LEFT)
    btn12.bind('<Button-1>', lambda e: describe('sulphates'))

    btn13 = tk.Button(root, text='alcohol', width=10, height=3)
    btn13.pack(side=LEFT)
    btn13.bind('<Button-1>', lambda e: describe('alcohol'))

    btn14 = tk.Button(root, text='quality', width=10, height=3)
    btn14.pack(side=LEFT)
    btn14.bind('<Button-1>', lambda e: describe('quality'))

#buttons for wine choices
btn1 = tk.Button(root, text = "white", width=10, height=2)
btn1.pack(side=TOP)
#remember which button user picks
btn1.bind('<Button-1>', lambda e: wine_choice('white'))

btn2 = tk.Button(root, text = "red", width=10, height=2)
btn2.pack(side=TOP)
btn2.bind('<Button-1>', lambda e: wine_choice('red'))

#must be called for window to be drawn and events to be processed
root.mainloop()

解决方案是将您的 UI 分成逻辑组,并使用框架来组织逻辑组。您可以让现有的东西发挥作用,但使用框架来组织小部件要容易得多。

我大概看到四个逻辑组:

  • 一组两个垂直堆叠的按钮
  • 十几个垂直排列的按钮
  • 带有“直方图”按钮的统计块
  • 直方图

因此,首先创建四个框架,每个部分一个。垂直堆叠最好使用 pack.

完成后,将各种小部件放入其中一个框架中。从布局角度来看,每个框架都是独立的,因此您可以在每个框架中使用 gridpack。虽然,由于每个组似乎都是垂直或水平分组,pack 可能在所有情况下都效果最好,因为它在 left-to-right 和 top-to-bottom 布局方面表现出色,代码行最少。