How to make ttk.Treeview strings editable?

Is it possible to use ttk Treeview with editable strings?

I mean, it should look more like a table. For example, when you double-click on an item, make column # 0 “editable”.

If this is not possible, any way to allow the selection of the mouse by element will be just fine. I did not mention this in tkdocs or other documents.

+7
source share
4 answers

After much research, I did not find such an opportunity, so I think there is. Tk is a very simple interface that allows the programmer to create “high-level” functions from the basics. Therefore, my desired behavior in this way.

def onDoubleClick(self, event): ''' Executed, when a row is double-clicked. Opens read-only EntryPopup above the item 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) # get column position info x,y,width,height = self._tree.bbox(rowid, column) # y-axis offset # pady = height // 2 pady = 0 # place Entry popup properly text = self._tree.item(rowid, 'text') self.entryPopup = EntryPopup(self._tree, rowid, text) self.entryPopup.place( x=0, y=y+pady, anchor=W, relwidth=1) 

This is the method inside the class that makes up ttk.Treeview as self._tree

And then EntryPopup is a very simple subclass of Entry:

 class EntryPopup(Entry): def __init__(self, parent, iid, text, **kw): ''' If relwidth is set, then width is ignored ''' super().__init__(parent, **kw) self.tv = parent self.iid = iid self.insert(0, text) # self['state'] = 'readonly' # self['readonlybackground'] = 'white' # self['selectbackground'] = '#1BA1E2' self['exportselection'] = False self.focus_force() self.bind("<Return>", self.on_return) self.bind("<Control-a>", self.select_all) self.bind("<Escape>", lambda *ignore: self.destroy()) def on_return(self, event): self.tv.item(self.iid, text=self.get()) self.destroy() def select_all(self, *ignore): ''' Set selection on the whole text ''' self.selection_range(0, 'end') # returns 'break' to interrupt default key-bindings return 'break' 
+5
source

You can also open the tool window with the editable fields listed in the Records section to update the values. This example has a tree structure with three columns and does not use subclasses.

Snap a double click to this:

 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 other attributes and geometry #### # Grab the entry 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 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 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 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) 

Then confirm the changes:

 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 

Here's how to delete an entry:

 def DeleteCurrentEntry(self, treeView): curr = treeView.focus() if '' == curr: return treeView.delete(curr) 
+1
source

I don’t know how to make the row editable, but to fix the click on the row, you use the virtual <<TreeviewSelect>> event. This is related to the routine using the bind() method, then you use the selection() method to get the identifiers of the selected elements.

These are fragments from an existing program, but show the basic sequence of calls:

 # 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 
-1
source

It is easy to create a tree for the specified path set in the constructor. You can bind your event to your element on this tree. The function of the event is left in such a way that the element can be used in many ways. In this case, it will show the name of the element when double-clicking on it. Hope this helps someone.

  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() 
-1
source

Source: https://habr.com/ru/post/952933/


All Articles