Tkinter 滚动树状视图时如何移动弹出的ttk.Combobox?

Tkinter 滚动树状视图时如何移动弹出的ttk.Combobox?,tkinter,combobox,popup,treeview,scrollbar,Tkinter,Combobox,Popup,Treeview,Scrollbar,这个问题是对这个问题的延伸 当用户双击树视图时,我创建组合框作为弹出窗口。当我在树状视图上滚动鼠标时,带有箭头的输入框可以正常移动。但是,关联的下拉列表框不会移动。我可以看到ttk组合框实际上是一个条目和一个listbox/PopdownWindow的组合。但是我找不到关于如何访问列表框部分并移动它的适当文档 import tkinter as tk from tkinter import ttk class ComboPopup(ttk.Combobox): def __init__

这个问题是对这个问题的延伸

当用户双击树视图时,我创建组合框作为弹出窗口。当我在树状视图上滚动鼠标时,带有箭头的输入框可以正常移动。但是,关联的下拉列表框不会移动。我可以看到ttk组合框实际上是一个条目和一个listbox/PopdownWindow的组合。但是我找不到关于如何访问列表框部分并移动它的适当文档

import tkinter as tk
from tkinter import ttk

class ComboPopup(ttk.Combobox):
    def __init__(self, parent, itemId, col, **kw):
        super().__init__(parent, **kw)
        self.tv = parent
        self.iId = itemId
        self.column = col
        choices = ["option1", "option2", "option3"]
        v = tk.StringVar()
        self.config(state="readonly", textvariable=v, values=choices, width=9)

        self.focus_force()

        existingChoice = 1
        self.current(existingChoice)
        #self.set(self.choices[existingChoice])

        self.bind("<Return>", self.onReturn)
        self.bind("<Escape>", self.onEscape)
        #self.bind("<FocusOut>", self.onFocusOut)        

    def saveCombo(self):    
        self.tv.set(self.iId, column=self.column, value=self.get())
        print("EntryPopup::saveEdit---{}".format(self.iId))

    def onEscape(self, event):
        print("ComboPopup::onEscape")
        # give focus back to the treeview.
        self.tv.focus_set()

        self.destroy()
    def onReturn(self, event):
        self.tv.focus_set()
        self.saveCombo()
        self.destroy()

