Работаем с мышью в Tkinter

Возьмем самый простой вариант создания окна и холста:

from tkinter import *
from random import randrange as rnd

root = Tk()
root.geometry('600x600+1+1')

canv = Canvas(bg='white')
canv.pack(fill=BOTH,expand=1)


mainloop()

С функциями (командами) вы уже знакомы, так что данный код не должен вызвать непонимание:

from tkinter import *
from random import randrange as rnd

root = Tk()
root.geometry('600x600+1+1')

canv = Canvas(bg='white')
canv.pack(fill=BOTH,expand=1)

def click():
	x = 200
	y = 200
	r = 50
	canv.create_oval(x-r,y-r,x+r,y+r,width=3)

click()

mainloop()

Сначала создается функция click, которая рисует окружность, а потом эта функция вызывается.

Теперь сделаем так, чтобы она вызывалась по щелчку мыши. Однажды мы это уже делали, но с Черепашкой. В Tkinter немного иначе.
Сначала нужно привязать событие «Щелчок левой кнопкой мыши» на холсте к вызову функции click:

canv.bind('<1>',click)

Но этого мало. Дело в том, что при таком вызове (как и в случае с Черепашкой), функция получает некоторую информацию, которую обязана принять.
Если мы это не учтем, то увидим ошибку:
Снимок экрана от 2016-07-06 18:23:46

Заголовок функции должен выглядеть так:

def click(event):

Но и это еще не все. Если запустить в таком варианте, то возникнет другая ошибка:
Снимок экрана от 2016-07-06 18:26:41

Это происходит потому, что вызов click() не содержит никакой информации, для переменной event.
Пока просто уберем вызов этой функции без щелчка, ведь мы собирались вызывать ее только по щелчку.

from tkinter import *
from random import randrange as rnd

root = Tk()
root.geometry('600x600+1+1')

canv = Canvas(bg='white')
canv.pack(fill=BOTH,expand=1)

def click(event):
	x = 200
	y = 200
	r = 50
	canv.create_oval(x-r,y-r,x+r,y+r,width=3)

canv.bind('<1>',click)

mainloop()

Событий, связанных с мышь, в Tkinter несколько. См. справочник.

Данная программа рисует круг радиусом 50 с центром в (200,200) после щелчка мышью.
Интереснее рисовать круг в том месте, где мы щелкнули мышкой.
Для этого потребуется информация о щелчке, которую мы получаем в переменную event.
Изучим ее, для этого в функцию click поместите print(dir(event)):

def click(event):
	print(dir(event))

Результат должен быть таким:
Снимок экрана от 2016-07-06 20:02:11

Обратите внимание на x,y — это не что иное, как координаты щелчка.
Убедимся в этом: выведем x,y на экран:

def click(event):
	print(event.x, event.y)

Осталось нарисовать в этой точке круг:

from tkinter import *
from random import randrange as rnd

root = Tk()
root.geometry('600x600+1+1')

canv = Canvas(bg='white')
canv.pack(fill=BOTH,expand=1)

def click(event):
	x = event.x
	y = event.y
	r = 50
	canv.create_oval(x-r,y-r,x+r,y+r,width=3)


canv.bind('<1>',click)

mainloop()
1. По щелчку нарисуйте линию от точки (0,0) до точки щелчка
2. По щелчку нарисуйте квадрат с центром в точке щелчка и стороной 20

А теперь будем рисовать линию от места щелчка, до места, где щелкнули в прошлый раз.
Для этого надо запоминать координаты «предыдущего» щелчка.

from tkinter import *
from random import randrange as rnd

root = Tk()
root.geometry('600x600+1+1')

canv = Canvas(bg='white')
canv.pack(fill=BOTH,expand=1)

def click(event):
	global prev_x, prev_y # изменения в этих переменных будут сохранены и после окончания работы функции
	x = event.x
	y = event.y
	r = 50
	if prev_x: # если в переменной prev_x есть значение (не None)
		canv.create_line(x,y,prev_x,prev_y,width=3)
	
	# запомнить координаты этого щелчка как "предыдущие" для следующего		
	prev_x = x 
	prev_y = y
	
# до первого щелчка никаких "предыдущих" нет
prev_x = None 
prev_y = None
canv.bind('<1>',click)

mainloop()

Я догадываюсь, какое может появится у вас желание: сделать так, чтобы линия рисовалась без щелчка, просто по перемещению мыши.
Если вы уже заглянули в Справочник и разобрались с событиями, то знаете, что нужно сделать. А если еще не заглянули, то самое время это сделать!

3. Рисовать линию по перемещению мыши
4. Рисовать круги по перемещению мыши

И опять, попытаюсь угадать, какое желание появилось на этот раз: сделать так, чтобы при нажатой клавише след оставался, а при перемещении мыши без нажатых клавиш — не оставался.
Подсказка: используйте свойство state:

def move(event):
    print(event.state)

Это только вывод на экран. Как сделать так, чтобы рисовании линии шло только при нажатой клавише мыши — вам нужно придумать самостоятельно.

5. Рисовать линию при перемещении мыши с нажатой левой клавишой.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *