如何删除选择的自动生成的条目框
How to delete chosen auto-generated entry box
编辑以反映 Paul Cornelius 的建议:
我在尝试删除自动生成的输入框时遇到困难:
每个 x_input
的两边都有相应的 v_input
。 v_input
是可选的,我希望相应的复选框能够忘记或停用其配对的 x_input
我一直在尝试使用索引方法,但没有成功。
下面的简化代码,跳到问题代码,查看实际的 generation/destruction 代码。
######### FRAME SET-UP ##########
from tkinter import *
"""Main app frame"""
class build_app(Tk):
def __init__(self):
Tk.__init__(self)
self._frame = None
self.switch_frame(home)
"""Old frame destruction"""
def switch_frame(self, frame_class):
new_frame = frame_class(self)
if self._frame is not None:
self._frame.forget()
self._frame = new_frame
self._frame.pack()
"""Home frame"""
class home(Frame):
def __init__(self, master):
Frame.__init__(self, master)
"""Label frame definitions"""
build_labelframe = LabelFrame(self, text="Build", padx=5, pady=5)
"""Label frame positions"""
build_labelframe.grid(row=2, column=0, sticky=N, padx=5, pady=5)
"""Build label definitions"""
x_label = Label(build_labelframe, text="x")
"""Build label positions"""
x_label.grid(row=5, column=0)
"""Build entry definition"""
count_input = Entry(build_labelframe, width=20)
"""Build entry text definition"""
count_input.insert(0, "Enter count")
count_input.configure(justify=CENTER)
"""Build entry position"""
count_input.grid(row=3, column=0, padx=2)
"""create table button command"""
def click_create_table():
global given_count
given_count = int(count_input.get())
########## PROBLEM CODE BEGINS ##########
"""Build entry definition/position function"""
p = 0
x = []
v = []
remove_v = []
for i in range(given_count):
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
v_input.configure(justify=CENTER)
v.append(v_input)
x_input = Entry(build_labelframe, width=20)
x_input.grid(row=7 + p + i, column=0)
x_input.configure(justify=CENTER)
x.append(x_input)
def handle_check(n):
def remove_v_command():
v[n].grid_forget()
return remove_v_command
remove_v_tick = Checkbutton(build_labelframe, text="Remove veil", bd=0, command=lambda:handle_check(remove_v.index(remove_v[i])))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
p += 2
remove_v_tick = Checkbutton(build_labelframe, text="Remove veil", bd=0, command=lambda:handle_check(len(remove_v)))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
v.append(v_input)
i += 1
"""Build button definition"""
create_table_button = Button(build_labelframe, text="Create table", width=15, command=click_create_table)
"""Build button position"""
create_table_button.grid(row=4, column=1)
if __name__ == "__main__":
app = build_app()
app.mainloop()
此方法成功地为列出的复选框获取了正确的索引值。但是,它没有正确地将索引值传递给 grid_forget
函数,相应的 v_input
框仍然存在。
这是此类程序的常见问题。问题围绕着你的函数remove_v_command
。如果你可以将一个整数变量传递给该函数,指示要从网格中删除哪些小部件,如下所示(我已经创建了 v、x 和 y 成员变量):
def remove_v_command(self, n):
self.v[n].grid_forget()
self.x[n].grid_forget()
self.y[n].grid_forget()
这将协调 v、x 和 y 数组中的小部件,以便将小部件一起删除。我认为这大约就是你想要做的。如果我误解了您的要求,您必须在此处进行一些更改。
但是事件处理器是tkinter内部调用的,没有办法让tkinter传递额外的变量n。有几种方法可以解决这个问题。我更喜欢的一种是使用 Python 闭包,像这样:
def handle_check(self, n):
def remove_v_command():
self.v[n].grid_forget()
self.x[n].grid_forget()
self.y[n].grid_forget()
return remove_v_command
然后您还要更改创建 Checkbutton 的代码行,如下所示:
remove_v_tick = Checkbutton(
build_labelframe, text="Remove veil", bd=0,
command=self.handle_check(len(remove_v)))
方法 handle_check 本身不是事件处理程序。它 returns 一个作为事件处理程序的函数,并且(根据 tkinter 的要求)必须采用零参数。由于每次调用 handle_check 时都会创建一个新的函数对象,因此每个 Checkbox 都有不同的事件处理程序。这些对象记住最初传递的 self 和 n 的值;因此每个复选框都链接到最近添加的条目字段。因此,您现在拥有了知道要从网格中删除哪些对象的事件处理程序。
我认为如果你使 handle_check 成为一个成员函数,并使 x、y 和 v 成员对象成为最干净的。
编辑:这是一个完整的工作程序。
######### FRAME SET-UP ##########
from tkinter import *
"""Main app frame"""
class build_app(Tk):
def __init__(self):
Tk.__init__(self)
self._frame = None
self.switch_frame(home)
"""Old frame destruction"""
def switch_frame(self, frame_class):
new_frame = frame_class(self)
if self._frame is not None:
self._frame.forget()
self._frame = new_frame
self._frame.pack()
"""Home frame"""
class home(Frame):
def __init__(self, master):
Frame.__init__(self, master)
"""Label frame definitions"""
build_labelframe = LabelFrame(self, text="Build", padx=5, pady=5)
"""Label frame positions"""
build_labelframe.grid(row=2, column=0, sticky=N, padx=5, pady=5)
"""Build label definitions"""
x_label = Label(build_labelframe, text="x")
"""Build label positions"""
x_label.grid(row=5, column=0)
"""Build entry definition"""
count_input = Entry(build_labelframe, width=20)
"""Build entry text definition"""
count_input.insert(0, "Enter count")
count_input.configure(justify=CENTER)
"""Build entry position"""
count_input.grid(row=3, column=0, padx=2)
"""create table button command"""
def click_create_table():
global given_count
given_count = int(count_input.get())
########## PROBLEM CODE BEGINS ##########
"""Build entry definition/position function"""
p = 0
self.x = []
self.v = []
remove_v = []
for i in range(given_count):
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
v_input.configure(justify=CENTER)
self.v.append(v_input)
x_input = Entry(build_labelframe, width=20)
x_input.grid(row=7 + p + i, column=0)
x_input.configure(justify=CENTER)
self.x.append(x_input)
remove_v_tick = Checkbutton(
build_labelframe,
text="Remove veil",
bd=0,
command=self.handle_check(len(remove_v)))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
p += 2
remove_v_tick = Checkbutton(
build_labelframe, text="Remove veil", bd=0,
command=self.handle_check(len(remove_v)))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
self.v.append(v_input)
i += 1
"""Build button definition"""
create_table_button = Button(build_labelframe,
text="Create table",
width=15, command=click_create_table)
"""Build button position"""
create_table_button.grid(row=4, column=1)
def handle_check(self, n):
def remove_v_command():
self.v[n].grid_forget()
return remove_v_command
app = build_app()
app.mainloop()
解释:
对 Button 构造函数的调用采用 command=f
形式的关键字参数。这里 'f' 是一个函数对象。典型用法类似于 command=click_create_table
,其中“click_create_table”是函数的名称,在某处使用 def click_create_table(...)
语句定义。它也可能类似于 lambda n: handle_check(n)
因为“lambda”创建了一个匿名函数对象。
但不必完全是那样。任何计算为函数对象的表达式都可以使用。这样的表达式是 self.handle_check(len(remove_v))
因为 self.handle_check returns 一个 函数 。在 Python 中,函数就像其他任何东西一样只是对象;它们可以被返回、存储在变量中、作为参数传递等。
Tkinter 在点击按钮时调用该函数。请注意,tkinter 没有调用 self.handle_check;它正在调用 self.handle_check.
创建并返回的对象
传递给 self.handle_check 的参数用作列表 self.v 的索引。 self.handle_check 返回的函数是“一个对象,当用户单击特定按钮时,它知道 grid_forget 进入哪个 Entry 字段。”它通过跟踪最初作为参数传递给 handle_check.
的值来做到这一点
正好len(remove_v)是要删除的Entry的右索引。那是因为调用 handle_check 时,新的 Checkbutton 尚未添加到 remove_v。第一次循环时,len(remove_v) 将为 0,而 self.v[0] 是单击 Checkbutton 时要隐藏的条目。第二次循环,len(remove_v) 为 1,self.v[1] 是关联的条目。等等。
编辑以反映 Paul Cornelius 的建议:
我在尝试删除自动生成的输入框时遇到困难:
每个 x_input
的两边都有相应的 v_input
。 v_input
是可选的,我希望相应的复选框能够忘记或停用其配对的 x_input
我一直在尝试使用索引方法,但没有成功。
下面的简化代码,跳到问题代码,查看实际的 generation/destruction 代码。
######### FRAME SET-UP ##########
from tkinter import *
"""Main app frame"""
class build_app(Tk):
def __init__(self):
Tk.__init__(self)
self._frame = None
self.switch_frame(home)
"""Old frame destruction"""
def switch_frame(self, frame_class):
new_frame = frame_class(self)
if self._frame is not None:
self._frame.forget()
self._frame = new_frame
self._frame.pack()
"""Home frame"""
class home(Frame):
def __init__(self, master):
Frame.__init__(self, master)
"""Label frame definitions"""
build_labelframe = LabelFrame(self, text="Build", padx=5, pady=5)
"""Label frame positions"""
build_labelframe.grid(row=2, column=0, sticky=N, padx=5, pady=5)
"""Build label definitions"""
x_label = Label(build_labelframe, text="x")
"""Build label positions"""
x_label.grid(row=5, column=0)
"""Build entry definition"""
count_input = Entry(build_labelframe, width=20)
"""Build entry text definition"""
count_input.insert(0, "Enter count")
count_input.configure(justify=CENTER)
"""Build entry position"""
count_input.grid(row=3, column=0, padx=2)
"""create table button command"""
def click_create_table():
global given_count
given_count = int(count_input.get())
########## PROBLEM CODE BEGINS ##########
"""Build entry definition/position function"""
p = 0
x = []
v = []
remove_v = []
for i in range(given_count):
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
v_input.configure(justify=CENTER)
v.append(v_input)
x_input = Entry(build_labelframe, width=20)
x_input.grid(row=7 + p + i, column=0)
x_input.configure(justify=CENTER)
x.append(x_input)
def handle_check(n):
def remove_v_command():
v[n].grid_forget()
return remove_v_command
remove_v_tick = Checkbutton(build_labelframe, text="Remove veil", bd=0, command=lambda:handle_check(remove_v.index(remove_v[i])))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
p += 2
remove_v_tick = Checkbutton(build_labelframe, text="Remove veil", bd=0, command=lambda:handle_check(len(remove_v)))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
v.append(v_input)
i += 1
"""Build button definition"""
create_table_button = Button(build_labelframe, text="Create table", width=15, command=click_create_table)
"""Build button position"""
create_table_button.grid(row=4, column=1)
if __name__ == "__main__":
app = build_app()
app.mainloop()
此方法成功地为列出的复选框获取了正确的索引值。但是,它没有正确地将索引值传递给 grid_forget
函数,相应的 v_input
框仍然存在。
这是此类程序的常见问题。问题围绕着你的函数remove_v_command
。如果你可以将一个整数变量传递给该函数,指示要从网格中删除哪些小部件,如下所示(我已经创建了 v、x 和 y 成员变量):
def remove_v_command(self, n):
self.v[n].grid_forget()
self.x[n].grid_forget()
self.y[n].grid_forget()
这将协调 v、x 和 y 数组中的小部件,以便将小部件一起删除。我认为这大约就是你想要做的。如果我误解了您的要求,您必须在此处进行一些更改。
但是事件处理器是tkinter内部调用的,没有办法让tkinter传递额外的变量n。有几种方法可以解决这个问题。我更喜欢的一种是使用 Python 闭包,像这样:
def handle_check(self, n):
def remove_v_command():
self.v[n].grid_forget()
self.x[n].grid_forget()
self.y[n].grid_forget()
return remove_v_command
然后您还要更改创建 Checkbutton 的代码行,如下所示:
remove_v_tick = Checkbutton(
build_labelframe, text="Remove veil", bd=0,
command=self.handle_check(len(remove_v)))
方法 handle_check 本身不是事件处理程序。它 returns 一个作为事件处理程序的函数,并且(根据 tkinter 的要求)必须采用零参数。由于每次调用 handle_check 时都会创建一个新的函数对象,因此每个 Checkbox 都有不同的事件处理程序。这些对象记住最初传递的 self 和 n 的值;因此每个复选框都链接到最近添加的条目字段。因此,您现在拥有了知道要从网格中删除哪些对象的事件处理程序。
我认为如果你使 handle_check 成为一个成员函数,并使 x、y 和 v 成员对象成为最干净的。
编辑:这是一个完整的工作程序。
######### FRAME SET-UP ##########
from tkinter import *
"""Main app frame"""
class build_app(Tk):
def __init__(self):
Tk.__init__(self)
self._frame = None
self.switch_frame(home)
"""Old frame destruction"""
def switch_frame(self, frame_class):
new_frame = frame_class(self)
if self._frame is not None:
self._frame.forget()
self._frame = new_frame
self._frame.pack()
"""Home frame"""
class home(Frame):
def __init__(self, master):
Frame.__init__(self, master)
"""Label frame definitions"""
build_labelframe = LabelFrame(self, text="Build", padx=5, pady=5)
"""Label frame positions"""
build_labelframe.grid(row=2, column=0, sticky=N, padx=5, pady=5)
"""Build label definitions"""
x_label = Label(build_labelframe, text="x")
"""Build label positions"""
x_label.grid(row=5, column=0)
"""Build entry definition"""
count_input = Entry(build_labelframe, width=20)
"""Build entry text definition"""
count_input.insert(0, "Enter count")
count_input.configure(justify=CENTER)
"""Build entry position"""
count_input.grid(row=3, column=0, padx=2)
"""create table button command"""
def click_create_table():
global given_count
given_count = int(count_input.get())
########## PROBLEM CODE BEGINS ##########
"""Build entry definition/position function"""
p = 0
self.x = []
self.v = []
remove_v = []
for i in range(given_count):
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
v_input.configure(justify=CENTER)
self.v.append(v_input)
x_input = Entry(build_labelframe, width=20)
x_input.grid(row=7 + p + i, column=0)
x_input.configure(justify=CENTER)
self.x.append(x_input)
remove_v_tick = Checkbutton(
build_labelframe,
text="Remove veil",
bd=0,
command=self.handle_check(len(remove_v)))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
p += 2
remove_v_tick = Checkbutton(
build_labelframe, text="Remove veil", bd=0,
command=self.handle_check(len(remove_v)))
remove_v_tick.grid(row=6 + p + i, column=1)
remove_v.append(remove_v_tick)
v_input = Entry(build_labelframe, width=20)
v_input.grid(row=6 + p + i, column=0)
self.v.append(v_input)
i += 1
"""Build button definition"""
create_table_button = Button(build_labelframe,
text="Create table",
width=15, command=click_create_table)
"""Build button position"""
create_table_button.grid(row=4, column=1)
def handle_check(self, n):
def remove_v_command():
self.v[n].grid_forget()
return remove_v_command
app = build_app()
app.mainloop()
解释:
对 Button 构造函数的调用采用 command=f
形式的关键字参数。这里 'f' 是一个函数对象。典型用法类似于 command=click_create_table
,其中“click_create_table”是函数的名称,在某处使用 def click_create_table(...)
语句定义。它也可能类似于 lambda n: handle_check(n)
因为“lambda”创建了一个匿名函数对象。
但不必完全是那样。任何计算为函数对象的表达式都可以使用。这样的表达式是 self.handle_check(len(remove_v))
因为 self.handle_check returns 一个 函数 。在 Python 中,函数就像其他任何东西一样只是对象;它们可以被返回、存储在变量中、作为参数传递等。
Tkinter 在点击按钮时调用该函数。请注意,tkinter 没有调用 self.handle_check;它正在调用 self.handle_check.
创建并返回的对象传递给 self.handle_check 的参数用作列表 self.v 的索引。 self.handle_check 返回的函数是“一个对象,当用户单击特定按钮时,它知道 grid_forget 进入哪个 Entry 字段。”它通过跟踪最初作为参数传递给 handle_check.
的值来做到这一点正好len(remove_v)是要删除的Entry的右索引。那是因为调用 handle_check 时,新的 Checkbutton 尚未添加到 remove_v。第一次循环时,len(remove_v) 将为 0,而 self.v[0] 是单击 Checkbutton 时要隐藏的条目。第二次循环,len(remove_v) 为 1,self.v[1] 是关联的条目。等等。