#python #tkinter #event-handling #mouseevent
#python #tkinter #обработка событий #mouseevent
Вопрос:
Я пытаюсь имитировать курсор, рисуя его на холсте и перемещая в ответ на события движения.
Согласно документации «нет события мыши для движения мыши без нажатия кнопки, за исключением ввода и выхода». Однако Tkinter принимает привязку к <Motion>
событию, которое, похоже, является тем, что я хочу, за исключением одной вещи: вы должны сначала щелкнуть где-нибудь в корневом окне, чтобы <Motion>
начать запуск. Как только указатель покинет окно, повторный вход без щелчка сработает, <Enter>
но не <Motion>
— даже если окно никогда не теряет фокус.
Такое поведение несовместимо с моей целью (тоже вызывает недоумение; зачем кому-то это нужно?), Поэтому я написал небольшую программу, чтобы посмотреть, смогу ли я изменить это, возможно, с помощью event_generate
. Я не мог (пока), но в процессе я обнаружил, что Tkinter как-то нечетко обрабатывает события мыши. Во-первых, он промахивается <Enter>
и <Leave>
довольно часто (вы перемещаете указатель, а он все еще думает, что он внутри, и наоборот). Еще более удивительно: иногда, когда вы перемещаете указатель, он запускает <Enter>
одно или два <Motion>
события без щелчка в корневом окне. Затем он отключается: больше никаких <Motion>
событий, пока вы не нажмете. Вы можете воспроизвести эти проблемы с помощью приведенного ниже кода. Я использую OS X El Capitan, Python 2.7.
Любые объяснения этого поведения или идеи о том, как отслеживать события движения без нажатия, будут оценены.
from Tkinter import *
def enter(e):
if e.widget is not canvas:
print "<Enter> caught by", e.widget
if canvas.state != "outside":
print "<Enter> in 'inside' state!"
canvas.state = "inside"
canvas.n = 0
canvas.itemconfig(inout, text=canvas.state)
canvas.itemconfig(count, text="no motions yet")
canvas.event_generate('<Button-1>', x=e.x, y=e.y, state=0x0100)
#canvas.update()
def motion(e):
if canvas.state == "outside":
print "<Motion> in 'outside' state!"
canvas.n = 1
canvas.itemconfig(count, text="motions since enter: {:03d}".format(canvas.n))
#canvas.update()
def leave(e):
if e.widget is not canvas:
print "Leave caught by", e.widget
if canvas.state == "outside":
print "<Leave> in 'outside' state!"
canvas.state = "outside"
canvas.itemconfig(inout, text=canvas.state)
canvas.itemconfig(count, text="")
#canvas.update()
root = Tk()
frame = Frame(root)
frame.pack(fill=BOTH)
canvas = Canvas(frame, bg='#E4E4E4', highlightthickness=0)
canvas.grid(row=0, column=0, sticky=W E N S)
canvas.create_text(140, 20, text="(tracking <Enter>, <Motion>, <Leave>)")
inout = canvas.create_text(140, 100, text="outside")
count = canvas.create_text(140, 120, text="")
canvas.n = 0
canvas.state = "outside"
canvas.bind('<Enter>', enter)
canvas.bind('<Motion>', motion)
canvas.bind('<Leave>', leave)
canvas2 = Canvas(frame, height=100, highlightthickness=0)
canvas2.grid(row=1, column=0, sticky=W E)
canvas2.create_text(140, 50, text="(no tracking here)")
frame.rowconfigure(0, weight=1)
def focusout(e):
print "root lost focus"
root.bind('<FocusOut>', focusout)
root.mainloop()
Комментарии:
1. «Согласно документации» — какой документации? Эта документация неверна.
2. Какая-то книга О’Рейли … docstore.mik.ua/orelly/other/python /…
3. Итак, вот откуда я взял эту цитату. Есть идеи о том, почему я иногда получаю события <Motion>? Или об отслеживании <Motion> ов после <Leave>, <Enter>?
4. В Windows ваш пример, похоже, работает так, как ожидалось. Я годами отслеживал <движение> без проблем.