You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取滚动后CustomTkinter Canvas的正确位置以解决绘图偏移

问题:CustomTkinter滚动Canvas后绘图位置偏移

使用CustomTkinter开发绘图程序时,带滚动条的Canvas在滚动后,鼠标拖动绘制椭圆的位置始终与光标错位。尝试过canvasx()和canvasy()方法,但未解决问题。

原代码

from customtkinter import *
from tkinter import Scrollbar

set_appearance_mode('System')
set_default_color_theme('dark-blue')

window = CTk()  # Window
window.geometry("800x520")

fill_color = '#000000'

def draw_with_brush(event):
    fx, fy = event.x - 1 , event.y - 1
    lx, ly = fx + 1, fy + 1
    canvas.create_oval((fx, fy, lx, ly), outline=fill_color, width=10, fill=fill_color)

canvas = CTkCanvas(window, bg='white', bd=2, relief=SUNKEN, height=430, width=700, scrollregion=(0,0,100000,100000))
canvas.place(x=60, y=50)
canvas.bind("<B1-Motion>", draw_with_brush)

x_scroll = Scrollbar(window, orient=HORIZONTAL, command=canvas.xview)
x_scroll.place(x=60, y=495, width=700)
y_scroll = Scrollbar(window, orient=VERTICAL, command=canvas.yview)
y_scroll.place(x=780, y=50, height=430)

canvas.config(xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)

window.mainloop()  # Loop

解决方案

问题核心是**event.x和event.y获取的是鼠标相对于Canvas组件本身的坐标,而非Canvas内部滚动后的实际绘图坐标**。正确做法是用canvas.canvasx(event.x)和canvas.canvasy(event.y)将组件坐标转换为Canvas内部的滚动坐标。

你之前尝试这两个方法但无效,大概率是未正确替换event.x和event.y的位置。修改后的draw_with_brush函数如下:

def draw_with_brush(event):
    # 转换为Canvas内部滚动后的坐标
    x = canvas.canvasx(event.x)
    y = canvas.canvasy(event.y)
    fx, fy = x - 1, y - 1
    lx, ly = fx + 2, fy + 2  # 保持椭圆大小一致
    canvas.create_oval((fx, fy, lx, ly), outline=fill_color, width=10, fill=fill_color)

修改后的完整代码

from customtkinter import *
from tkinter import Scrollbar

set_appearance_mode('System')
set_default_color_theme('dark-blue')

window = CTk()  # Window
window.geometry("800x520")

fill_color = '#000000'

def draw_with_brush(event):
    # 转换鼠标坐标为Canvas滚动后的实际坐标
    x = canvas.canvasx(event.x)
    y = canvas.canvasy(event.y)
    fx, fy = x - 1, y - 1
    lx, ly = fx + 2, fy + 2
    canvas.create_oval((fx, fy, lx, ly), outline=fill_color, width=10, fill=fill_color)

canvas = CTkCanvas(window, bg='white', bd=2, relief=SUNKEN, height=430, width=700, scrollregion=(0,0,100000,100000))
canvas.place(x=60, y=50)
canvas.bind("<B1-Motion>", draw_with_brush)

x_scroll = Scrollbar(window, orient=HORIZONTAL, command=canvas.xview)
x_scroll.place(x=60, y=495, width=700)
y_scroll = Scrollbar(window, orient=VERTICAL, command=canvas.yview)
y_scroll.place(x=780, y=50, height=430)

canvas.config(xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set)

window.mainloop()  # Loop

说明

  • canvasx()和canvasy()会自动计算Canvas的滚动偏移量,将鼠标在组件上的位置转换为Canvas内部的绝对坐标,滚动后绘图位置可精准对应鼠标位置。
  • 调整椭圆右下角坐标计算为fx + 2,确保椭圆大小不会因坐标转换改变。

内容的提问来源于stack exchange,提问作者Little Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:53:29