На примере программы пинг-понг по стенкам демонстрируем работу функции after() из библиотеки Pyton tkinter. Функция after() (точнее, метод визуальных объектов) осуществляет задержку выполнения программы или отложенный вызов функции.
Первый параметр функции after() - время задержки в миллисекундах, а второй не обязательный параметр - имя вызываемой после задержки функции.
from tkinter import * # Импорт функций из tkinter
fps = 9 # Время обновления в мСек
rBall=25 # Радиус шарика
xSize = 800; ySize = 400 # Размер canvas - rBall
xv = 1.4; yv = 2.7 # Скорость по х и у
def moveBall(): # Функция перемещения
global xv, yv # Скорости глобальные
xyCoords = cnv.coords(1) # Текущая координата [x, y]
if xyCoords[0] < rBall or xyCoords[0] > xSize: # Предел по x
xv *= -1 # Инверсия скорости по x
if xyCoords[1] < rBall or xyCoords[1] > ySize: # Предел по y
yv *= -1 # Инверсия скорости по x
cnv.move(1, xv, yv) # Перемещение на шаг
cnv.after(fps, moveBall) # Рекурсивный вызов с задержкой
cnv = Canvas(width=xSize+rBall, height=ySize+rBall) # Создание холста
cnv.pack() # Вывод холста на экран
img = PhotoImage(file='silver.png') # Создание объекта PhotoImage
cnv.create_image(50, 30, image=img, anchor=CENTER) # Размещение PhotoImage на холсте
moveBall() # Запуск движения
mainloop() # Главный цикл программы
Программа 1. Пинг-понг по стенкам.
Рис. 1. Пинг-понг по стенкам.
ООП
Программа 1. короткая и не сложная, но попробуйте с помощью функций создать запустить в полёт с различными параметрами десятки шариков. Задача сильно усложнится.
Создавать шарики на экране и управлять их полётом будет удобнее как абстрактными объектами.
Абстрагирование означает выделение значимой информации и исключение из рассмотрения незначимой. В объектно-ориентированном программировании рассматривают лишь абстракцию данных, нередко называя её просто абстракцией и подразумевая набор наиболее значимых характеристик объекта, доступных остальной программе.
Объектно-ориентированное программирование (ООП) — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определённого класса, а классы образуют иерархию наследования.
Так же, как и абстракция, с ООП неразрывно связано понятие инкапсуляция. Инкапсуляция — свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе.
Класс — универсальный, комплексный тип данных, состоящий из тематически единого набора полей (переменных более простых типов) и методов (функций для работы с этими полями), то есть он является моделью информационной сущности с внутренним и внешним интерфейсами созданными для управления содержимым полей.
Переменная-объект, относящаяся к заданному классом типу, называется экземпляром класса.
Объект — сущность в адресном пространстве памяти вычислительной системы, появляющаяся при создании экземпляра класса.
class car():
def __init__(self, color=2):
self.palette=['red','green','black','blue']
self.color = color
def set(self, color):
self.color = color
def get(self):
return self.palette[self.color]
auto = car()
print(auto.get())
auto.set(1)
print(auto.get())
Программа 2.
Рис. 2. Изображения шариков в png формате.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# brownian-motion.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# brownian-motion.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# brownian-motion.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from tkinter import *
from random import *
file = ['red.png', 'yellow.png', 'gold.png', 'green.png',
'emerald.png', 'cyan.png', 'blue.png', 'pink.png',
'azure.png', 'bronze.png', 'purple.png',
'scarlet.png', 'steel.png', 'silver.png']
rBall=25 # Радиус шарика
xSize = 800; ySize = 400 # Размер canvas-rBall
class cnvBall:
global rball, xSize, ySize
def moveBall(self):
xyCoords = self.cnv.coords(self.obj)
if xyCoords[0] < rBall or xyCoords[0] > xSize:
self.xv *= -1
if xyCoords[1] < rBall or xyCoords[1] > ySize:
self.yv *= -1
self.cnv.move(self.obj, self.xv, self.yv)
self.cnv.after(self.tic, self.moveBall)
def __init__(self, cnv, img, x, y):
self.cnv = cnv
self.obj = cnv.create_image(x, y, image=img, anchor=CENTER)
self.xv = 1; self.yv = 1
self.tic = 10
self.moveBall()
cnv = Canvas(width=xSize+rBall, height=ySize+rBall)
cnv.pack()
img = []; ball = []
for i in file: img.append(PhotoImage(file=i))
for j in range(30):
for i in img: ball.append(cnvBall(cnv, i, choice(range(rBall, xSize)), choice(range(rBall, ySize))))
for i in range(420):
ball[i].xv = random()*7-3.5
ball[i].yv = random()*11-5.5
ball[i].tic = choice(range(15, 30))
mainloop()
Программа 2. Броуновское движение.
В программе 2 мы создали класс cnvBall. Конструктор этого класса создаёт объект PhotoImage на холсте (Canvas), используя в качестве параметров объект класса Canvas, объект класса PhotoImage и координаты размещения PhotoImage на Canvas. Конструктор класса cnvBall, так же, создаёт свойства объекта класса cnvBall: xv, yv и tic. Создав объект и свойства, конструктор запускает метод moveBall(). MoveBall(), используя свойства xv и yv, как приращения координат, перемещает объект self.obj на холсте. Кроме того, в методе moveBall() вычисляются моменты столкновения перемещаемого объекта с границами холста и меняется знак соответствующих приращений координат xv или yv для изменения направления движения объекта.
В последней строке метода mooveBall() происходит рекурсивный вызов функции moveBall() с задержкой, созданной методом after(). Время задержки определяет свойство self.tic, передаваемое в функцию after() в качестве параметра.
Рис. 3. Броуновское движение.