按下 <button-1> 时如何使 tkinter <Enter> 事件起作用?
how to make tkinter <Enter> event work when <button-1> is pressed?
我想像在绘画中一样填充矩形。当按下鼠标按钮时,我希望我输入的每个矩形都被填充,否则我不希望发生任何事件。
这是我的代码:
from tkinter import Canvas
import tkinter
_width = 50
_height = 50
_size = 8
root = tkinter.Tk()
root.title("draw me a lovely matrix")
canv = Canvas(root, width=_width * _size, height=_height * _size)
class Wrapper:
btn1d = False
def set_btn1d(value):
print(value)
Wrapper.btn1d = value
def toggle_color(rect):
print('called')
if Wrapper.btn1d:
color = canv.itemcget(rect, 'fill')
canv.itemconfig(rect, fill=("#aaa" if color == '#fff' else '#fff'))
rects = []
canv.bind('<ButtonPress-1>', lambda e, value=True: set_btn1d(value))
canv.bind('<ButtonRelease-1>', lambda e, value=False: set_btn1d(value))
for i in range(_size):
for j in range(_size):
rect = canv.create_rectangle(_width * j, _height * i, _width * (j + 1), _height * (i + 1), fill="#fff", width=0)
rects.append(rect)
canv.tag_bind(rect, '<Enter>', lambda e, rect=rect: toggle_color(rect))
canv.pack()
root.mainloop()
问题是当我按下鼠标按钮时,只有按下鼠标的单元格检测到鼠标指针的进入(也是最后释放鼠标的单元格)
任何对我的代码有益的一般性建议当然会非常感激。
根本不需要使用<Enter>
。尝试:
from tkinter import Canvas
import tkinter
_width = 50
_height = 50
_size = 8
root = tkinter.Tk()
root.title("draw me a lovely matrix")
canv = Canvas(root, width=_width * _size, height=_height * _size)
rects = []
# B1-Motion activates every time the mouse is moved with button 1 held down
# See https://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
# We fill every item that the mouse comes in contact with while button 1 is held
# The tag tied to the item the event was called on, "current", points to the
# item under the pointer when the button was pressed, i.e. the first box.
# Only the x and y properties change, so we configure the item closest to those.
def motion(event):
canv.itemconfig(canv.find_closest(event.x, event.y), fill="#aaa")
canv.bind("<B1-Motion>", motion)
for i in range(_size):
for j in range(_size):
rects.append(canv.create_rectangle(_width * j, _height * i, _width * (j + 1), _height * (i + 1), fill="#fff", width=0))
# don't need to bind anything to <Enter>
canv.pack()
root.mainloop()
不幸的是,没有使用 <Enter>
的可能解决方案。如果 <Enter>
按照您希望的方式工作,则以下非工作代码理论上是正确的。
import tkinter
_width = 50
_height = 50
_size = 8
root = tkinter.Tk()
root.title("draw me a lovely matrix")
canv = tkinter.Canvas(root, width=_width * _size, height=_height * _size)
rects = []
# This javascript-like approach doesn't work in tkinter because
# <Enter> and <Leave> events aren't called while any mouse buttons
# are held.
def fill(tag):
canv.itemconfig(tag, fill="#aaa")
def enter(event):
fill("current")
def mousedown(event):
fill("current")
canv.tag_bind("all", "<Enter>", enter, add="+")
def mouseup(event):
canv.tag_unbind("all", "<Enter>")
canv.bind("<Button-1>", mousedown)
canv.bind("<ButtonRelease-1>", mouseup)
for i in range(_size):
for j in range(_size):
rects.append(canv.create_rectangle(_width * j, _height * i, _width * (j + 1), _height * (i + 1), fill="#fff", width=0))
canv.pack()
root.mainloop()
在 python 3.8.2、tkinter 8.6
中测试
我想像在绘画中一样填充矩形。当按下鼠标按钮时,我希望我输入的每个矩形都被填充,否则我不希望发生任何事件。
这是我的代码:
from tkinter import Canvas
import tkinter
_width = 50
_height = 50
_size = 8
root = tkinter.Tk()
root.title("draw me a lovely matrix")
canv = Canvas(root, width=_width * _size, height=_height * _size)
class Wrapper:
btn1d = False
def set_btn1d(value):
print(value)
Wrapper.btn1d = value
def toggle_color(rect):
print('called')
if Wrapper.btn1d:
color = canv.itemcget(rect, 'fill')
canv.itemconfig(rect, fill=("#aaa" if color == '#fff' else '#fff'))
rects = []
canv.bind('<ButtonPress-1>', lambda e, value=True: set_btn1d(value))
canv.bind('<ButtonRelease-1>', lambda e, value=False: set_btn1d(value))
for i in range(_size):
for j in range(_size):
rect = canv.create_rectangle(_width * j, _height * i, _width * (j + 1), _height * (i + 1), fill="#fff", width=0)
rects.append(rect)
canv.tag_bind(rect, '<Enter>', lambda e, rect=rect: toggle_color(rect))
canv.pack()
root.mainloop()
问题是当我按下鼠标按钮时,只有按下鼠标的单元格检测到鼠标指针的进入(也是最后释放鼠标的单元格)
任何对我的代码有益的一般性建议当然会非常感激。
根本不需要使用<Enter>
。尝试:
from tkinter import Canvas
import tkinter
_width = 50
_height = 50
_size = 8
root = tkinter.Tk()
root.title("draw me a lovely matrix")
canv = Canvas(root, width=_width * _size, height=_height * _size)
rects = []
# B1-Motion activates every time the mouse is moved with button 1 held down
# See https://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
# We fill every item that the mouse comes in contact with while button 1 is held
# The tag tied to the item the event was called on, "current", points to the
# item under the pointer when the button was pressed, i.e. the first box.
# Only the x and y properties change, so we configure the item closest to those.
def motion(event):
canv.itemconfig(canv.find_closest(event.x, event.y), fill="#aaa")
canv.bind("<B1-Motion>", motion)
for i in range(_size):
for j in range(_size):
rects.append(canv.create_rectangle(_width * j, _height * i, _width * (j + 1), _height * (i + 1), fill="#fff", width=0))
# don't need to bind anything to <Enter>
canv.pack()
root.mainloop()
不幸的是,没有使用 <Enter>
的可能解决方案。如果 <Enter>
按照您希望的方式工作,则以下非工作代码理论上是正确的。
import tkinter
_width = 50
_height = 50
_size = 8
root = tkinter.Tk()
root.title("draw me a lovely matrix")
canv = tkinter.Canvas(root, width=_width * _size, height=_height * _size)
rects = []
# This javascript-like approach doesn't work in tkinter because
# <Enter> and <Leave> events aren't called while any mouse buttons
# are held.
def fill(tag):
canv.itemconfig(tag, fill="#aaa")
def enter(event):
fill("current")
def mousedown(event):
fill("current")
canv.tag_bind("all", "<Enter>", enter, add="+")
def mouseup(event):
canv.tag_unbind("all", "<Enter>")
canv.bind("<Button-1>", mousedown)
canv.bind("<ButtonRelease-1>", mouseup)
for i in range(_size):
for j in range(_size):
rects.append(canv.create_rectangle(_width * j, _height * i, _width * (j + 1), _height * (i + 1), fill="#fff", width=0))
canv.pack()
root.mainloop()
在 python 3.8.2、tkinter 8.6
中测试