Kodomo

Пользователь

Учебная страница курса биоинформатики,
год поступления 2010

Занятие 4

Помните пример с рисованием фигур из отрезков? Было бы здорово иметь возможность перезапускать этот код, чтобы строить новую картинку с другим углом. Для этого хорошо бы иметь кнопку, при нажатии на которую запускался этот код.

Функции

Для того, чтобы перестраивать картинку, нам нужно как-то выделить часть кода, которая это делает. Для этого используют функции.

Функция – это набор действий. Когда мы хотим выполнить эти действия,мы вызываем функцию. На самом деле, мы уже пользовались стандартными функциями, например,

   1 math.sin(x)

Теперь будем писать свои

   1 def my_print():
   2     printhello

При вызове любой функции происходит передача аргументов, которая заключается в том, что передаваемые значения присваиваются аргументам функции.

   1 def my_print(x):
   2     print x

Чтобы выполнить код, прописанный в функции, нужно в программе вызвать функцию и передать значения параметров

   1 my_print(“ку-ку”)

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

   1 def glue(x, y):
   2     delim = '_'
   3     return str(x) + delim + str(y)

Результат выполнения функции можно присвоить в переменную

   1 z = glue(y,x)

Переменные, создаваемые внутри функции, являются локальными, и они не видны снаружи. То есть они «живут» только в рамках этой функции. Аргументы функции имеют в точности те же права, что и локальные переменные.

   1 word1=”first
   2 word2=”second
   3 def glue(x, y):
   4             delim = '_'
   5             return str(x) + delim + str(y)
   6  z = glue(word1,word2)
   7  z = glue(z, z)
   8 print z

Если мы в основной программе попытаемся print(delim) или print(x), то возникнет ошибка.

В разных функциях могут быть переменные с одинаковыми именами:

   1 def mult(x,y):
   2             return x*y
   3 def plus(x,y):
   4             return x+y
   5 a=2
   6 b=3
   7 c=4
   8 print mult(a,b)
   9 print plus(c,b)

Можно вызывать одну функцию внутри другой. Функция, которая вызывает сама себя, называется рекурсией. Пример — числа Фибоначчи.

   1 def fibonacci(n):
   2             if n==0 or n==1:
   3                         return 1
   4             return fibonacci(n-1)+fibonacci(n-2)
   5 print fibonacci(2)
   6 print fibonacci(5)

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

Теперь вынесем код, который рисует фигуру, в функцию (можно для краткости в качестве примера здесь рисовать в случайном месте круг случайного размера). Перед отрисовкой будем чистить холст.

   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() и его нельзя поменять внутри функции.

События

Нужный нам кусок кода в функцию мы вынесли. Теперь пора создавать кнопку, при нажатии на которую мы хотим вызывать нашу функцию.

   1 button = Tkinter.Button(root, text='draw', width=30, command=draw)
   2 button.pack()

Можно еще поиграть с мышкой, том более что это нам пригодится для нашего червячка. Для этого придется разобраться, что такое событие. Событие это нечто, что происходит. Например, мы подвинули курсор мыши, произошло событие 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 вызывает себя сама, такая функция еще называется рекурсивной. Таким образом, мы получаем что-то вроде бесконечного цикла.