2013-09-01 32 views
6

Có cách nào để sử dụng ttk Treeview với các hàng có thể chỉnh sửa không?Làm cách nào để các hàng của ttk.Treeview có thể chỉnh sửa được?

Tôi có nghĩa là nó sẽ hoạt động giống như một bảng. Ví dụ: nhấp đúp vào mục làm cho cột # 0 có thể chỉnh sửa được.

Nếu điều này là không thể, bất kỳ cách nào để cho phép chọn chuột trên mục sẽ vẫn ổn. Tôi đã không tìm thấy bất kỳ đề cập đến điều này trong tkdocs hoặc các tài liệu khác.

+0

tôi đã phát triển một cách bấm vào một ô trong một khung nhìn tre và tạo một trường trên đầu ô được bấm để giá trị ô có thể được chỉnh sửa. Tuy nhiên, một trong những phương pháp treeview mà tôi sử dụng để kéo này chỉ hoạt động trên máy Mac của tôi, nhưng không phải trên Windows. Điều kỳ lạ là nó về mặt kỹ thuật không phải là ngay cả làm việc cho Mac, nhưng nó có. Bạn không liệt kê nền tảng của mình, nhưng nếu bạn đang sử dụng máy Mac (và sẽ không chạy mã trên Windows), hãy cho tôi biết và tôi sẽ đăng câu trả lời kèm theo chi tiết. –

+1

Tôi đã làm như vậy và nó hoạt động cả linux và windows, tôi không có cơ hội dùng thử trên Mac. Tôi không phải làm cho văn bản có thể chỉnh sửa được, tôi đã làm cho tiện ích Entry chỉ đọc. Vì vậy, nếu 'giải pháp chỉ dành cho Mac' của bạn gặp sự cố khi hiển thị cửa sổ bật lên Nhập, có thể giải pháp của tôi có thể truyền cảm hứng cho bạn. Xem câu trả lời của tôi cho câu hỏi này cho ví dụ mã. – dakov

+0

Tôi đã chạy vào những hạn chế tương tự, chủ yếu bằng cách sử dụng Treeview để bắt chước một bảng vì không có tiện ích bảng giống như trong tkinter/ttk. Nếu bạn không sử dụng Treeview làm "cây", bạn có thể thử tkintertable (https://code.google.com/p/tkintertable/). Về cơ bản, tính năng này cho phép tính năng bảng tính và tương đối hiện tại, được ghi lại tài liệu và khá giàu tính năng. – Fiver

Trả lời

2

Sau khi nghiên cứu lâu tôi đã không tìm thấy tính năng như vậy nên tôi đoán có bất kỳ. Tk là giao diện rất đơn giản, cho phép lập trình viên xây dựng các tính năng 'cao cấp' từ những điều cơ bản. Vì vậy, hành vi mong muốn của tôi theo cách này.

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) 

Đây là phương pháp trong một lớp mà soạn ttk.Treeview như self._tree

Và sau đó EntryPopup là rất đơn giản sub-class of Entry:

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

Điều này rất giống với quy trình tôi đang sử dụng. Trong trường hợp của tôi, tôi đang sử dụng 'ident_region' để xác định vị trí người dùng đã nhấp vào trong treeview và chỉ hiển thị trường nhập nếu người dùng đã nhấp vào một ô. Các tài liệu tôi đã được ban đầu sử dụng không nói gì về phương pháp đó chỉ làm việc với Tk 8,6 và lên, vì vậy tôi đã thử nó. Thật kỳ diệu nó đã hoạt động ... trên máy Mac của tôi. Nó không phải cho đến khi nó ném một ngoại lệ trên hệ thống Windows của khách hàng của tôi mà tôi phát hiện ra rằng các mô-đun Tkinter và ttk của Python hiện đang sử dụng Tk 8.5. Tại sao nó làm việc cho tôi? Không ý kiến. Ở mức nào, bạn đã cho tôi một số ý tưởng về cách khắc phục nó. Cảm ơn! –

+0

Xin vui lòng, bạn có thể cung cấp một ví dụ làm việc, tôi có nghĩa là mã này không hoạt động nếu tôi cố gắng chạy nó. – nbro

0

Tôi không biết làm cho hàng có thể chỉnh sửa được, nhưng để chụp nhấp vào một hàng, bạn sử dụng sự kiện ảo . Điều này bị ràng buộc với một thói quen với phương thức bind(), sau đó bạn sử dụng phương thức selection() để lấy các id của các mục được chọn.

Đây là đoạn từ một chương trình hiện có, nhưng hiển thị chuỗi cơ bản của cuộc gọi:

# 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

Đây chỉ là để tạo một cây cho đường dẫn được chỉ định được đặt trong hàm tạo. bạn có thể ràng buộc sự kiện của bạn với mục của bạn trên cây đó. Chức năng sự kiện được để lại theo cách mà mục đó có thể được sử dụng theo nhiều cách. Trong trường hợp này, nó sẽ hiển thị tên của mục khi nhấp đúp vào nó. Hy vọng điều này sẽ giúp ai đó.

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

Bạn cũng có thể bật lên cửa sổ công cụ với các trường có thể chỉnh sửa được liệt kê với Mục nhập để cập nhật giá trị. Ví dụ này có một lượt xem tre với ba cột và không sử dụng các lớp con.

Bind nhấn đúp chuột của bạn như thế này:

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) 

Sau đó, xác nhận thay đổi:

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 

Dưới đây là làm thế nào để xóa một mục:

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

    if '' == curr: return 

    treeView.delete(curr) 
Các vấn đề liên quan