You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter网格异常问题:销毁方块后视觉消失的排查与解决

Tkinter图像揭示游戏开发:问题与解决

需求与初始实现

我正在用Python的Tkinter开发一款图像揭示游戏,核心功能是展示一张被可点击销毁的网格方块覆盖的图片。点击方块时销毁它并打印坐标,期望销毁方块后其余方块保持网格位置不变,逐步揭示下方图片,网格形态不发生变化。

我编写了以下最简版线性代码:

from tkinter import *
from PIL import ImageTk, Image


class Box:
    def __init__(self, parent, row, column, width, height):
        self.row = row
        self.column = column
        self.canvas = Canvas(parent, bg='black', width=width, height=height)
        self.canvas.grid(row=row, column=column, sticky=NSEW)
        self.canvas.bind('<Button-1>', self.destroy)

    def destroy(self, event):
        print('Destroyed box at', self.row, self.column)
        self.canvas.destroy()


root = Tk()
root.title('Image Reveal')
root.state('zoomed')
image_raw = None

# 为图片创建容器框架
image_frame = Frame(root, highlightbackground="blue", highlightthickness=5)
image_frame.pack(expand=True, anchor=CENTER, fill=BOTH, padx=0, pady=0)

# 加载图片并放入标签
image_raw = Image.open('image.png')
image = ImageTk.PhotoImage(image_raw)
image_label = Label(image_frame, image=image, borderwidth=5, relief='ridge')
image_label.pack(anchor=CENTER, expand=True)

# 计算方块尺寸
image_label.update()
width = image.width()
height = image.height()
column_amount = 10
row_amount = 10
box_width = width / column_amount
box_height = height / row_amount

# 创建铺满网格的方块
for row in range(row_amount):
    for column in range(column_amount):
        Box(image_label, row, column, box_width, box_height)

root.mainloop()

异常现象

点击方块销毁后,其余方块视觉上消失,但仍可点击触发销毁日志,无法实现预期的网格保持效果。

优化与最终解决方案

在Lukas Krahbichler的帮助下先实现了大部分预期效果,但销毁整行或整列方块时会导致网格尺寸变化。最终通过将方块隐藏至图片下方替代销毁的方式解决问题(由于Canvas没有直接整体下移的方法,需调用tk原生命令)。

最终可用代码如下:

from tkinter import *
from PIL import ImageTk, Image


class Box:
    def __init__(self, root, image_frame, image_label, row, column):
        self.root = root
        self.row = row
        self.column = column
        self.image_label = image_label
        self.image_frame = image_frame
        self.visible = True
        self.canvas = Canvas(image_frame, bg='black')
        self.canvas.grid(row=row, column=column, sticky=NSEW, padx=5, pady=5)
        
        self.canvas.bind('<Button-1>', self.hide)

    def hide(self, event):
        # 将方块下移至图片下方实现隐藏
        self.canvas.tk.call('lower', self.canvas._w, None)
        self.visible = False
        print('Hid box at', self.row, self.column)



root = Tk()
root.title('Image Reveal')
root.state('zoomed')
image_raw = None
column_amount = 10
row_amount = 10
boxes = []

# 为图片创建容器框架
image_frame = Frame(root, highlightbackground="blue", highlightthickness=0)
image_frame.pack(anchor=CENTER, fill=None, padx=0, pady=0)

# 加载图片并放入标签
image_raw = Image.open('image.png')
image = ImageTk.PhotoImage(image_raw)
width = image.width()
height = image.height()

# 创建图片标签
image_label = Label(image_frame, image=image, borderwidth=0, relief='ridge')

# 配置图片框架禁止自动调整尺寸             <----- 更新部分
image_frame.config(width=width, height=height)
image_frame.grid_propagate(False)
image_label.grid_propagate(False)

# 将图片标签放入框架
image_label.grid(rowspan=row_amount, columnspan=column_amount, sticky="NSEW")

# 配置网格权重                                <----- 更新部分
for row in range(10):
    image_frame.rowconfigure(row, weight=1)
for column in range(10):
    image_frame.columnconfigure(column, weight=1)

# 更新图片标签状态
image_label.update()

# 创建铺满网格的方块
for row in range(row_amount):
    for column in range(column_amount):
        box = Box(root, image_frame, image_label, row, column)
        boxes.append(box)

root.mainloop()

内容的提问来源于stack exchange,提问作者Yamiko Hikari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:00:27