class EditableDataTable(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.parent = parent
        self.tree = None
        self.comboPopup = None
        self.curSelectedRowId = ""
        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)

        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.tree.bind("<MouseWheel>", self.onMousewheel)

    def onMousewheel(self, event):
        popupWindow = None
        #TODO: Fix the scroll of combobox (the associated listbox)        
        if self.comboPopup != None:
            if ttk.Combobox.winfo_exists(self.comboPopup):
                popupWindow = self.comboPopup

                pd = popupWindow.tk.call('ttk::combobox::PopdownWindow', popupWindow)
                lb = popupWindow.tk.eval('return {}.f.l'.format(pd))
                print("pw: {}".format(popupWindow))
                print("pd: {}".format(pd))
                print("lb: {}".format(lb))

        if popupWindow != None:
            def _move():
                try:
                    iid = popupWindow.iId
                    x, y, width, height = self.tree.bbox(iid, column="#2") #hardcoded to col2
                    popupWindow.place(x=x, y=y+height//2, anchor='w', width=width)
                except ValueError:
                    popupWindow.place_forget()
                except tk.TclError:
                    pass

            popupWindow.after(5, _move)
            if ttk.Combobox.winfo_exists(self.comboPopup):
                #pd.after(5, _move) # does not work
                #lb.after(5, _move) # does not work
                pass

    def createPopup(self, row, column):
        x, y, width, height = self.tree.bbox(row, column)

        # y-axis offset
        pady = height // 2
        self.comboPopup = ComboPopup(self.tree, row, column)
        self.comboPopup.x = x
        self.comboPopup.y = y+pady
        self.comboPopup.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()

将tkinter作为tk导入
从tkinter导入ttk
类ComboPopup(ttk.Combobox):
定义初始值(自身、父项、项ID、列,**kw):
超级()
self.tv=家长
self.iId=itemId
self.column=col
选项=[“选项1”、“选项2”、“选项3”]
v=tk.StringVar()
self.config(state=“readonly”,textvariable=v,values=choices,width=9)
self.focus_force()
现有选项=1
自身电流(现有选择)
#self.set(self.choices[existingChoice])
self.bind(“,self.onReturn)
self.bind(“,self.onEscape)
#self.bind(“,self.onFocusOut)
def saveCombo(自我):
self.tv.set(self.iId,column=self.column,value=self.get())
打印(“EntryPopup::saveEdit--{}”.format(self.iId))
def onEscape(自我、事件):
打印(“ComboPopup::onEscape”)
#把焦点放回树视图。
self.tv.focus_set()
自我毁灭
def onReturn(自身、事件):
self.tv.focus_set()
self.saveCombo()
自我毁灭
类EditableDataTable(tk.Frame):
定义初始化(自身,父级):
tk.Frame.\uuuu init\uuuuu(自,父)
self.parent=parent
self.tree=None
self.comboPopup=None
self.curseelectedrowid=“”
列=(“Col1”、“Col2”)
#使用垂直滚动条创建树状视图。
self.tree=ttk.Treeview(self,columns=columns,show=“headers”)
self.tree.grid(列=0,行=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(列=1,行=0,sticky='ns')
self.grid\u column配置(0,权重=1)
self.grid_rowconfigure(0,权重=1)
col1=[]
col2=[]
对于范围(50)内的r:
col1.append(“数据1-{}”.format(r))
col2.append(“数据2-{}”.format(r))
对于范围内的i(最小值(len(col1),len(col2)):
self.tree.insert(“”,i,value=(col1[i],col2[i]))
self.tree.bind(“”,self.onDoubleClick)
self.tree.bind(“,self.onmouseheel)
鼠标滚轮上的def(自身、事件):
popupWindow=无
#TODO:修复combobox(关联列表框)的滚动
如果self.comboPopup!=无:
如果ttk.Combobox.winfo_存在(self.Combobox弹出窗口):
popupWindow=self.comboPopup
pd=popupWindow.tk.call('ttk::combobox::PopupDownWindow',popupWindow)
lb=popupWindow.tk.eval('return{}.f.l'.format(pd))
打印(“pw:{}”.format(popupWindow))
打印(“pd:{}”。格式(pd))
打印(“lb:{}”。格式(lb))
如果弹出窗口!=无:
def_move():
尝试:
iid=popupWindow.iid
x、 y,width,height=self.tree.bbox(iid,column=“#2”)#硬编码为col2
popupWindow.place(x=x,y=y+高度//2,锚点=w',宽度=宽度)
除值错误外:
poppuphindow.place_忘记()
除了tk.TclError:
通过
在(5,_移动)之后弹出窗口
如果ttk.Combobox.winfo_存在(self.Combobox弹出窗口):
#pd.在(5)之后,移动不起作用
#lb.after(5,_move)#不起作用
通过
def createPopup(自身、行、列):
x、 y,宽度,高度=self.tree.bbox(行,列)
#y轴偏移
帕迪=高度//2
self.comboPopup=comboPopup(self.tree,row,column)
self.comboPopup.x=x
self.comboPopup.y=y+pady
self.comboPopup.place(x=x,y=y+pady,anchor='w',width=width)
定义双击(自身、事件):
rowid=self.tree.identification\u行(event.y)
column=self.tree.identification\u列(event.x)
self.createPopup(rowid,column)
root=tk.tk()
对于范围(2)中的行:
root.grid\u rowconfigure(行,权重=1)
root.grid\u columnconfigure(0,权重=1)
label=tk.label(root,text=“双击编辑并按‘Enter’”)
label.grid(行=0,列=0,sticky='news',padx=10,pady=5)
dataTable=EditableDataTable(根)
网格(行=1,列=0,sticky=“news”,pady=10,padx=10)
根几何(“450x300”)
root.mainloop()
如何访问“列表框”并将其与“条目”一起移动?我在Python3上使用的是tkinter 8.6版。

正如我之前在文章中所说的,您需要移动这些小部件,这意味着要计算并跟踪它。我不知道为什么在编辑过程中需要多个活动弹出窗口小部件。我的treeview内联编辑解决方案是一次只允许编辑一个单元格。这样做可以降低支持这种事情所需的代码的复杂性。我在github上发布了一个关于这个的工作演示,我会在这里发布代码,但是演示中有很多代码。Treeview是一个非常难对付的野兽,如果你想把它全部覆盖的话。无论如何,我会发布下面的链接,让它运行一下,它可能适合你的需要。代码目前正在处理中,但可以按原样使用。代码在一个文件中,不需要导入


我不想编辑多个单元格。实际上,ttk.Combobox是条目和列表框的组合。启动组合框弹出窗口时,有两个小部件:文本字段和