Python grid_remove

时间:2016-02-23 02:02:32

标签: python-2.7 tkinter grid

我仍然是Python的新手,正在为应用程序创建GUI。在此应用程序中,用户选择他/她想要的元素,并根据他的选择显示必要数量的输入网格。

例如。 Square = 2,Sphere = 1等......

我的问题在于,无论何时用户希望更新,首先让他/她选择Square(因此显示两个输入字段),但之后如果他按下Sphere(仍然显示两个输入字段)。

当新的字段数小于当前的字段数时,grid_forget似乎不起作用。

以下代码的一部分:

    def domain_dimensions(self, req_dim):
        if self.domain.get() == "Square":
            req_dim = 2
        elif self.domain.get() == 'Sphere':
            req_dim = 1
        else:
            req_dim = 5
        for x in range(0,int(req_dim)):
            self.domain_dim = Entry(self)
            self.domain_dim.grid(row=11, column=1+int(x))
        self.domain_dim.grid_forget() #doesnt seem to forget when value is less on reclick.

self.domain = StringVar()
self.domain.set('Square')
domain_dropdown = OptionMenu(self, self.domain,*neper_domains1, command=self.domain_dimensions).grid(row=10, column=1, columnspan=3)

史蒂文帮助后更新的代码

def domain_dimensions(self, req_dim):
    global container

    for wid in container:
        wid.destroy()

    container = []

    for type, req_dim in neper_domains.iteritems():
        if type == self.domain.get():
            for x in range(0,int(req_dim)):
                domain_dim = Entry(root)
                domain_dim.grid(row=25 + x, column=1)
                container.append(domain_dim)

1 个答案:

答案 0 :(得分:3)

由于网格的性质,如果给出相同的坐标(行和列),则可以将小部件堆叠在一起。如果你换了包装,你会看到在旧纸盒下面继续创建输入框。

此外,您没有正确使用grid_forget。您所做的就是忘记在for循环之后创建的最后一个小部件。因此,当您选择square时,您只能获得1个Entry小部件。

此外,如果您不打算将忘记的小部件返回到窗口中,那么我建议您使用destroy。忘记将窗口小部件值保留在内存中,因此如果您不打算重新使用它,应用程序将继续累积忘记的Entry小部件而不是删除它们。

现在为代码示例。您要做的是删除所有现有的Entry小部件,然后再添加新小部件。 winfo_children返回窗口小部件中包含的所有窗口小部件的列表。

import tkinter as tk

def onChange(val):
    if val == "Square":
        r = 2
    elif val == "Sphere":
        r = 1
    else:
        r = 5

    # Destroys all existing widgets in the container frame
    for wid in container.winfo_children():
        wid.destroy() # Using destory instead of grid_forget

    # Dynamically create Entry widgets in container frame
    # Number is equal to r
    for x in range(r):
        e = tk.Entry(container)
        e.grid(row = 1 + x, column = 0)

root = tk.Tk()
root.minsize(200, 200)

options = ["Square", "Sphere", "Other"]
var = tk.StringVar()
var.set("Square")

op_menu = tk.OptionMenu(root, var, *options, command = onChange)
op_menu.grid(row = 0, column = 0)

# Container frame for the Entry widgets
container = tk.Frame(root)
container.grid()

如果要保留不会删除的Entry小部件的值,则可以使用以下内容作为onChange函数。

def onChange(val):
    if val == "Square":
        r = 2
    elif val == "Sphere":
        r = 1
    else:
        r = 5

    c = container.winfo_children()
    old_r = len(c) # Number of widgets in container frame

    # Destroys all excess widgets in the container frame
    # Eg. old_r = 5, r = 2 | Last 3 widgets in frame are destroyed
    if old_r > r:
        for wid in c[r:old_r]:
            wid.destroy()

    # Dynamically create Entry widgets in container frame
    # Only creates extra to meet r value
    # Eg. old_r = 2, r = 5 | Creates 3 widgets in frame after original 2
    elif old_r < r:
        for x in range(old_r, r):
            e = tk.Entry(container)
            e.grid(row = 1 + x, column = 0)

如果您不想为容器使用新框架。然后有几个选择。

首先,如果您使用的帧只有动态创建的Entry小部件,那么您可以使用if语句排除所有非Entry小部件被销毁。

for wid in container.winfo_children():
    if type(wid).__name__ == "Entry":
        wid.destroy()

或者您可以将动态创建的条目小部件添加到列表中并迭代它而不是winfo_children

中的列表
def onChange(val):
    ...
    ...

    global container # Global is used here because this example is not done using classes

    for wid in container:
        wid.destroy() # Using destory instead of grid_forget

    container = [] # Reset container to empty list

    for x in range(r):
        e = tk.Entry(root)
        e.grid(row = 1 + x, column = 0)
        container.append(e) # Append widget to container list   
...
...

# Container list for the Entry widgets
container = []