Tkinter Canvas滚动后点击文本无法获取正确值的问题
解决Tkinter Canvas滚动后点击文本获取错误值的问题
问题原因
你用scan_mark/scan_dragto实现的滚动是画布视图平移,并没有改变文本元素的实际坐标。点击时直接用event.x/event.y(视图坐标)调用find_closest,会匹配到原始坐标下该位置的元素,而非你实际点击的、被滚动后的元素。
修复步骤
- 转换点击坐标:用
canvas.canvasx(event.x)和canvas.canvasy(event.y)将视图坐标转换为画布的原始坐标,这样find_closest就能找到正确的元素。 - 直接获取文本内容:无需通过字典反向查找,用
canvas.itemcget(item_id, "text")直接获取文本元素的内容,更简洁可靠。 - 优化冗余代码:移除重复定义的字典,减少全局变量依赖。
修复后的完整代码
import tkinter as tk import customtkinter root = tk.Tk() root.config(bg='#ffffff') w, h = root.winfo_screenwidth(), root.winfo_screenheight() root.geometry("%dx%d+0+0" % (w, h)) root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id())) root.resizable(True, True) def Example(): atras_button2 = None def optionmenu_callback(): nonlocal atras_button2 if atras_button2: atras_button2.destroy() def scroll_start(event): canvas.scan_mark(event.x, event.y) def scroll_move(event): canvas.scan_dragto(event.x, event.y, gain=2) canvasmaster = tk.Canvas(root, width=252, height=512, background="#ffffff") canvasmaster.place(relx=0.428, rely=0.48, anchor="center") canvas = tk.Canvas(master=canvasmaster, width=250, height=350, background="white") canvas.configure(scrollregion=(0, 0 ,250,1000)) canvas.grid(row=0, column=0, sticky="nsew") def onObjectClick(event): nonlocal atras_button2 # 转换坐标为画布原始坐标 x = canvas.canvasx(event.x) y = canvas.canvasy(event.y) # 找到正确的元素 item_id = canvas.find_closest(x, y)[0] # 直接获取文本内容 prefix = canvas.itemcget(item_id, "text") print("prefijo", prefix) textprefijo_var = customtkinter.StringVar(value=prefix) textprefijo = customtkinter.CTkLabel( master=root, textvariable=textprefijo_var, anchor="w", padx=4, font=customtkinter.CTkFont(family="Lato", size=18), text_color="#333333" ) textprefijo.place(relx=0.374, rely=0.20, anchor="w") canvas.destroy() canvasmaster.destroy() atras_button2 = customtkinter.CTkButton( master=root, corner_radius=8, height=60, border_spacing=1, border_color="#385974", border_width=2, text="ATRÁS", font=customtkinter.CTkFont(family="Roboto", size=20), fg_color="#ffffff", text_color="#385974", hover_color=("#ffffff", "gray10"), width=60, anchor="center", command=optionmenu_callback ) atras_button2.place(relx=0.515, rely=0.20, anchor="center") # 只定义一次字典 diccionariodepaises = { 'España':'1','Afganistán':'2','Albania':'3','Alemania':'4','Angola':'5','Anguila':'6', 'Antigua y Barbuda':'7','Antillas Holandesas':'8','Arabia Saudita':'9','Argelia':'10', 'Argentina':'11','Armenia':'12','Aruba':'13','Australia':'14','Austria':'15','Azerbaiyán':'16', 'Bahamas':'17','Bangladés':'18','Barbados':'19','Bélgica':'20','Belice':'21','Benín':'22', 'Bermudas':'23','Bielorrusia':'24','Bolivia':'25','Bosnia y Herzegovina':'26','Botsuana':'27', 'Brasil':'28','Brunéi':'29','Bulgaria':'30','Burkina Faso':'31','Burundi':'32' } for idx, (country, _) in enumerate(diccionariodepaises.items()): canvas.create_text(10, (idx+1)*30, anchor="w", text=country, tags=str(idx+1)) canvas.tag_bind(str(idx+1), '<ButtonPress-1>', onObjectClick) canvas.bind("<ButtonPress-1>", scroll_start) canvas.bind("<B1-Motion>", scroll_move) Entry_textoEMAILreservaBOX= customtkinter.CTkEntry( master=root, width=250, height=60, font=customtkinter.CTkFont(family="Lato", size=10), justify='center', placeholder_text_color="#003f5c", fg_color="#ffffff" ) Entry_textoEMAILreservaBOX.place(relx=0.428, rely=0.20, anchor="center") Entry_textoEMAILreservaBOX.configure(justify="left", state="disabled") atras_button2 = customtkinter.CTkButton( master=root, corner_radius=8, height=60, border_spacing=1, border_color="#385974", border_width=2, text="ATRÁS", font=customtkinter.CTkFont(family="Roboto", size=20), fg_color="#ffffff", text_color="#385974", hover_color=("#ffffff", "gray10"), width=60, anchor="center", command=optionmenu_callback ) atras_button2.place(relx=0.515, rely=0.20, anchor="center") if __name__ == "__main__": Example() root.mainloop()
关键修改点
- 用
canvas.canvasx()和canvasy()转换点击坐标,解决滚动后坐标不匹配的问题。 - 用
canvas.itemcget(item_id, "text")直接获取文本,避免字典反向查找的冗余和出错可能。 - 用
nonlocal替代全局变量,减少全局作用域污染。 - 循环遍历字典时用
enumerate,代码更清晰。
内容的提问来源于stack exchange,提问作者Une
相关产品推荐
相关产品推荐

