How to move popup window when scrolling a tkinter treeview? How to move popup window when scrolling a tkinter treeview? tkinter tkinter

How to move popup window when scrolling a tkinter treeview?


I have done something similar before by binding a function to mousewheel and recalculate all the new x & y location of your hovering widgets.

class EditableDataTable(tk.Frame):    def __init__(self, parent):        tk.Frame.__init__(self, parent)        self.parent = parent        self.tree = None        self.entryPopup = None        self.list_of_entries = []        ...        self.tree.bind("<MouseWheel>", self._on_mousewheel)    def _on_mousewheel(self, event):        if self.list_of_entries:            def _move():                for i in self.list_of_entries:                    try:                        iid = i.iId                        x, y, width, height = self.tree.bbox(iid, column="Col2") #hardcoded to col2                        i.place(x=x, y=y+height//2, anchor='w', width=width)                    except ValueError:                        i.place_forget()                    except tk.TclError:                        pass            self.master.after(5, _move)    def createPopup(self, row, column):        x,y,width,height = self.tree.bbox(row, column)        # y-axis offset        pady = height // 2        self.entryPopup = EntryPopup(self.tree, row, column)        self.list_of_entries.append(self.entryPopup)        self.entryPopup.place(x=x, y=y+pady, anchor='w', width=width)

Note that this only works on the second column, but should be easy enough to implement for the rest.


You will need to do the math and move the entry widget when the tree is scrolled. I have edited your code and I programmed the scrollbar buttons only. If you click the button the entry widget will scroll with the tree. I did not program the wheelmouse scrolling or dragging the scrollbar. You should be able to figure out the rest.

import tkinter as tkimport tkinter.font as tkfontfrom tkinter import ttkclass EntryPopup(ttk.Entry):    def __init__(self, parent, itemId, col, **kw):        super().__init__(parent, **kw)        self.tv = parent        self.iId = itemId        self.column = col        self['exportselection'] = False        self.focus_force()        self.bind("<Return>", self.onReturn)    def saveEdit(self):        self.tv.set(self.iId, column=self.column, value=self.get())        print("EntryPopup::saveEdit---{}".format(self.iId))    def onReturn(self, event):        self.tv.focus_set()        self.saveEdit()        self.destroy()class EditableDataTable(tk.Frame):    def __init__(self, parent):        tk.Frame.__init__(self, parent)        self.parent = parent        self.tree = None        self.entryPopup = None        columns = ("Col1", "Col2")        # Create a treeview with vertical scrollbar.        self.tree = ttk.Treeview(self, columns=columns, show="headings")        self.tree.grid(column=0, row=0, sticky='news')        self.tree.heading("#1", text="col1")        self.tree.heading("#2", text="col2")        self.vsb = ttk.Scrollbar(self, orient="vertical", command=self.tree.yview)        self.tree.configure(yscrollcommand=self.vsb.set)        self.vsb.grid(column=1, row=0, sticky='ns')        self.grid_columnconfigure(0, weight=1)        self.grid_rowconfigure(0, weight=1)        self.entryPopup = None        self.curSelectedRowId = ""        col1 = []        col2 = []        for r in range(50):            col1.append("data 1-{}".format(r))            col2.append("data 2-{}".format(r))        for i in range(min(len(col1),len(col2))):            self.tree.insert('', i, values=(col1[i], col2[i]))        self.tree.bind('<Double-1>', self.onDoubleClick)        self.vsb.bind('<ButtonPress-1>', self.func)    def func(self, event):        print(self.vsb.identify(event.x, event.y))        if hasattr(self.entryPopup, 'y'):            item = self.vsb.identify(event.x, event.y)            if item == 'uparrow':                self.entryPopup.y += 20            elif item == 'downarrow':                self.entryPopup.y -= 20            self.entryPopup.place(x=self.entryPopup.x, y=self.entryPopup.y, )    def createPopup(self, row, column):        x, y, width, height = self.tree.bbox(row, column)        # y-axis offset        pady = height // 2        self.entryPopup = EntryPopup(self.tree, row, column)        self.entryPopup.x = x        self.entryPopup.y = y+pady        self.entryPopup.place(x=x, y=y+pady, anchor='w', width=width)    def onDoubleClick(self, event):        rowid = self.tree.identify_row(event.y)        column = self.tree.identify_column(event.x)        self.createPopup(rowid, column)root = tk.Tk()for row in range(2):    root.grid_rowconfigure(row, weight=1)root.grid_columnconfigure(0, weight=1)label = tk.Label(root, text="Double-click to edit and press 'Enter'")label.grid(row=0, column=0, sticky='news', padx=10, pady=5)dataTable = EditableDataTable(root)dataTable.grid(row=1, column=0, sticky="news", pady=10, padx=10)root.geometry("450x300")root.mainloop()