= Создание графических интерфейсов в питоне =

[[/Record|Конспект]]

== План рассказа ==
 * орг.: пора определяться с зачётным заданием
 * орг.: следующий раз будет 20-го числа :(
 * передача параметров по имени
 * откуда взялся Tk
 * основные понятия Tk: виджет, настройки виджета, контейнер, упаковщик, события
 * перерыв
 * как делать программу с canvas
 * как работать с временем / перерисовками
 * преобразования пространства (масштабирование, смещение, поворот)

== Контрольная работа ==
 1. В переменных {{{x}}} и {{{y}}} лежат некоторые значения. Выполните такой набор действий, чтобы в {{{x}}} лежало то, что изначально было в {{{y}}}, а в {{{y}}} лежало то, что изначально было в {{{x}}}. Т.е. поменяйте эти две переменные значениями. Пример начала и конца диалога с питоном (заполните середину):
 {{{#!python
 >>> x = 99
 >>> y = "hello"



 >>> x
 'hello'
 >>> y
 99
 }}}
 2. Напишите функцию {{{fib(n)}}}, которая возвращает число ФИбоначчи с номером {{{n}}}. Числа Фибоначчи определяются следующим образом: ''f,,1,, = f,,2,, = 1, f,,n+2,, = f,,n,, + f,,n+1,,''. Первые числа Фибоначчи выглядят так: 1, 1, 2, 3, 5, 8, 13, ...

== Пример графической программы ==
{{{#!python
import Tkinter
import math

class Fun(object):
    def __init__(self, canvas):
        self.canvas = canvas
        self.phi = 0
        self.after_id = 0
    def begin(self):
        self.phi += 0.01
        self.canvas.delete("all")
        x, y = math.cos(self.phi) * 100 + 150, math.sin(self.phi) * 100 + 150
        x0, y0 = x - 10, y - 10
        x1, y1 = x + 10, y + 10
        self.canvas.create_oval(x0, y0, x1, y1, fill="red")
        self.after_id = canvas.after(10, self.begin)
    def end(self):
        self.canvas.after_cancel(self.after_id)

root = Tkinter.Tk()
root.title("Merry-go-round")

canvas = Tkinter.Canvas(root, background="black")
canvas.pack(fill="both", expand="yes")

fun = Fun(canvas)

panel = Tkinter.Frame(root)
panel.pack(fill="x")
go = Tkinter.Button(panel, text="Go", command=fun.begin)
go.pack(side="left", fill="both", expand="yes")
stop = Tkinter.Button(panel, text="Stop", command=fun.end)
stop.pack(side="left", fill="both", expand="yes")

root.mainloop()
}}}

{{{#!wiki note
Предупреждение: в теле примера для отступов используются табуляции, в то время, как в Idle по умолчанию используются пробелы. Смесь этих двух типов отступов чревата большим количеством головной боли. Idle умеет конвертировать отступы между табуляциями и пробелами. Выделите кусок текста и см. меню Format > Untabify. (Заодно поглядите, какие ещё полезные вещи есть в меню Format).
}}}

== Документация ==
 * [[http://www.tutorialspoint.com/python/python_gui_programming.htm|Неофициальный туториал]]
 * встроенные {{{help()}}}'ы
 * [[http://docs.python.org/library/tkinter.html|Официальная справочная документация]]
 * [[http://www.pythonware.com/library/tkinter/introduction/index.htm|Почти официальный туториал по Tkinter]]
 * [[Href:~dendik/data/python/2010-04-06/Tkinter.ppt|Презентация Леси Денисенко с прошлого года]]
 * Гугл?

== Упражнения ==
Упражнения выполнять не обязательно, но если вы не представляете себе, как подступиться к задачам, то лучше сначала для тренировки повыполнять тупые упражнения, которые похожи на то, что творилось на доске.
 1. Разберитесь, как работает пример программы выше.
 1. Напишите в файле {{{excercise_hello.py}}} программу, которая рисует графическое окошко с сообщением "hello, world", и ничего более не делает.
 2. Напишите в файле {{{excercise_figures.py}}} программу, которая рисует окно с полотном (canvas), на котором нарисованы квадрат, круг и треугольник разных цветов.
 3. Напишите в файле {{{excercise_sine.py}}} программу, которая рисует (крупно и понятно) график синусоиды.
 4. Напишите в файле {{{excercise_wave.py}}} программу, которая рисует колеблющуюся волну: т.е. график синусоиды с постоянно изменяющейся фазой. (Суть задания в том, чтобы пользователь видел движущуюся картинку).

== Задание ==
Задачи, помеченные (*) выполнять не обязательно. Пункт, помеченный (**) предназначен для крепких духом, желающих сделать красивую картинку своими руками.

 1. Приделайте к модели солнечной системы графический интерфейс. Первая графическая версия программы должна создавать окно, занятое целиком одним полотном (canvas), на котором в осмысленном масштабе рисуется солнечная система. Программа обновляет модель бесконечно, покуда пользователь не закроет окно.
  * чтобы ситуация на экране стала интересной, нужно в любом случае хотя бы три сравнимо массивных тела; даже если вы не сделаете пункт 2, вам никто не мешает руками в файл вбить начальные данные какой-нибудь кометы, чтобы поглядеть на красивую картинку
 2. (*) Добавьте к интерфейсу способ добавлять планеты.
  * добавьте массивную комету, пролетающую между Землёй и Солнцем, и поглядите, как она меняет поведение системы
 3. (*) Добавьте к интерфейсу способ менять начало координат, направление (**) и масштаб отображения (начало координат можно задавать инерциальным в какой-нибудь точке или связывать с какой-нибудь из планет; направление можно делать фиксированным в какую-нибудь сторону или связывать с азимутом с одной планеты на другую)
  * добавьте планету, движущуюся по той же орбите, что и Земля, образующую с Солнцем правильный треугольник
   * перейдите в систему отсчёта, связанную с Землёй и сориентированную по оси Земля-Солнце и поглядите на поведение системы

== Пошаговая инструкция к заданию 1 для негордых ==
 1. Добавьте в класс {{{Model}}} поля {{{canvas}}}, {{{scale}}}, {{{offset}}} (и соответствующие аргументы конструктору)
 2. Добавьте в класс {{{Model}}} метод {{{draw}}}, который сначала очищает {{{canvas}}}, затем рисует на нём кругами планеты
  * лучше, чтобы планеты изображались разными цветами
  * для кругов лучше задавать и параметр fill, и параметр outline
  * при рисовании используются параметры {{{scale}}} (на это число домножаются координаты и радиус планет) и {{{offset}}} (этот вектор прибавляется к координатам планет
 3. Добавьте в класс {{{Model}}} метод {{{run}}}, который перерисовывает картинку на экране, делает шаг эмуляции и ставит таймер на перезапуск самого себя через 10мс.<<FootNote(По-хорошему, тут бы должен был бы быть ещё один параметр timescale, который устанавливал бы зависимость между delta_t и интервалами, через которые мы перерисовываем картинку. Но как всегда.)>>
 4. Добавьте в конец модуля astro код для создания окна Tk, создания на нём полотна, создания модели из имеющихся планет, полотна, и осмысленных значений для {{{scale}}} и {{{offset}}} (подумайте, какие значения были бы осмысленными), первичного запуска метода run в модели и запуска основного цикла Tk.

## vim: set ts=4 sts=4 et: