首页 > 解决方案 > python tkinter canvas将背景图像放在中心

问题描述

全部

这是我第一次使用 Tkinter。

我的工作是加载图像,在对象上绘制边界框并给它们正确的标签,如下所示:

文本

这是我的代码

class ExampleApp(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        self.x = 0
        self.y = 0
        self.img = ImageTk.PhotoImage(file = "0.png") 
        self.canvas = tk.Canvas(self, width=1080, height=720)
        self.canvas.create_image(20, 20, anchor=NW, image=self.img)
        self.canvas.pack()
        self.canvas.bind("<ButtonPress-1>", self.on_button_press)
        self.canvas.bind("<B1-Motion>", self.on_move_press)
        self.canvas.bind("<Motion>", self.moving)

        self.start_x = None
        self.start_y = None
        self.rect = None


    def right_click(self, event):
        self.canvas.delete(self.canvas.find_closest(event.x, event.y))

    def moving(self, event):
        all_item = self.canvas.find_all()

        for i in all_item[1:]:
            for i in all_item:
                self.canvas.itemconfig(i, width=2.0, outline='red')

            target = self.canvas.find_closest(event.x, event.y)[0]
            self.canvas.itemconfig(target, width=4.0, outline='yellow')

    def on_button_press(self, event):
        self.start_x = event.x
        self.start_y = event.y
        self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, width=2.0, outline='red')

    def on_move_press(self, event):
        curX, curY = (event.x, event.y)
        self.canvas.coords(self.rect, self.start_x, self.start_y, curX, curY)

    def on_button_release(self, event):
        pass

if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()

我想要的是当我在矩形移动鼠标时,它会变成黄色。

问题是只有当鼠标正好在矩形的边缘时矩形才会变成黄色。

因为背景图片也是画布项目之一,所以 find_closest 函数将始终

当鼠标不在矩形边缘时返回图片。

有人有更好的主意吗??

标签: pythoncanvastkinterlabel

解决方案


对于填充的矩形,您只需要

create_rectangle(..., activeoutline="yellow") 

没有使用功能moving()


对于空矩形,您必须获取所有矩形并使用矩形使用canvas.bbox(id)的获取区域(x1,y1,x2,y2)并与event.x, event.y

要仅检查矩形,我将标签添加到矩形

self.canvas.create_rectangle(..., tag='rect')

后来我只能得到矩形

all_rect = self.canvas.find_withtag('rect')

def moving(self, event):
    all_rect = self.canvas.find_withtag('rect')

    x = event.x
    y = event.y

    for i in all_rect:
        x1, y1, x2, y2 = self.canvas.bbox(i)

        if x1 <= x <= x2 and y1 <= y <= y2:
            self.canvas.itemconfig(i, width=4.0, outline='yellow')
        else:
            self.canvas.itemconfig(i, width=2.0, outline='red')

最终而不是使用find_withtag()bbox()你可以使用 list 来保持

(rect_id, (x1,y1,x2,y3), text_id) 

并使用它moving()来查找矩形,然后您也可以更改矩形中的文本。


完整的示例代码。

我添加了重叠的矩形来测试它是否会改变两个矩形的颜色。

import tkinter as tk
from PIL import ImageTk

class ExampleApp(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)

        self.x = 0
        self.y = 0

        self.img = ImageTk.PhotoImage(file="image.jpg") 
        self.canvas = tk.Canvas(self, width=1080, height=720)
        self.canvas.pack()

        self.canvas.bind("<ButtonPress-1>", self.on_button_press)
        self.canvas.bind("<B1-Motion>", self.on_move_press)
        self.canvas.bind("<Motion>", self.moving)

        self.canvas.create_image(20, 20, anchor='nw', image=self.img)

        self.canvas.create_rectangle(50, 50, 100, 100, width=2.0, outline='red', tag='rect')
        self.canvas.create_rectangle(200, 200, 250, 250, width=2.0, outline='red', tag='rect')
        self.canvas.create_rectangle(75, 75, 225, 225, width=2.0, outline='red', tag='rect')

        self.start_x = None
        self.start_y = None
        self.rect = None

    def right_click(self, event):
        self.canvas.delete(self.canvas.find_closest(event.x, event.y))

    def moving(self, event):
        all_rect = self.canvas.find_withtag('rect')

        x = event.x
        y = event.y

        for i in all_rect:
            x1, y1, x2, y2 = self.canvas.bbox(i)
            if x1 <= x <= x2 and y1 <= y <= y2:
                self.canvas.itemconfig(i, width=4.0, outline='yellow')
            else:
                self.canvas.itemconfig(i, width=2.0, outline='red')

    def on_button_press(self, event):
        self.start_x = event.x
        self.start_y = event.y
        self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, width=2.0, outline='red', tag='rect')

    def on_move_press(self, event):
        curX, curY = (event.x, event.y)
        self.canvas.coords(self.rect, self.start_x, self.start_y, curX, curY)

    def on_button_release(self, event):
        pass

if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()

编辑:使用列表(rect_id, (x1,y1,x2,y3), text_id)更改矩形和文本颜色的代码。我on_button_release()用来将新矩形添加到此列表中。

import tkinter as tk
from PIL import ImageTk

class ExampleApp(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)

        self.x = 0
        self.y = 0

        self.img = ImageTk.PhotoImage(file="image.jpg") 
        self.canvas = tk.Canvas(self, width=1080, height=720)
        self.canvas.pack()

        self.canvas.bind("<ButtonPress-1>", self.on_button_press)
        self.canvas.bind("<ButtonRelease-1>", self.on_button_release)
        self.canvas.bind("<B1-Motion>", self.on_move_press)
        self.canvas.bind("<Motion>", self.moving)

        self.canvas.create_image(20, 20, anchor='nw', image=self.img)

        self.all_rect = []

        rect_id = self.canvas.create_rectangle(50, 50, 100, 100, width=2.0, outline='red')
        text_id = self.canvas.create_text(55, 57, text='A', fill="red")
        self.all_rect.append((rect_id, (50, 50, 100, 100), text_id))

        rect_id = self.canvas.create_rectangle(200, 200, 250, 250, width=2.0, outline='red')
        text_id = self.canvas.create_text(205, 207, text='B', fill="red")
        self.all_rect.append((rect_id, (200, 200, 250, 250), text_id))

        rect_id = self.canvas.create_rectangle(75, 75, 225, 225, width=2.0, outline='red')
        text_id = self.canvas.create_text(80, 82, text='C', fill="red")
        self.all_rect.append((rect_id, (75, 75, 225, 225), text_id))

        self.start_x = None
        self.start_y = None
        self.rect = None


    def right_click(self, event):
        self.canvas.delete(self.canvas.find_closest(event.x, event.y))

    def moving(self, event):

        x = event.x
        y = event.y

        for rect_id, bbox, text_id in self.all_rect:
            x1, y1, x2, y2 = bbox
            if x1 <= x <= x2 and y1 <= y <= y2:
                self.canvas.itemconfig(rect_id, width=4.0, outline='yellow')
                if text_id:
                    self.canvas.itemconfig(text_id, fill='yellow')
            else:
                self.canvas.itemconfig(rect_id, width=2.0, outline='red')
                if text_id:
                    self.canvas.itemconfig(text_id, fill='red')

    def on_button_press(self, event):
        self.start_x = event.x
        self.start_y = event.y
        self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, width=2.0, outline='red')

    def on_move_press(self, event):
        curX, curY = (event.x, event.y)
        self.canvas.coords(self.rect, self.start_x, self.start_y, curX, curY)

    def on_button_release(self, event):
        curX, curY = (event.x, event.y)

        x1, x2 = sorted((curX, self.start_x)) # I need `x1 <= x2` in `moving()`
        y1, y2 = sorted((curY, self.start_y)) # I need `y1 <= y2` in `moving()`

        self.all_rect.append((self.rect, (x1, y1, x2, y2), None) )

if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()

推荐阅读