Учебная страница курса биоинформатики,
год поступления 2010
Занятие 4
Помните пример с рисованием фигур из отрезков? Было бы здорово иметь возможность перезапускать этот код, чтобы строить новую картинку с другим углом. Для этого хорошо бы иметь кнопку, при нажатии на которую запускался этот код.
Функции
Для того, чтобы перестраивать картинку, нам нужно как-то выделить часть кода, которая это делает. Для этого используют функции.
Функция – это набор действий. Когда мы хотим выполнить эти действия,мы вызываем функцию. На самом деле, мы уже пользовались стандартными функциями, например,
1 math.sin(x)
Теперь будем писать свои
При вызове любой функции происходит передача аргументов, которая заключается в том, что передаваемые значения присваиваются аргументам функции.
Чтобы выполнить код, прописанный в функции, нужно в программе вызвать функцию и передать значения параметров
1 my_print(“ку-ку”)
Помимо того, что функция берет на вход аргументы, она может возвращать значение (как в случае с синусом). Напишем свой пример:
Результат выполнения функции можно присвоить в переменную
1 z = glue(y,x)
Переменные, создаваемые внутри функции, являются локальными, и они не видны снаружи. То есть они «живут» только в рамках этой функции. Аргументы функции имеют в точности те же права, что и локальные переменные.
Если мы в основной программе попытаемся print(delim) или print(x), то возникнет ошибка.
В разных функциях могут быть переменные с одинаковыми именами:
Можно вызывать одну функцию внутри другой. Функция, которая вызывает сама себя, называется рекурсией. Пример — числа Фибоначчи.
Переменные основной программы по отношению к функции являются глобальными. Внутри функции их можно читать (и для этого ничего не нужно делать), но изнутри функции их нельзя создавать и в них нельзя присваивать.
Теперь вынесем код, который рисует фигуру, в функцию (можно для краткости в качестве примера здесь рисовать в случайном месте круг случайного размера). Перед отрисовкой будем чистить холст.
1 def draw():
2 alpha = 0
3 x_start = canvas_size/2
4 y_start = 100
5
6 x1 = x_start
7 y1 = y_start
8
9 canv.delete("all")
10 betha = random.randint(50, 90)
11
12 for i in range (200):
13 size = 100
14 alpha = (alpha + betha) % 360
15 x2 = x1 + size * math.cos(math.radians(alpha))
16 y2 = y1 + size * math.sin(math.radians(alpha))
17 color = random.choice(colors)
18 canv.create_line(x1,y1,x2,y2, fill=color, width=2)
19 x1 = x2
20 y1 = y2
21
22 if (int (x2-x_start) == 0)&(int (y2-y_start) == 0):
23 break
Размер холста является глобальной переменной для функции draw() и его нельзя поменять внутри функции.
События
Нужный нам кусок кода в функцию мы вынесли. Теперь пора создавать кнопку, при нажатии на которую мы хотим вызывать нашу функцию.
Можно еще поиграть с мышкой, том более что это нам пригодится для нашего червячка. Для этого придется разобраться, что такое событие. Событие это нечто, что происходит. Например, мы подвинули курсор мыши, произошло событие Motion. Можно заставить программу как-то отреагировать на событие, осуществить в ответ какие-то действия. Например, нарисуем квадрат-липучку, который приклеился к курсору мыши. При нажатии левой кнопки мыши он отлетает от курсора на небольшое расстояние в произвольном направлении
1 import Tkinter
2 import random
3 import math
4
5 root = Tkinter.Tk()
6 c = Tkinter.Canvas(root,width="300",height="300",background = 'gray')
7 c.pack(fill="both", expand="yes")
8 side = 20
9 radius = 50
10
11 c.create_rectangle(0, 0, side, side,fill='blue')
12
13 def mouseMove(event):
14 c.delete("all") #очистить холст
15 x = c.canvasx(event.x)
16 y = c.canvasy(event.y)
17 c.create_rectangle(x, y, x + side, y + side, fill='blue')
18
19 def mousePressed(event):
20 c.delete("all") #очистить холст
21 x = c.canvasx(event.x) #получаем x координату точки, в которой кликнули
22 y = c.canvasy(event.y) #получаем y координату точки, в которой кликнули
23 alpha = random.randint(0, 360)
24 x = x + radius * math.cos(math.radians(alpha))
25 y = y + radius * math.sin(math.radians(alpha))
26 c.create_rectangle(x, y, x + side, y + side, fill='blue')
27
28 c.bind('<Motion>',mouseMove) #связать событие движения мыши на холсте с нашей функцией #mouseMove
29 c.bind('<ButtonPress>',mousePressed) #связать событие нажатия мыши на холсте с нашей функцией #mousePressed
30 root.mainloop()
Объект event автоматически создается системой при возникновении события, он хранит разную информацию, связанную с событием. В данном случае мы получили координаты курсора мыши в месте клика.
After
Пример с мячиком из первого занятия. Мячик падает до действием силы тяжести. Для того, чтобы картинка превратилась в мультик, ее надо перерисовывать через некоторые промежутки времени. Мы вычисляем новые координаты мячика в следующий момент, а затем трем мячик и рисуем его на новом месте. Для этого нужно как-то хранить текущие координаты и скорости мяча. Но глобальные переменные можно только читать и нельзя менять. Для хранения текущих координат и скоростей мяча мы применяем «военную» хитрость в виде списка, который можно менять, несмотря на то, что он глобальный.
1 from Tkinter import Tk, Canvas
2 import random
3 import math
4
5 width = 500
6 height = 500
7 background = "black"
8 delay = 10
9
10 mass = 10.0
11 gravity = 1.0
12 delta_phi = 3
13 ball_radius = 10
14 ball_color = "yellow"
15
16 state = [250, 0, 1e-10, 0]
17 ball = [None]
18
19 def step():
20 x, y, vx, vy = state
21 vy += gravity / mass
22 x += vx
23 y += vy
24
25 x = (x + width) % width
26
27 if y + ball_radius >= 500:
28 y = 500 - ball_radius
29 phi = math.atan2(vy, vx)
30 phi += (random.random() - 0.5) * delta_phi
31 v = math.hypot(vy, vx)
32 vx = v * math.cos(phi)
33 vy = v * math.sin(phi)
34 vy = - abs(vy)
35
36 state[:] = x, y, vx, vy
37
38 if ball[0]:
39 canvas.delete(ball[0])
40 ball[0] = canvas.create_oval(
41 x - ball_radius, y - ball_radius, x + ball_radius, y + ball_radius,
42 fill=ball_color, outline=ball_color
43 )
44
45 def on_timer():
46 step()
47 root.after(delay, on_timer)
48
49 root = Tk()
50 canvas = Canvas(root, width=width, height=height, background=background)
51 canvas.pack()
52 on_timer()
53 root.mainloop()
функция on_timer вызывает себя сама, такая функция еще называется рекурсивной. Таким образом, мы получаем что-то вроде бесконечного цикла.