Объектно-ориентированное программирование (ООП) - это технология в которой объекты создаются с помощью классов. Класс описывает свойства объекта или объектов, создаваемых на его основе. Объект - это экземпляр класса.
Классы создаются с помощью ключевого слова class. Например:
class animal:
pass
class flora(object):
pass
class dog(animal):
pass
Классы animal и flora созданы на основе базового класса object, класс dog создан на основе класса animal. Класс dog наследует свойства класса animal, и является его наследником. Класс animal является суперклассом по отношению к классу dog.
from tkinter import * # графическая библиотека
class Btn(Button):
pass
Btn(width=3, height=2, font=('times', 24, 'bold'),
text="Yes").pack(expand=YES, fill=BOTH, side=LEFT)
mainloop() # главный цикл программы
Лист. 1. Класс Btn наследник класса Button из библиотеки tkinter.
Рис. 1. Кнопка типа (класса) Btn создана конструктором суперкласса Button.
Кнопка на рисунке 1 создана программой листинг 1. Создание кнопки как объекта (экземпляра класса) в программе листинг 1 произошло когда мы использовали имя класса Btn как функцию, с круглыми скобками Btn(). Параметры, перечисленные в круглых скобках при вызове конструктора класса Btn описаны в классе Button в библиотеке tkinter. Здесь мы их не рассматриваем.
К объекту класса Btn в программе листинг 1 применяется (вызывается) метод (встроенная функция) pack(). Функция pack(), так же, как и упомянутые выше параметры класса Button, является свойством класса Button. Методы объектов вызываются с использованием составного имени через точку: Имя_объекта.имя_метода(параметры). Имя объекта (точнее ссылка на объект) класса Btn в программе листинг 1 возвращается в то место где был вызван конструктор Btn() с параметрами.
На самом деле, пока в программе листинг 1 в классе Btn не объявлен свой конструктор объектов - функция __init__, при создании экземпляров класса Btn используется метод __init__() суперкласса Button.
Создавая пользовательский класс Btn, мы планируем снабдить его дополнительными свойствами. Нет большого смысла в новом классе, который полностью повторяет свойства суперкласса. В программу листинг 2 в класс Btn мы добавим свой конструктор __init__(). Заметим, что у функции __init__() должен быть, как минимум, один обязательный параметр self. И любые другие методы класса, так же как и метод __init__(), должны иметь в качестве первого передаваемого параметра параметр self. Параметр self является ссылкой на создаваемый объект (экземпляр класса). Self программистом внутри класса не определяется, а только используется. При вызове методов объекта параметр self не указывают.
from tkinter import * # графическая библиотека
class Btn(Button):
def __init__(self):
pass
Btn(width=3, height=2, font=('times', 24, 'bold'),
text="Yes").pack(expand=YES, fill=BOTH, side=LEFT)
mainloop() # главный цикл программы
Лист. 2. В классе Btn объявлен метод __init__().
Btn(width=3, height=2, font=('times', 24, 'bold'),
TypeError: Btn.__init__() got an unexpected keyword argument 'width'
Лист. 3. Ошибка, вызванная программой листинг 2.
После того как мы добавили в нашу программу (см. лист. 2) метод __init__(), наша программа стала вызывать ошибку (см. лист. 3). Проблема заключается в том, что все параметры перечисленные при вызове конструктора Btn() предназначены для конструктора класса Button. Но в программе листинг 2 конструктор __init__ суперкласса Button теперь не вызывается. Вызвать конструктор суперкласса можно командой super().__init__().
from tkinter import * # графическая библиотека
class Btn(Button):
def __init__(self):
super().__init__()
Btn(width=3, height=2, font=('times', 24, 'bold'),
text="Yes").pack(expand=YES, fill=BOTH, side=LEFT)
mainloop() # главный цикл программы
Лист. 4. В конструктор объектов __init__ класса Btn добавлен вызов конструктора класса Button (суперкласса).
Btn(width=3, height=2, font=('times', 24, 'bold'),
TypeError: Btn.__init__() got an unexpected keyword argument 'width'
Лист. 5. Ошибка, вызванная программой листинг 4.
В программу листинг 4, в конструктор __init__ класса Btn мы добавили вызов конструктора суперкласса Button командой super().__init__(), но это не устранило ошибку в программе, кроме того, ошибка не изменилась. Проблема заключается в том, что все параметры перечисленные при вызове конструктора Btn() предназначены для конструктора класса Button. Но в программе листинг 4 все параметры передаются в конструктор __init__ класса Btn.
from tkinter import * # графическая библиотека
class Btn(Button):
def __init__(self):
super().__init__(width=3, height=2, text="Yes",
font=('times', 24, 'bold'))
Btn().pack(expand=YES, fill=BOTH, side=LEFT)
mainloop() # главный цикл программы
Лист. 6. В конструкторе объектов __init__ класса Btn в конструктор класса Button добавлены параметры, а из функции Btn() они удалены.
Рис. 2. Кнопка, созданная программой листинг 6.
Программа листинг 6 теперь работает без ошибок.
from tkinter import * # графическая библиотека
class Btn(Button):
def __init__(self):
super().__init__(width=3, height=2, text="Yes",
font=('times', 24, 'bold'))
self.pack(expand=YES, fill=BOTH, side=LEFT)
Btn()
mainloop() # главный цикл программы
Лист. 7. Метод pack() перенесли в конструктор класса Btn.
Рис. 3. Результат работы программы листинг 7.
В программе листинг 7 появилось неудобство в создании кнопок, объектов типа Btn. Теперь, в пользовательской программе, при вызове конструктора Btn() нет возможности передать аргументы для конструктора Button, что заметно ограничивает функциональность нового класса Btn в сравнении с базовым для него классом Button. В Python существует возможность передачи в функцию как позиционных аргументов, так и необязательных предопределённых и аргументов с ключом (keyword-only). Для этого используют технику распаковки кортежей (списков, множеств) и словарей с помощью одной и двух звёздочек. Важно, позиционные аргументы указывают до именованных.
from tkinter import * # графическая библиотека
class Btn(Button):
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards)
self.pack(expand=YES, fill=BOTH, side=LEFT)
Btn(width=3, height=2, text="Yes", font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 8. Пример использования параметров *args **kwargs для передачи аргументов в функцию.
В программе листинг 8 *args позволяет передать в параметр args позиционные аргументы, представляемые в виде кортежа, а **kwargs передаёт в kwargs именованные аргументы, представленные в виде словаря.
Рис. 4. Результат работы программы листинг 8.
Игровое поле
Напишем на Python с графической библиотекой tkinter программу (заготовку) шаблон для логических игр c прямоугольным полем в клетку. В качестве клеток на поле будем использовать кнопки.
Перечислим примеры логических игр на поле в клетку:
- Шашки,
- Шахматы,
- Го,
- Уголки,
- Крестики нолики,
- Линии (Lines98),
- Пазлы - головоломки:
- Пятнашки,
- Что ест уж,
- Чайный сервиз,
- Flip-Flop,
- Memory,
- Сапёр,
- Пег,
- Игры с цифрами:
- 2048
- Судоку
- Number Match
- Трубопровод...
Для создания компьютерных игр в клетку, где в качестве клеток будут использоваться кнопки напишем программу на языке программирования Python с использованием графической библиотеки tkinter.
from tkinter import * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards)
self.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
Btn(f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 9. GUI приложение с решёткой кнопок.
Рис. 5. Приложение созданное программой листинг 9.
Программа листинг 9 использует библиотеку Tkinter для создания приложения с графическим интерфейсом (GUI). Вот что она делает:
- Первая строка импортирует модуль tkinter, который предоставляет основу для строительства приложений с GUI.
- Далее определены переменные column и row, которые устанавливают количество столбцов и строк в layout GUI.
- Определен класс Btn как подкласс Button. Этот кастомный класс кнопки переопределяет метод __init__ для добавления некоторых дополнительных функций:
- Он вызывает метод __init__ родительского класса с помощью super().__init__(*args, **kwards).
- Он настраивает расположение кнопки с помощью pack() с разными опциями (expand, fill и side).
- Затем программа вводит вложенный цикл для создания решётки кнопок:
- Внешний цикл повторяется row раз, создавая новый объект Frame для каждой строки.
- Внутренний цикл повторяется column раз, создавая новую кнопку Btn для каждого столбца в текущем фрейме.
- Каждая кнопка настраивается с помощью различных атрибутов (ширина, высота, шрифт).
- Наконец, программа вызывает функцию mainloop() для запуска основного цикла событий Tkinter.
В целом, это код создает простое приложение с GUI с решёткой кнопок, используя библиотеку Tkinter.
"Текст предоставлен llama3 (модель AI)"
from tkinter import * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards, command=self.play)
self.pack(expand=YES, fill=BOTH, side=LEFT)
def play(self): # обработчик нажатия на кнопку
self.config(text='*')
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
Btn(f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 10. В программу, в класс Btn добавлен метод play().
Рис. 6. Приложение созданное программой листинг 10.
Метод play(), экземпляров класса Btn, по щелчку мышью на кнопке выводит на эту кнопку звёздочку (*).
Крестики нолики
from tkinter import * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
who = True
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards, command=self.play)
self.pack(expand=YES, fill=BOTH, side=LEFT)
def play(self): # обработчик нажатия на кнопку
if Btn.who:
self.config(text='X')
else:
self.config(text='0')
Btn.who = not(Btn.who)
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
Btn(f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 11.
Рис. 7.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# tic-tac-toe.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# tic-tac-toe.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.
#
# tic-tac-toe.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
who = True
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards, command=self.play)
self.pack(expand=YES, fill=BOTH, side=LEFT)
def play(self): # обработчик нажатия на кнопку
if self.cget('text') != '': return
self.config(text='X' if Btn.who else '0')
Btn.who = not(Btn.who)
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
Btn(f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 12.
Программа листинг 12 с графическим интерфейсом на основе Tkinter!
Давайте разберемся шаг за шагом: "Что делает программа?"
Программа создает простое игровое приложение Tic-Tac-Toe с графическим интерфейсом, используя Tkinter. Игра имеет 3x3 сетку кнопок, а игроки чередуют клики по пустым кнопкам для placement своих отметок (X или O).
Как работает программа:
- Мы импортируем модуль `tkinter`, который обеспечивает основу для создания приложений с графическим интерфейсом.
- Мы определяем две переменные: `column` со значением 3 и `row` со значением 3, которые определяют размер нашей сетки.
- Мы создаем класс `Btn`, который наследуется от класса `Button` Tkinter. Этот класс будет использоваться для создания отдельных кнопок в нашей сетке.
- В методе `__init__` класса `Btn`:
- Мы вызываем конструктор родительского класса (`super().__init__(*args, **kwards)`) для инициализации кнопки с ее 기본ными настройками.
- Мы устанавливаем команду кнопки на метод `play` (который мы будем обсуждать позднее).
- Мы упаковываем кнопку в сетку с помощью метода `pack`. Опции `expand=YES`, `fill=BOTH` и `side=LEFT` означают, что кнопка будет расширяться для заполнения любого доступного пространства, размещаться на левом краю контейнера и занимать оба горизонтального и вертикального пространства.
- В методе `play`:
- Мы проверяем, не пустая ли кнопка (`if self.cget('text') != '': return`). Если это так, мы возвращаемся сразу.
- Мы обновляем текст кнопки до либо "X", либо "0", в зависимости от значения `Btn.who`.
- Мы переключаем значение `Btn.who` между истиной и ложью.
- В главном цикле:
- Мы создаем фрейм (`Frame`) для каждой строки нашей сетки, используя цикл, который повторяется `row` раз.
- Inside each frame, мы создаем столбец кнопок с помощью другого цикла, который повторяется `column` раз.
- Мы передаем текущий фрейм в аргумент конструктора класса `Btn`, а также другие опции, такие как `width`, `heig `height` и `font`.
- Наконец, мы запускаем цикл событий Tkinter с помощью метода `mainloop()`.
Советы для ваших студентов:
- Понимайте концепцию объектно-ориентированного программирования (ООП) и как классы используются для определения пользовательских объектов.
- Сосредоточьтесь на различии между методом `__init__` и другими методами класса.
- Изучите метод `pack` и его опции, чтобы понимать, как упаковывать widget в сетку или другой макет.
- Практикуйте создание своих пользовательских классов и использование их для создания элементов интерфейса.
Надеюсь, это поможет!
"Текст предоставлен llama3 (модель AI)"
Я решил посмотреть как напишет подобную программу Искусственный Интеллект.
>>> Измени следуюющую программу, улучшив её:
Программа была улучшена!
Вот изменения, которые я сделал:
- Переименовал класс `Btn` в `TicTacToe`, потому что он представляет собой инстанцию игры Tic-Tac-Toe.
- Использовал `tkinter` вместо просто `tk`.
- Создал метод `create_buttons`, который создает и настраивает все кнопки в одном месте.
- Заменил метод `__init__` класса `Btn` на простой конструктор, который инициализирует атрибут `window`.
- Заменил метод `play` класса `Btn` на новый, который принимает индексы строки и столбца как аргументы, а не зависит от магических чисел.
- Использовал `grid` вместо `pack` для упаковывания кнопок в сетку, что более подходит для игры Tic-Tac-Toe.
- Удалил ненужный вызов `mainloop()` в конце программы.
Данные изменения сделали код более читаемым и поддерживаемым, а также позволяют более легко расширять или модифицировать логику игры, если это нужно.
Вот полная улучшенная программа:
"Текст предоставлен llama3 (модель AI)"
# "Текст предоставлен llama3 (модель AI)"
import tkinter as tk
class TicTacToe:
def __init__(self):
self.window = tk.Tk()
self.window.title("Tic-Tac-Toe")
self.window.geometry("300x300")
self.buttons = [[None for _ in range(3)] for _ in range(3)]
self.who = True
self.create_buttons()
self.window.mainloop()
def create_buttons(self):
for i in range(3):
for j in range(3):
button = tk.Button(self.window, text="", width=10, height=5,
command=lambda i=i, j=j: self.play(i, j))
button.grid(row=i, column=j)
self.buttons[i][j] = button
def play(self, row, col):
if self.buttons[row][col]['text'] != "":
return
self.buttons[row][col].config(text='X' if self.who else '0')
self.who = not self.who
if __name__ == "__main__":
game = TicTacToe()
Лист. 13. Программа tic-tac-toe написанная llama3 (модель AI).
Рис. 8.
Нельзя это оставить без комментариев.
Код как в учебных пособиях американских профессоров (не буду уточнять). Это не плохо.
Теперь по поводу улучшений (по пунктам из комментария к программе):
- ИИ не понял, что программа листинг 12, предложенная ему в качестве образца, только вариант из множества логических игр на поле в клетку, поэтому я использовал для создания кнопок класс Btn наследник класса Button.
- import tkinter as tk, согласен, только так надо делать в больших проектах.
- "Создал метод `create_buttons`, который создает и настраивает все кнопки в одном месте", а я сделал так, чтобы класс Btn с минимальными изменениями использовался в других играх, а дизайн кнопок мог бы настраиваться в основной программе.
- "Заменил метод `__init__` класса `Btn` на простой конструктор, который инициализирует атрибут `window`", у меня это делается в основной программе ведь для разных игр и window обычно разное.
- "Заменил метод `play` класса `Btn` на новый, который принимает индексы строки и столбца как аргументы, а не зависит от магических чисел." ИИ (или американские профессора) наверное считают что вычисление номера строки или столбца в таблице по номеру элемента в этой же таблице с помощью простейших арифметических операций деление нацело // и взятие остатка от деления % - это МАГИЯ.
- "Использовал `grid` вместо `pack` для упаковывания кнопок в сетку, что более подходит для игры Tic-Tac-Toe". Это не так, у ИИ игровое поле получилось кривое. Кроме того, в пользу форматирования элементов интерфейса и контента путём размещения этих элементов в контейнерах уже несколько десятилетий голосуют web разработчики. В tkinter for Python для этого применяется метод pack().
- "Удалил ненужный вызов `mainloop()` в конце программы". Это хорошо, если не учитывать изложенные мною аргументы в пунктах 1, 2, 4.
Что ест уж
арвар
from tkinter import * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
def __init__(self, num, *args, **kwards):
super().__init__(*args, **kwards, command=self.play,
text=self.playground[num])
self.pack(expand=YES, fill=BOTH, side=LEFT)
self.num = num
def play(self): # обработчик нажатия на кнопку
self.config(text=' ')
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 14.
Рис. 9.
from tkinter import * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
def __init__(self, num, *args, **kwards):
super().__init__(*args, **kwards, command=self.play,
text=self.playground[num])
self.pack(expand=YES, fill=BOTH, side=LEFT)
self.num = num
def play(self): # обработчик нажатия на кнопку
n = self.num
m = self.playground.index(" ")
self.config(text=' ')
self.playground[m], self.playground[n] = self.playground[n], " "
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 15.
Рис. 10.
from tkinter import * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
def __init__(self, num, *args, **kwards):
super().__init__(*args, **kwards, command=self.play,
text=self.playground[num])
self.pack(expand=YES, fill=BOTH, side=LEFT)
self.num = num
self.automove()
def play(self): # обработчик нажатия на кнопку
n = self.num
m = self.playground.index(" ")
self.config(text=' ')
self.playground[m], self.playground[n] = self.playground[n], " "
self.automove()
def automove(self): # функция кнопки с пробелом
self.config(text=self.playground[self.num])
if self.cget('text') == " ":
self.after(300, self.automove)
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 16. В программе, в функции Btn.automove() используется рекурсивный отложенный вызов с помощью функции after().
Рис. 11.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.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.
#
# snake.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
class Btn(Button):
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
def __init__(self, num, *args, **kwards):
super().__init__(*args, **kwards, command=self.play,
text=self.playground[num])
self.pack(expand=YES, fill=BOTH, side=LEFT)
self.num = num
self.automove()
def play(self): # обработчик нажатия на кнопку
n = self.num
m = self.playground.index(" ")
if (n in [m+1, m-1] and m // column == n // column
or n in [m-column, m+column]):
self.config(text=' ')
self.playground[m], self.playground[n] = self.playground[n], " "
self.automove()
def automove(self): # функция кнопки с пробелом
self.config(text=self.playground[self.num])
if self.cget('text') == " ":
self.after(300, self.automove)
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))
mainloop() # главный цикл программы
Лист. 17. В программе, в функции Btn.automove() используется рекурсивный отложенный вызов с помощью функции after(). В функцию play() добавлена функция if с правилами игры в условии.
Рис. 12.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.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.
#
# snake.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
class Btn(Button):
space = 8
def __init__(self, num, *args, **kwards):
super().__init__(*args, **kwards, command=self.play)
self.pack(expand=YES, fill=BOTH, side=LEFT)
self.num = num
def play(self): # обработчик нажатия на кнопку
n = self.num
m = Btn.space
if (n in [m+1, m-1] and m // column == n // column
or n in [m-column, m+column]):
playground[m].set(playground[n].get())
playground[n].set(" ")
Btn.space = n
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
playground[n] = StringVar(f, playground[n])
Btn(n, f, width=3, height=2, font=('times', 24, 'bold'),
textvariable=playground[n])
mainloop() # главный цикл программы
Лист. 18. Свойство textvariable объектов класса Button связано с переменной типа StringVar.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.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.
#
# snake.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
btn = [] # список кнопок
class Btn(Button):
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
def __init__(self, num, *args, **kwards):
super().__init__(*args, **kwards, command=self.play,
text=self.playground[num])
self.pack(expand=YES, fill=BOTH, side=LEFT)
self.num = num
def play(self): # обработчик нажатия на кнопку
n = self.num
m = self.playground.index(" ")
if (n in [m+1, m-1] and m // column == n // column
or n in [m-column, m+column]):
self.config(text=' ')
btn[m].config(text=self.playground[n])
self.playground[m], self.playground[n] = self.playground[n], " "
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
btn += [Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))]
mainloop() # главный цикл программы
Лист. 19. Программа содержит список объектов класса Button, то есть, объекты поименованы.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.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.
#
# snake.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
btn = [] # список кнопок
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
class Btn(Button):
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards)
self.pack(expand=YES, fill=BOTH, side=LEFT)
def play(n): # обработчик нажатия на кнопку
m = playground.index(" ")
if (n in [m+1, m-1] and m // column == n // column
or n in [m-column, m+column]):
playground[m], playground[n] = playground[n], " "
btn[n].config(text=" ")
btn[m].config(text=playground[m])
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
btn += [Btn(f, width=3, height=2, font=('times', 24, 'bold'),
text=playground[n], command=lambda n=n: play(n))]
mainloop() # главный цикл программы
Лист. 20. Программа с lambda функцией.
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.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.
#
# snake.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
btn = [] # список кнопок
playground = list('ЧТОЕСТЖУ ') # виртуальное игровое поле
class Btn(Button):
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards)
self.pack(expand=YES, fill=BOTH, side=LEFT)
class Letter:
def __set__(self, instance, value):
instance.config(text=value)
letter = Letter()
def play(n): # обработчик нажатия на кнопку
m = playground.index(" ")
if (n in [m+1, m-1] and m // column == n // column
or n in [m-column, m+column]):
btn[m].letter, btn[n].letter = playground[m], playground[n] = playground[n], " "
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
btn += [Btn(f, width=3, height=2, font=('times', 24, 'bold'),
text=playground[n], command=lambda n=n: play(n))]
mainloop() # главный цикл программы
Лист. 21. Класс Btn с дескриптором Letter, который содержит функцию __set__ .
#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.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.
#
# snake.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 * # графическая библиотека
column = 3 # столбцы
row = 3 # строки
btn = [] # список кнопок
class Btn(Button):
def __init__(self, *args, **kwards):
super().__init__(*args, **kwards)
self.pack(expand=YES, fill=BOTH, side=LEFT)
class Letter:
def __set__(self, instance, value):
instance.config(text=value)
def __get__(self, instance, owner):
return instance.cget('text')
letter = Letter()
def play(n): # обработчик нажатия на кнопку
m = [i.letter for i in btn].index(" ")
if (n in [m+1, m-1] and m // column == n // column
or n in [m-column, m+column]):
btn[m].letter, btn[n].letter = btn[n].letter, " "
for i in range(row):
f = Frame() # Фреймы
f.pack(expand=YES, fill=BOTH)
for j in range(column):
n = i * column + j
btn += [Btn(f, width=3, height=2, font=('times', 24, 'bold'),
text='ЧТОЕСТЖУ '[n], command=lambda n=n: play(n))]
mainloop() # главный цикл программы
Лист. 22. Класс Btn с дескриптором Letter, который содержит функции __set__ и __get__.
Литература: proglib