Python Tkinter拖放功能的一个巨大的自定义图表的性能和其他问题

idfiyjo8  于 2023-10-14  发布在  Python
关注(0)|答案(1)|浏览(85)

最后的目标是建立一个图表,这是y轴加上主要领域。主字段由单独的框组成(比如20 x20像素)。至少有500 x500个盒子,我希望更多。主字段应该是可拖动的。
在Stackoverflow的帮助下,我选择将图像放在主字段画布上,而不仅仅是标签。使用canvas.move()而不是在拖动时重绘元素。y轴也是一个画布,但带有标签。
这个解决方案对于小画布(100 x100个元素)是可以的,但是当拖动500 x500个元素的画布时,我遇到了延迟(滞后,惯性)。
然后我尝试添加额外的画布,这是内部的。这个想法是在画布上移动内部画布(带有图像),而不仅仅是在单个画布上移动图像。
因此,内部画布必须放置在窗口内。我在Windows上贴上了“canv”标签。并在调用move函数时引用它。
但我可以捕捉窗口只是点击一个小的1像素的区域周围的内部画布周长。
当点击主字段本身时,为了拖动图表的主字段,而不仅仅是1-pxl画布轮廓,应该改变什么?或者解决方案体系结构发生了变化?
需要记住的是,y轴必须与主磁场的垂直运动同步。我设法通过以前的解决方案实现了这种同步,但不是通过当前的解决方案。

import tkinter as tk
from functools import partial

class DraggableCanvas(tk.Canvas):
    def __init__(self, master=None, **kwargs):
        super().__init__(master, **kwargs)
        self.start_pos = 0, 0
        self.bind('<Button>', self.on_drag_start)
        self.image = tk.PhotoImage(file='images\\image_ .png')  # icon-like 20*20 pxls image
        self.tag_bind('canv', '<B1-Motion>', partial(self.on_drag_motion, 'canv'))
        self.add_images()
        self.add_internal_canvas()

    def on_drag_start(self, event):
        self.start_pos = event.x, event.y

    def add_internal_canvas(self):

        int_canvas = tk.Canvas(self, width=200, height=200)
        self.create_window(50, 25, anchor='nw', window=int_canvas, tags='canv')

        for i in range(100):
            for j in range(100):
                int_canvas.create_image(10+j*21, 10+i*21, image=self.image)

    def add_images(self):
        pass
        # for i in range(100):
        #     for j in range(100):
        #         self.create_image(10+j*21, 10+i*21, image=self.image, tags='img')

    def on_drag_motion(self, imgs_tag, event):
        self.tag_raise(imgs_tag)
        self.move(imgs_tag, event.x - self.start_pos[0], event.y - self.start_pos[1])
        self.on_drag_start(event)

def main():
    root = tk.Tk()
    canvas1 = tk.Canvas(root, bg='#303040', width=100, height=480)
    canvas1.pack(side='left', anchor='n')

    for i in range(10):
        lbl = tk.Label(canvas1, text='y_axis', width=5, bg='#303030', fg='white')
        lbl.pack(anchor='n')

    DraggableCanvas(root, bg='grey', width=750, height=480).pack(anchor='nw')
    root.mainloop()

if __name__ == "__main__":
    main()
vawmfj5a

vawmfj5a1#

我有这个

import tkinter as tk
from functools import partial

class DraggableCanvas(tk.Canvas):
    def __init__(self, master=None, **kwargs):
        super().__init__(master, **kwargs)
        self.start_pos = 0, 0
        #self.bind('<Button>', self.on_drag_start)
        #self.tag_bind('canv', '<B1-Motion>', partial(self.on_drag_motion, 'canv'))
        self.image = tk.PhotoImage(file=r"imgs/pawn.black.png")  # icon-like 20*20 pxls image
        self.add_images()
        self.add_internal_canvas()

    def on_drag_start(self, event):
        self.tag_raise("canv")
        eventx = event.x_root-self.bbox("canv")[0] + self.winfo_rootx()
        eventy = event.y_root-self.bbox("canv")[1] + self.winfo_rooty()
        self.start_pos = eventx, eventy

    def add_internal_canvas(self):

        int_canvas = tk.Canvas(self, width=200, height=200, bd=0)
        self.create_window(50, 25, anchor='nw', window=int_canvas, tags="canv")
        int_canvas.bind('<Button>', self.on_drag_start)
        int_canvas.bind('<B1-Motion>', self.on_drag_motion)

        for i in range(100):
            for j in range(100):
                int_canvas.create_image(10+j*21, 10+i*21, image=self.image)

    def add_images(self):
        pass
        for i in range(100):
            for j in range(100):
                self.create_image(10+j*21, 10+i*21, image=self.image)

    def on_drag_motion(self, event):
        dx = event.x_root + self.winfo_rootx()-self.start_pos[0]
        dy = event.y_root + self.winfo_rooty()-self.start_pos[1]
        # The max(..., 0) claps it down so that it can't go off of the screen to the left/top (you can remove it)
        self.moveto("canv", max(dx, 0), max(dy, 0))

def main():
    root = tk.Tk()
    canvas1 = tk.Canvas(root, bg='#303040', width=100, height=480)
    canvas1.pack(side='left', anchor='n')

    for i in range(10):
        lbl = tk.Label(canvas1, text='y_axis', width=5, bg='#303030', fg='white')
        lbl.pack(anchor='n')

    DraggableCanvas(root, bg='grey', width=750, height=480).pack(anchor='nw')
    root.mainloop()

if __name__ == "__main__":
    main()

我认为你的代码的问题是int_canvas吞下了所有发生在它内部的鼠标事件,这样on_drag_starton_drag_motion就不会被调用。为了解决这个问题,我绑定到int_canvas,并在on_drag_starton_drag_motion中稍微改变了计算。我不认为我的代码是非常有效的,所以如果有人想更新它,随时这样做。
现在它有一个问题,你可以把画布拖到屏幕外面。我通过使用max(..., 0)添加了一个小的修复,但这只适用于左侧/顶部。
至于滞后的问题,我在我的电脑上没有看到,但如果你仍然看到它,试着减少tkinter必须处理的东西的数量。例如,您可以使用PIL将某些图像合并合并,并将其显示为1个单个图像。

相关问题