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 и храните виджеты во вложенном списке по их координатам в сетке. С такой основой вы сможете по запросу менять внешний вид или подпись любой клетки, а цикл событий будет поддерживать отзывчивость интерфейса.