Tkinter неустойчивая обработка событий мыши

#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 ваш пример, похоже, работает так, как ожидалось. Я годами отслеживал <движение> без проблем.