有没有办法编辑列表框项目而不是删除它?
我正在使用带有列表框的 tkinter GUI。现在我的列表框可以包含例如 10 个项目。如果我想更改某一项的文本,有什么方法可以做到吗?
我知道我可以创建一个按钮来删除单个项目,但是有没有办法也可以编辑一个项目?
列表框不支持直接编辑列表框中的项目。您必须提供一种机制供用户输入数据,然后您可以仅替换列表框中的单个项目。
话虽这么说,tkinter 为您提供了让用户双击某个项目并更改它所需的所有工具。这是一个示例的快速破解。简而言之,当您双击时,它将在您单击的项目上叠加一个条目小部件,当您按返回键时,它将将该项目保存到列表框中。
import tkinter as tk
class EditableListbox(tk.Listbox):
"""A listbox where you can directly edit an item via double-click"""
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.edit_item = None
self.bind("<Double-1>", self._start_edit)
def _start_edit(self, event):
index = self.index(f"@{event.x},{event.y}")
self.start_edit(index)
return "break"
def start_edit(self, index):
self.edit_item = index
text = self.get(index)
y0 = self.bbox(index)[1]
entry = tk.Entry(self, borderwidth=0, highlightthickness=1)
entry.bind("<Return>", self.accept_edit)
entry.bind("<Escape>", self.cancel_edit)
entry.insert(0, text)
entry.selection_from(0)
entry.selection_to("end")
entry.place(relx=0, y=y0, relwidth=1, width=-1)
entry.focus_set()
entry.grab_set()
def cancel_edit(self, event):
event.widget.destroy()
def accept_edit(self, event):
new_data = event.widget.get()
self.delete(self.edit_item)
self.insert(self.edit_item, new_data)
event.widget.destroy()
root = tk.Tk()
lb = EditableListbox(root)
vsb = tk.Scrollbar(root, command=lb.yview)
lb.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
lb.pack(side="left", fill="both", expand=True)
for i in range(100):
lb.insert("end", f"Item #{i+1}")
root.mainloop()
由@Bryan Oakley共享的代码的修改版本,此版本在开始编辑时删除滚动条,并在取消或完成编辑后放回滚动条用于在开始编辑时删除滚动条共享
import tkinter as tk
class EditableListbox:
def __init__(self):
self.editItemIndex = None
self.root = tk.Tk()
self.lb = tk.Listbox(self.root)
self.vsb = tk.Scrollbar(self.root, command=self.lb.yview)
self.vsb.pack(side="right", fill="y")
self.lb.configure(yscrollcommand=self.vsb.set)
self.lb.pack(side="left", fill="both", expand=True)
for i in range(100):
self.lb.insert("end", f"Item #{i + 1}")
self.lb.bind("<Double-1>", self.startEdit)
def startEdit(self, event):
index = self.lb.index(f"@{event.x},{event.y}")
self.vsb.pack_forget()
self._start_edit(index)
return "break"
def _start_edit(self, index):
self.editItemIndex = index
text = self.lb.get(index)
y0 = self.lb.bbox(index)[1]
entry = tk.Entry(self.root, borderwidth=0, highlightthickness=1)
entry.bind("<Return>", self.accept_edit)
entry.bind("<Escape>", self.cancel_edit)
entry.insert(0, text)
entry.selection_from(0)
entry.selection_to("end")
entry.place(relx=0, y=y0, relwidth=1, width=-20)
entry.focus_set()
entry.grab_set()
def cancel_edit(self, event):
event.widget.destroy()
self.vsb.pack(side="right", fill="y")
def accept_edit(self, event):
new_data = event.widget.get()
self.lb.delete(self.editItemIndex)
self.lb.insert(self.editItemIndex, new_data)
event.widget.destroy()
self.vsb.pack(side="right", fill="y")
def runGUI(self):
self.root.mainloop()
if __name__ == "__main__":
flc_app = EditableListbox()
flc_app.runGUI()