代码之家  ›  专栏  ›  技术社区  ›  ivan_pozdeev RenanSS

提供带有编辑功能的列表框的标准ttk方式

  •  2
  • ivan_pozdeev RenanSS  · 技术社区  · 6 年前

    我需要一个具有多个选择的列表控件,以及用户编辑显示列表的方法。

    判断依据 Python - python-list - ttk Listbox , ttk.Treeview 是新的吗 黑色 显示列表和替换的方式 Tkinter.Listbox .

    是否也提供了一些库存/推荐的方法来合并列表编辑?

    这通常通过控件周围的三个按钮“添加”/“编辑”/“删除”来完成(前两个按钮可能会导致弹出一个带有编辑控件的小窗口),或者列表条目本身成为编辑器,例如双击。手工实现这两种逻辑都是不平凡的。

    1 回复  |  直到 6 年前
        1
  •  2
  •   ivan_pozdeev RenanSS    5 年前

    Tk和Tkinter只提供基本小部件;它们的可重用组合超出了它们的范围。被遗弃的 Tix 该软件包提供了一种机制和一个称为“巨型小部件”的集合,但这个想法显然没有流行起来。

    我做到了 我的方式 以下方法(使用模型视图演示器设计模式)。

    看起来是这样的:

    how it looks

    import tkinter
    from tkinter import ttk
    from tkinter import W, E
    
    
    class View_EditableList(object):
        def __init__(self,root,root_row):
            """ List with buttons to edit its contents.
            :param root: parent widget
            :param roow_row: row in `root'. The section takes 2 rows.
            """
    
            self.list = tkinter.Listbox(root, selectmode=tkinter.EXTENDED)
            self.list.grid(row=root_row, sticky=(W, E))
            root.rowconfigure(root_row, weight=1)
    
            self.frame = ttk.Frame(root)
            self.frame.grid(row=root_row+1, sticky=(W, E))
    
            self.add = ttk.Button(self.frame, text="+", width=5)
            self.add.grid(row=0, column=1)
            self.edit = ttk.Button(self.frame, text="*", width=5)
            self.edit.grid(row=0, column=2)
            self.del_ = ttk.Button(self.frame, text="-", width=5)
            self.del_.grid(row=0, column=3)
            self.up = ttk.Button(self.frame, text=u"↑", width=5)
            self.up.grid(row=0, column=4)
            self.down = ttk.Button(self.frame, text=u"↓", width=5)
            self.down.grid(row=0, column=5)
            self.frame.grid_columnconfigure(0, weight=1)
            self.frame.grid_columnconfigure(6, weight=1)
    
    
    class Presenter_EditableList(object):
        def __init__(self,view,root):
            """
    
            :param view: View_EditableList
            :param root: root widget to be used as parent for modal windows
            """
            self.root = root
            self.view = view
            view.add.configure(command=self.add)
            view.edit.configure(command=self.edit)
            view.del_.configure(command=self.del_)
            view.up.configure(command=self.up)
            view.down.configure(command=self.down)
    
        def add(self):
            w=View_AskText(self.root)
            self.root.wait_window(w.top)
            if w.value:
                self.view.list.insert(self.view.list.size(),w.value)
    
        def edit(self):
            l=self.view.list
            try:
                [index]=l.curselection()
            except ValueError:
                return
            w=View_AskText(self.root,l.get(index))
            self.root.wait_window(w.top)
            if w.value:
                l.delete(index)
                l.insert(index,w.value)
    
        def del_(self):
            l=self.view.list
            try:
                [index]=l.curselection()
            except ValueError:
                return
            l.delete(index)
            l.select_set(max(index,l.size()-1))
    
        def up(self):
            l = self.view.list
            try:
                [index] = l.curselection()
            except ValueError:
                return
            if index>0:
                v = l.get(index)
                l.delete(index)
                l.insert(index-1,v)
                l.select_set(index-1)
    
        def down(self):
            l = self.view.list
            try:
                [index] = l.curselection()
            except ValueError:
                return
            if index<l.size()-1:
                v = l.get(index)
                l.delete(index)
                l.insert(index+1,v)
                l.select_set(index+1)
    
        def getlist(self):
            return [self.view.list.get(i) for i in range(self.view.list.size())]
    
        def setlist(self,list_):
            self.view.list.delete(0,tkinter.END)
            for i,v in enumerate(list_):
                self.view.list.insert(i,v)
    
    # supplemental class; it's in another file in my actual code
    class View_AskText(object):
        """
        A simple dialog that asks for a text value.
        """
        def __init__(self, master, value=u""):
            self.value = None
    
            top = self.top = tkinter.Toplevel(master)
            top.grab_set()
            self.l = ttk.Label(top, text=u"Value:")
            self.l.pack()
            self.e = ttk.Entry(top)
            self.e.pack()
            self.b = ttk.Button(top, text='Ok', command=self.save)
            self.b.pack()
    
            if value: self.e.insert(0, value)
            self.e.focus_set()
            top.bind('<Return>', self.save)
    
        def save(self, *_):
            self.value = self.e.get()
            self.top.destroy()
    
    
    root = tkinter.Tk()
    view = View_EditableList(root, 5)
    Presenter_EditableList(view, root)
    root.mainloop()