2013-09-01 203 views
6

有什么办法可以使用带有可编辑行的ttk Treeview吗?如何使ttk.Treeview的行可编辑?

我的意思是它应该更像一张桌子。例如,双击该项目,使#0列'可编辑'。

如果这是不可能的,任何允许鼠标在物品上选择的方法都可以。在tkdocs或其他文档中我没有发现任何这方面的内容。

+0

我开发了一种点击树形视图中的单元格,并在单击的单元格顶部创建一个字段,以便可以编辑单元格值。然而,我用来解决这个问题的一个treeview方法只适用于我的Mac,但不适用于Windows。奇怪的是,它在技术上不应该适用于Mac,但它确实如此。您没有列出您的平台,但是如果您使用的是Mac(并且不会在Windows上运行该代码),请告诉我,并且我会提供详细的答案。 –

+1

我已经完成了相同的工作,它可以在Linux和Windows上运行,我没有机会在Mac上尝试它。实际上,我不必使文本可编辑,我已将Entry小部件只读。因此,如果您的“仅限Mac的解决方案”在显示Entry弹出窗口时遇到问题,也许我的解决方案可能会激发您。有关代码示例,请参阅我对此问题的回答。 – dakov

+0

我遇到过类似的限制,主要是使用Treeview模仿一个表,因为tkinter/ttk中没有类似表格的小部件。如果你不使用树视图作为“树”,你可以尝试tkintertable (https://code.google.com/p/tkintertable/)。 它基本上允许电子表格的功能,并且是相对最新的,有据可查的,功能非常丰富。 – Fiver

回答

2

长期研究后,我还没有发现这样的功能,所以我想有任何。 Tk是非常简单的界面,它允许程序员从基础知识中构建“高级”功能。所以我希望这样的行为。

def onDoubleClick(self, event): 
    ''' Executed, when a row is double-clicked. Opens 
    read-only EntryPopup above the item's column, so it is possible 
    to select text ''' 

    # close previous popups 
    self.destroyPopups() 

    # what row and column was clicked on 
    rowid = self._tree.identify_row(event.y) 
    column = self._tree.identify_column(event.x) 

    # clicked row parent id 
    parent = self._tree.parent(rowid) 

    # do nothing if item is top-level   
    if parent == '': 
     return 

    # get column position info 
    x,y,width,height = self._tree.bbox(rowid, column) 

    # y-axis offset 
    pady = height // 2 

    # place Entry popup properly   
    url = self._tree.item(rowid, 'text') 
    self.entryPopup = EntryPopup(self._tree, url) 
    self.entryPopup.place(x=0, y=y+pady, anchor=W, relwidth=1) 

这是构成ttk.Treeview作为self._tree

而且EntryPopup然后子类很简单入门的类中的方法:

class EntryPopup(Entry): 

    def __init__(self, parent, text, **kw): 
     ''' If relwidth is set, then width is ignored ''' 
     super().__init__(parent, **kw) 

     self.insert(0, text) 
     self['state'] = 'readonly' 
     self['readonlybackground'] = 'white' 
     self['selectbackground'] = '#1BA1E2' 
     self['exportselection'] = False 

     self.focus_force() 
     self.bind("<Control-a>", self.selectAll) 
     self.bind("<Escape>", lambda *ignore: self.destroy()) 

    def selectAll(self, *ignore): 
     ''' Set selection on the whole text ''' 
     self.selection_range(0, 'end') 

     # returns 'break' to interrupt default key-bindings 
     return 'break' 
+0

这与我使用的过程非常相似。就我而言,我使用'identify_region'来确定用户在树视图中单击的位置,并且只在用户单击单元格时才显示输入字段。我最初使用的文档没有提到这个方法,只使用Tk 8.6和以上版本,所以我尝试了它。奇迹般地,它在我的Mac上运行。直到它在客户端的Windows系统上抛出异常,我发现Python的Tkinter和ttk模块目前使用Tk 8.5。为什么它对我有用?不知道。无论如何,你给了我一些关于如何解决它的想法。谢谢! –

+0

请问,你能提供一个工作示例吗?我的意思是,如果我尝试运行它,则此代码不起作用。 – nbro

0

我不知道如何编辑行,但要捕获点击行,您可以使用虚拟事件。这将使用bind()方法绑定到例程,然后使用selection()方法获取所选项目的ID。

这些都是从现有的程序段,但显示来电的基本过程:

# in Treeview setup routine 
    self.tview.tree.bind("<<TreeviewSelect>>", self.TableItemClick) 

# in TableItemClick() 
    selitems = self.tview.tree.selection() 
    if selitems: 
     selitem = selitems[0] 
     text = self.tview.tree.item(selitem, "text") # get value in col #0 
0

这仅仅是为了创建在构造函数中设置的指定路径的树。您可以将您的活动绑定到该树上的项目。事件功能留下来的方式,该项目可以用很多方式。在这种情况下,它会在双击它时显示该项目的名称。希望这有助于某人。

import ttk 
    from Tkinter import* 
    import os* 

    class Tree(Frame): 

    def __init__(self, parent): 
     Frame.__init__(self, parent) 
     self.parent = parent 
     path = "/home/...." 
     self.initUI(path) 

    def initUI(self, path): 
     self.parent.title("Tree") 
     self.tree = ttk.Treeview(self.parent) 
     self.tree.bind("<Double-1>", self.itemEvent) 
     yScr = ttk.Scrollbar(self.tree, orient = "vertical", command = self.tree.yview) 
     xScr = ttk.Scrollbar(self.tree, orient = "horizontal", command = self.tree.xview) 
     self.tree.configure(yscroll = yScr.set, xScroll = xScr.set) 
     self.tree.heading("#0", text = "My Tree", anchor = 'w') 
     yScr.pack(side = RIGHT, fill = Y) 

     pathy = os.path.abspath(path) 
     rootNode = self.tree.insert('', 'end', text = pathy, open = True) 
     self.createTree(rootNode, pathy) 

     self.tree.pack(side = LEFT, fill = BOTH, expand = 1, padx = 2, pady = 2) 

     self.pack(fill= BOTH, expand = 1) 

    def createTree(self, parent, path) 
     for p in os.listdir(path) 
      pathy = os.path.join(path, p) 
      isdir = os.path.isdir(pathy) 
      oid = self.tree.insert(parent, 'end' text = p, open = False) 
      if isdir: 
       self.createTree(oid, pathy) 

    def itemEvent(self, event): 
     item = self.tree.selection()[0] # now you got the item on that tree 
     print "you clicked on", self.tree.item(item,"text") 



    def main(): 
     root = Tk.Tk() 
     app = Tree(root) 
     root.mainloop() 

    if __name__ == '__main__' 
     main() 
2

你也可以弹出与条目更新值列出的可编辑字段的工具窗口。这个例子有一个三列树形视图,不使用子类。

绑定你双击此:

def OnDoubleClick(self, treeView): 
    # First check if a blank space was selected 
    entryIndex = treeView.focus() 
    if '' == entryIndex: return 

    # Set up window 
    win = Toplevel() 
    win.title("Edit Entry") 
    win.attributes("-toolwindow", True) 

    #### 
    # Set up the window's other attributes and geometry 
    #### 

    # Grab the entry's values 
    for child in treeView.get_children(): 
     if child == entryIndex: 
      values = treeView.item(child)["values"] 
      break 

    col1Lbl = Label(win, text = "Value 1: ") 
    col1Ent = Entry(win) 
    col1Ent.insert(0, values[0]) # Default is column 1's current value 
    col1Lbl.grid(row = 0, column = 0) 
    col1Ent.grid(row = 0, column = 1) 

    col2Lbl = Label(win, text = "Value 2: ") 
    col2Ent = Entry(win) 
    col2Ent.insert(0, values[1]) # Default is column 2's current value 
    col2Lbl.grid(row = 0, column = 2) 
    col2Ent.grid(row = 0, column = 3) 

    col3Lbl = Label(win, text = "Value 3: ") 
    col3Ent = Entry(win) 
    col3Ent.insert(0, values[2]) # Default is column 3's current value 
    col3Lbl.grid(row = 0, column = 4) 
    col3Ent.grid(row = 0, column = 5) 

    def UpdateThenDestroy(): 
     if ConfirmEntry(treeView, col1Ent.get(), col2Ent.get(), col3Ent.get()): 
      win.destroy() 

    okButt = Button(win, text = "Ok") 
    okButt.bind("<Button-1>", lambda e: UpdateThenDestroy()) 
    okButt.grid(row = 1, column = 4) 

    canButt = Button(win, text = "Cancel") 
    canButt.bind("<Button-1>", lambda c: win.destroy()) 
    canButt.grid(row = 1, column = 5) 

然后确认修改:

def ConfirmEntry(self, treeView, entry1, entry2, entry3): 
    #### 
    # Whatever validation you need 
    #### 

    # Grab the current index in the tree 
    currInd = treeView.index(treeView.focus()) 

    # Remove it from the tree 
    DeleteCurrentEntry(treeView) 

    # Put it back in with the upated values 
    treeView.insert('', currInd, values = (entry1, entry2, entry3)) 

    return True 

下面是如何删除条目:

def DeleteCurrentEntry(self, treeView): 
    curr = treeView.focus() 

    if '' == curr: return 

    treeView.delete(curr)