Home > database >  Tkinter Widget Motion Event blocked by Canvas Motion Event whent drawing something on canvas
Tkinter Widget Motion Event blocked by Canvas Motion Event whent drawing something on canvas

Time:10-16

When I catch motion in rectangle widget in a canvas it work propertly but when i draw mouseposition in canvas the whidet box event is not trigged anymore

To see the proble just uncomment lines in canvmove function.

Thanks for your help.

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()

CodePudding user response:

Here is a slightly different way to achieve the same or similar results.

The tag consists of fill, outline and activefill colors and is applied to each rectangle as they are created.

The act method handles dashed cross hairs by offsetting the lines by a 3 points.

This allows both cross hair and rectangle interactions.

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()

This is perhaps a better replacement of method act.

The cursor is turned on when over a rectangle and cross hairs turned off. When cursor is not over rectangle then cross hair is on and cursor is off.

    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)

CodePudding user response:

I've been tinking all day and I found a way to achieve what I needed : In fact when drawind lines, I asume the cursor is not on a rectangle but on de line newly created... So, I tried changing the way of drawing the lines and draw them arround the mouse position ( 3 x-y) and the event trigger as well !!

Thanks for your answer Derek !!!

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')

Solved then ;)

  • Related