====== Картинки и анимация ======
На предыдущих занятиях мы разобрали библиотеку, которая позволяла работать с графиками. Однако, основная ее функциональность сосредоточена на разного вида диаграммах. Сегодня разберемся с модулем, который нам дает возможность рисовать как заблагорассудится. Для Питона есть множество библиотек для работы с графикой (как обычно), мы рассмотрим сегодня самую простую из них: ''graphics.py''.
Начнем с простого примера. Если он вдруг не заработает сразу, то выполните у себя в терминале
pip3 install --user graphics.py
from graphics import *
import time
# наша рисующая функция
def gr():
winWidth = 800
winHeight = 600
# Создадим окно с заголовком "Шарик" и размером 800 на 600 пикселей
win = GraphWin("Шарик", winWidth, winHeight)
# В координаты 50, 50 поместим окружность радиусом 10
c = Circle(Point(50, 50), 10)
# В координаты 50, 50 напишем текст
e = Text(Point(200, 100),
"Не то, чтобы совсем не попал, но только не попал в шарик!")
# нарисуем шарик в окне win
c.draw(win)
# нарисуем текст в окне win
e.draw(win)
# запустим цикл, который будет ждать нажатия мышью
while (True):
# подождем, пока кто-нибудь не кликнет мышкой в окне
clickPoint = win.getMouse()
# напечатаем на экран координаты точки клика
print(clickPoint)
# если лопнули шарик
if c.getP1().getX() < clickPoint.getX() < c.getP2().getX() and c.getP1().getY() < clickPoint.getY() < c.getP2().getY():
# то удалим шарик с экрана
c.undraw()
# изменим текст
e.setText("Пух!")
# подождем 2 секунды
time.sleep(2)
# и прервем выполнение цикла
break
# и закроем графическое окно
win.close()
# запустим функцию
gr()
====== Функции GraphWin ======
GraphWin это графическое окно, которое умеет следующее:
* ''GraphWin(title, width, height)'' - создает новое графическое окно на экране. Если не указать параметров, то будет создано окно размером 200х200 пикселей. ''win = GraphWin("Тут картинка", 640, 480)''
* ''plot(x, y, color)'' - рисует в окне пиксель по координатам (x, y) цветом color. Например: ''win.plot(x, y, "yellow")''
* ''setBackground(color)'' - заливает фон окна выбранным цветом. Например ''win.setBackground("green")''
* close() - закрывает окно. Например: ''win.close()''
* ''getMouse()'' - останавливает выполнение программы и ждет, пока пользователь не кликнет мышью внутри графического окна. После клика возвращает координаты точки клика в переменную типа Point. Например: 'clickPoint = win.getMouse()'
* ''checkMouse()'' - ведет себя аналогично getMouse, но не останавливает выполнение программы. При вызове, возвращает координаты последнего клика или None если с предыдущего вызова checkMouse или getMouse клика не было.
* ''getKey()'' - приостанавливает выполнение программы и ожидает пока нажмут кнопку на клавиатуре. Возвращает строчку, в которой хранится нажатая клавиша. Например: keyString = win.getKey()
* ''checkKey()''- аналогично checkMouse, но для клавиатуры. В отличие от checkMouse, если клавиша нажата не была, то возвращает пустую строку.
* ''getWidth()'' - возвращает значение ширины графического окна в пикселях
* ''getHeight()'' - возвращает значение высоты графического окна в пикселях
====== Графические элементы ======
''graphics.py'' хранит в себе реализацию стандартных графических примитивов (точка, линия, окружность и т.д.) в виде типов данных Point, Line, Circle, Oval, Rectangle, Polygon, Text. Для каждого типа данных можно установить следующие свойства:
* ''setFill(color)'' - цвет заливки внутренней части. ''circ.setFill("red")''
* ''setOutline(color)'' - цвет контура. ''circ.setOutline("blue")''
* ''setWidth(pixels)'' - ширина контура в пикселях. ''circ.setWidth(2)''
* ''draw(graphWin)'' - рисует объект в выбранном графическом окне. ''circ.draw(win)'' ВАЖНО: для всех типов данных в этом разделе, чтобы увидеть их на экране нужно вызвать эту функцию для каждой необходимой переменной.
* ''undraw(graphWin)'' - скрывает объект с выбранного графического окна. ''circ.undraw(win)''
* ''move(dx, dy)'' - перемещает объект на величину dx по x и dy по y. ''circ.move(10, 15.5)''
* ''clone()'' - возвращает копию объекта. ''copy = circ.clone()''
===== Точка =====
Самый простой тип данных. Хранит в себе просто две координаты на экране.
* ''Point(x, y)'' - создает точку с координатами x и y. Внимание, точка просто создается в оперативной памяти, она НЕ рисуется на экране. Например: 'aPoint = Point(3.5, 8)' Чтобы отобразить эту точку, нужно вызвать функцию draw: ''aPoint.draw(win)''
* ''getX()'' - возвращает координату x. ''x = aPoint.getX()''
* ''getY()'' - возвращает координату y. ''y = aPoint.getY()''
===== Линия =====
* ''Line(point1, point2)'' - cоздает переменную типа Line. В качестве аргументов передаются 2 переменные типа Point, которые задают начало и конец линии.
* ''setArrow(endString)'' - добавляет к концам линии символ стрелки. Стрелка может рисоваться на каждом из концов независимо или сразу на обоих. Например: ''aLine .setArrow("both")''. Чтобы указать где рисовать стрелку используются такие значения переменной endSting:
* ''first'' - стрелка в начале
* ''last'' - стрелка в конце
* ''both'' - стрелка на обоих концах
* ''getCenter()'' - возвращает переменную типа Point, где хранятся координаты центра линии.
* ''getP1(), getP2()'' - возвращает координаты начала и конца линии.
===== Окружность =====
* ''Circle(centerPoint, radius)'' - создает окружность с центром в cenerPoint и радиусом radius в пикселях
* ''getCenter()'' - возвращает координаты центра окружности
* ''getRadius()'' - возвращает радиус окружности
* ''getP1(), getP2()'' - возвращает соответственно, координаты левого нижнего и правого верхнего углов квадрата, в который может быть вписана окружность.
===== Прямоугольник =====
* ''Rectangle(point1, point2)'' - создает прямоугольник по координатам левого нижнего и правого верхнего углов
* ''getCenter()'' - возвращает координаты центра прямоугольника
* ''getP1(), getP2()'' - возвращает координаты левого нижнего и правого верхнего углов прямоугольника
===== Овал =====
* ''Oval(point1, point2)'' - создает овал, который вписан в прямоугольник с заданными левым нижним и правым верхним углами.
* ''getCenter()'' - возвращает координаты центра овала.
* ''getP1(), getP2()'' - возвращает соответственно, координаты левого нижнего и правого верхнего углов прямоугольника, в который вписан овал.
===== Сегмент =====
К сожалению, библиотека не содержит в себе встроенной функции для отрисовки сегмента окружности или овала. Однако, это питон и никто не мешает нам дописать необходимую функциональность.
Добавим в начало программы следующий код:
class Arc(Oval):
def __init__(self, p1, p2,start, extent):
self.extent = extent
self.start = start
super().__init__(p1, p2)
def __repr__(self):
return "Arc({}, {}, {})".format(str(self.p1), str(self.p2), self.extent)
def clone(self):
other = Arc(self.p1, self.p2, self.start, self.extent)
other.config = self.config.copy()
return other
def _draw(self, canvas, options):
p1 = self.p1
p2 = self.p2
x1, y1 = canvas.toScreen(p1.x, p1.y)
x2, y2 = canvas.toScreen(p2.x, p2.y)
options['style'] = tk.PIESLICE
options['extent'] = self.extent
options['start'] = self.start
return canvas.create_arc(x1, y1, x2, y2, options)
Теперь в нашей программе появилась возможность рисовать сегменты окружности, например:
arc = Arc(Point(50, 50), Point(100, 100), 45, 270)
arc.setFill("yellow")
arc.draw(win)
* Arc(point1, point2, start_angle, segemnt_angle) - создает сегмент овала, который вписан в прямоугольник с заданными левым нижним и правым верхним углами. start_angle - начальный угол с которого начинает рисоваться сегмент, segment_angle - угол закрашенного участка.
* getCenter() - возвращает координаты центра овала.
* getP1(), getP2() - возвращает соответственно, координаты левого нижнего и правого верхнего углов прямоугольника, в который вписан овал.
===== Многоугольник =====
* ''Polygon(point1, point2, point3, ...)'' - создает замкнутый многоугольник по заданному набору вершин. В качестве аргумента может быть и список. Например: ''aPolygon = Polygon(Point(1,2), Point(3,4), Point(5,6))'' или ''aPolygon = Polygon([Point(1,2), Point(3,4), Point(5,6)])''
* ''getPoints()'' - возвращает список вершин многоугольника
===== Текст =====
* ''Text(anchorPoint, textString)'' - создает текстовый блок, отцентрированый по координатам точки anchorPoint.
* ''setText(string)'' - изменяет строку, помещенную в текстовый блок
* ''getText()'' - возвращает строку из текстового блока
* ''getAnchor()'' - возвращает координаты точки центра текста
* ''setFace(family)'' - изменяет вид шрифта текстового блока. Возможные значения параметра: "helvetica", "courier", "times roman" и "arial"
* ''setSize(point)'' - задает размер шрифта в пунктах
* ''setStyle(style)'' - задает стиль шрифта. Возможные значения параметра: "normal", "bold", "italic", "bold italic".
* ''setTextColor(color)'' - Задает цвет текста
===== Обновление экрана =====
По умолчанию, библиотека graphics.py обновляет экран при отрисовке каждого элемента. Обновление экрана операция дорогая по времени, поэтому иногда (например, когда на экране мнго объектов) нужно эту функцию автообновления отключить.
Для этого:
1. При инициализации графического окна нужно добавить параметр ''autoflush=False''.
2. В цикле отрисовки нужно добавить явный вызов функции обновления окна, указав в качестве аргумента частоту кадров, с которой следует обновлять окно
win = GraphWin("Update Example", 320, 200, autoflush=False)
for i in range(1000):
# <Все что рисуется на экране>
update(30)
===== Работа с цветами =====
В этой библиотеке цвет можно описать двумя способами: текстовым значением и прямым указанием цветовых компонент. В первом случае, цвет задается своим названием, например "red". Помимо этого, есть определенный выбор оттенков, например "red1", "red2","red3", "red4". По мере увеличения номера, оттенок становится более темным. На картинке перечислены все возможные значения цветов:
{{ :python:colorschart3.jpg |}}
Во втором случае, цвета задаются с помощью функции color_rgb(r, g, b). Ее аргументами являются числовые значения цветовых компонент: красной, зеленой и синей. Значения каждой от 0 до 255. Например aCircle.setFill(color rgb(130, 0, 130)) задаст цвет заливки окружности чуть светлее, чем darkmagenta из предыдущей таблицы.
===== Задачи =====
==== Задание 18 ====
Написать программу, которая рисует на экране точки, расположенные на окружности. Координаты точек требуется вычислять в полярной системе координат.
https://nsunc.com/moodle/mod/assign/view.php?id=656
==== Задание 19 ====
Модифицировать предыдущую программу так, чтобы точки располагались по спирали
https://nsunc.com/moodle/mod/assign/view.php?id=657
==== Задание 20 ====
Модифицировать прогрмму из задания 18 так, чтобы:
- Вместо точек рисовались окружности
- Когда рисуется следующая окружность, предыдущая должна удаляться
https://nsunc.com/moodle/mod/assign/view.php?id=658
==== Задание 21 (планеты со спутниками) ====
Добавить еще одну точку для вращения, которая будет двигаться вместе с окружностью. Запустить вокруг нее еще одну окружность. В центре разместить Солнце
https://nsunc.com/moodle/mod/assign/view.php?id=659
==== Задание 22 ====
Написать программу, в которой N точек двигались бы по одной окружности
https://nsunc.com/moodle/mod/assign/view.php?id=660
==== Задание 23 ====
Модифицировать программу так, чтобы точки были соединены линиями
https://nsunc.com/moodle/mod/assign/view.php?id=661
==== Задание 24 ====
Модифицировать предыдущую программу так, чтобы вышла иллюзия вращающейся пирамидки
https://nsunc.com/moodle/mod/assign/view.php?id=662