Событие движения виджета Tkinter блокируется событием движения холста при рисовании чего-либо на холсте

#python #tkinter #events

Вопрос:

Когда я ловлю движение в виджете прямоугольника на холсте, он работает правильно, но когда я рисую положение мыши на холсте, событие whidet box больше не срабатывает

Чтобы увидеть проблему, просто раскомментируйте строки в функции canvmove.

Спасибо за вашу помощь.

 from tkinter import *


class box():
    def __init__(self, canvas, startx, starty, endx, endy, **opts):
        self.canvas = canvas
        self.startx, self.starty, self.endx, self.endy=startx, starty, endx, endy
        self.index=self.canvas.create_rectangle(self.startx, self.starty, self.endx, self.endy, fill='orange')
        
        self.tag="BoundingBox" str(self.index)
        self.canvas.addtag(self.tag, 'withtag',self.index)
        
        self.canvas.tag_bind(self.tag, '<Leave>', lambda event,t=self.tag:self.boxleave(event,self.tag))
        self.canvas.tag_bind(self.tag, '<Motion>', lambda event:self.boxmotion(event,self.tag))
        
    def boxleave(self, event, tag):
        self.canvas.itemconfig(tag, fill="orange")
        
    def boxmotion(self, event, tag):
        # print("box motion ", event.x, event.y)
        self.canvas.itemconfig(tag, fill="red")
                
    def showcursorpos(self, event,t):
        self.canvas.delete('mousepos')
     

def canvmove(event):
    # print("canvas motion ", event.x, event.y)
    dashes = [5, 25]
    canvas.delete('mousepos')
    # **********************************************************************
    # WHEN ACTIVATING LINES BELOW THE BOXMOTION EVENT DOESN'T TRIGGER
    # canvas.create_line(event.x, 0, event.x, 1000, dash=dashes, tags='mousepos')
    # canvas.create_line(0, event.y, 1000, event.y, dash=dashes, tags='mousepos')
    # **********************************************************************
    
root = Tk()
canvas = Canvas(root, background="white")
canvas.bind("<Motion>", canvmove)
label = Label(root)

for x in range(0, 200, 50):
    for y in range(0, 200, 50):

        # create unique tag
        tag = 'rectangle_%s_%s' % (x,y)
        rect = box(canvas, x,y,x 40,y 40)
    
canvas.grid()
label.grid()

root.mainloop()
 

Ответ №1:

Вот несколько иной способ достижения тех же или аналогичных результатов.

Он tag состоит из цветов заливки, контура и активного заполнения и применяется к каждому прямоугольнику по мере их создания.

act Метод обрабатывает пунктирные перекрестия, смещая линии на 3 точки.

Это позволяет взаимодействовать как с перекрестием, так и с прямоугольником.

 import tkinter as tk

class box:
    def __init__(self):
        self.master = tk.Tk()
        self.canvas = tk.Canvas(self.master)
        self.canvas.grid(sticky = tk.NSEW)
        self.rect = []
        tag = dict(fill = "orange", outline = "black", activefill = "red")
        for x in range(2, 202, 50):
            for y in range(2, 202, 50):
                self.rect.append(
                    self.canvas.create_rectangle(x,y,x 40,y 40, tag))
        dashes = [5, 25]
        self.itemLine1 = self.canvas.create_line(0, 0, 0, 1000,
                                                dash = dashes, fill = "black")
        self.itemLine2 = self.canvas.create_line(0, 0, 1000, 0,
                                                dash = dashes, fill = "black")
        self.canvas.bind( "<Motion>", self.act)
        
    def act(self, ev):
        self.canvas.coords( self.itemLine1, ev.x 3, 0, ev.x 3, 1000)
        self.canvas.coords( self.itemLine2, 0, ev.y 3, 1000, ev.y 3)

app = box()
app.master.mainloop()
 

Это, возможно, лучшая замена метода act .

Курсор включается, когда над прямоугольником и перекрестием выключены. Когда курсор не находится над прямоугольником, перекрестие включено, а курсор выключен.

     def act(self, ev):
        i = self.canvas.find_enclosed(ev.x-40, ev.y-40, ev.x 40, ev.y 40)
        if i and i[0] in self.rect:
            self.canvas.itemconfig(self.itemLine1, state = "hidden")
            self.canvas.itemconfig(self.itemLine2, state = "hidden")
            self.canvas["cursor"] = "crosshair"
        else:
            self.canvas["cursor"] = "none"
            self.canvas.itemconfig(self.itemLine1, state = "normal")
            self.canvas.itemconfig(self.itemLine2, state = "normal")
            self.canvas.coords( self.itemLine1, ev.x, 0, ev.x, 1000)
            self.canvas.coords( self.itemLine2, 0, ev.y, 1000, ev.y)
 

Ответ №2:

Я размышлял весь день и нашел способ добиться того, что мне было нужно : на самом деле, когда я рисую линии, я предполагаю, что курсор находится не на прямоугольнике, а на только что созданной линии… Итак, я попытался изменить способ рисования линий и нарисовать их вокруг положения мыши ( 3 x-y), а также триггера события !!

Спасибо за твой ответ, Дерек !!!

 canvas.create_line(event.x, 0, event.x, event.y-3, dash=dashes, tags='mousepos')
canvas.create_line(event.x, event.y 3, event.x, 1000, dash=dashes, tags='mousepos')
canvas.create_line(0, event.y, event.x-3, event.y, dash=dashes, tags='mousepos')  
canvas.create_line(event.x 3, event.y, 1000, event.y, dash=dashes, tags='mousepos')
 

Тогда решено 😉