2025, Nov 25 15:01
Шахматная доска в Tkinter: чередование цветов и доступ к клеткам
Как сделать шахматную доску в Tkinter: узор по (r+c)%2, хранение кнопок в двумерном списке, удобный доступ к клеткам для смены текста и фона. Примеры кода.
Создать интерфейс шахматной доски в Tkinter кажется простым — пока не требуется менять отдельные клетки. Если каждую ячейку создавать «на лету» и сразу размещать в сетке, потом обращаться к кнопкам или перекрашивать их неудобно. Ниже — рабочий способ: аккуратное чередование цветов и доступ к любой клетке по её строке и столбцу, чтобы при необходимости менять текст или фон.
Первый подход и почему он мешает
Обычно сначала создают кнопки прямо в сетке, не сохраняя на них ссылок. Отрисовка работает, но удобных «ручек» для последующих изменений не остаётся.
import tkinter as tk
ui = tk.Tk()
ui.geometry("800x500")
ui.minsize(800, 500)
ui.maxsize(800, 500)
boardPane = tk.Frame(ui, width=300, height=300, padx=5, pady=5)
boardPane.pack(side=tk.LEFT)
for r in range(8):
for c in range(8):
tk.Button(boardPane, text=f"{r},{c}", width=5, height=3).grid(row=r, column=c)
ui.mainloop()
Что происходит на самом деле и почему обновления не удаются
Когда виджет создаётся и в том же выражении размещается с помощью grid, ссылка на него нигде не сохраняется. Без ссылки нельзя позже найти виджет и поменять свойства вроде фона или текста. К тому же хранение ссылок помогает избежать преждевременного сборщика мусора. Для чередования цветов нужна стабильная схема, сопоставляющая каждой координате свой цвет; здесь идеально подходит арифметика по модулю.
Решение: чередование через модуль и хранение кнопок в двумерном списке
Шахматный узор — это простая проверка чётности. Если сумма строки и столбца чётная — один цвет; нечётная — другой. Сохраняйте каждый Button во вложенном списке с индексами [row][column] — и обновлять элементы станет элементарно.
import tkinter as tk
TILE_A = "white"
TILE_B = "green"
app = tk.Tk()
app.geometry("800x500")
app.minsize(800, 500)
app.maxsize(800, 500)
board = tk.Frame(app, width=300, height=300, padx=5, pady=5)
board.pack(side=tk.LEFT)
cells = [] # двумерный список ссылок на кнопки
for r in range(8):
cells.append([])
for c in range(8):
shade = TILE_A if (r + c) % 2 else TILE_B
btn = tk.Button(
board,
text=f"{r},{c}",
width=5,
height=3,
bg=shade,
)
btn.grid(row=r, column=c)
cells[r].append(btn)
# Пример изменения конкретной клетки по строке и столбцу
cells[3][2]["text"] = "It works!"
app.mainloop()
Почему модуль 2 даёт шахматный узор
Рассмотрим сетку 2×2. Если складывать индексы строки и столбца, чётность меняется при каждом шаге по горизонтали или вертикали. Применение % 2 к этой сумме чередует 0 и 1 у соседних клеток — это напрямую соответствует двум цветам.
+---+---+
| 0 | 1 |
+---+---+
| 1 | 0 |
+---+---+
Тот же принцип масштабируется на любую доску и даёт классический чередующийся рисунок без каскадов условий и жёстко заданных координат.
Доступ и изменение любой клетки
Имея вложенный список, вы обращаетесь к любой кнопке по индексам и меняете атрибуты так же, как в словарном стиле. Например, cells[3][2]["text"] = "It works!" изменит подпись в строке 3, столбце 2. Сохранённые ссылки также удерживают виджеты в памяти и не дают им попасть под сборщик мусора во время работы интерфейса.
О mainloop
mainloop запускает цикл обработки событий. Он не даёт программе завершиться после последней строки кода и отслеживает события вроде нажатий кнопок.
Почему это важно
Поддерживать GUI проще, когда к виджетам можно напрямую обратиться. Небольшое структурное решение — хранить ссылки в двумерном списке — открывает простой путь к изменениям цвета, текста и поведения. Окрашивание через модуль лаконично, читаемо и надёжно. Вместе эти практики делают постепенные доработки интерфейса предсказуемыми и масштабируемыми.
Итоги
Соберите доску один раз, но сохраните доступ к каждой клетке. Чередуйте цвета с помощью (row + column) % 2 и храните виджеты во вложенном списке по их координатам в сетке. С такой основой вы сможете по запросу менять внешний вид или подпись любой клетки, а цикл событий будет поддерживать отзывчивость интерфейса.