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

Pyglet中Glooey按钮图标有时显示有时不显示的问题求助

问题原因与解决方案

我来帮你分析这个不稳定的图标显示问题,你的代码里有几个关键bug导致了这个现象:

核心原因

  • 变量作用域错误:在BasicButton的do_draw方法里,你用了image_path而不是self.image_path来加载图片。这意味着所有按钮都在引用外部的某个image_path变量(比如创建按钮时的循环变量),而不是每个按钮自己实例化时传入的路径。Python的变量绑定特性会导致这个外部变量的值可能在按钮绘制时已经变成了最后一个按钮的路径,或者因为作用域混淆随机指向不同路径,最终表现为每次运行显示图标的按钮都不一样。
  • 重复读取图片文件:每次绘制按钮都调用Image.open(self.image_path).size获取尺寸,这会反复打开并读取文件,既浪费资源,也可能因为文件系统临时问题(比如缓存、权限)导致部分图片读取失败。
  • 无错误处理:图片加载过程中没有捕获异常,如果某个图片路径错误或文件损坏,会直接导致该按钮的精灵无法创建,但没有任何提示,这也让问题看起来像是"随机"发生。

修复后的代码

下面是修正后的完整代码,我标注了所有关键修改点:

from PIL import Image
import glooey
import pyglet

class BasicButton(glooey.Button):
    def __init__(self, *, button_text, image_path):
        super().__init__(button_text)
        self.sprite = None
        self.image_path = image_path
        # 修复点1:提前加载图片并缓存尺寸,避免每次绘制重复读文件
        try:
            self.image = pyglet.image.load(self.image_path)
            self.image_width, self.image_height = self.image.width, self.image.height
        except Exception as e:
            # 修复点2:添加错误处理,打印加载失败信息
            print(f"Failed to load image {self.image_path}: {e}")
            self.image = None
            self.image_width = self.image_height = 0

    def do_draw(self):
        if not self.image:
            # 图片加载失败时,退回到只显示按钮文字
            super().do_draw()
            return
        
        # 计算图标居中位置
        x = self.rect.left + self.rect.width/2 - self.image_width/2
        y = self.rect.bottom + self.rect.height/2 - self.image_height/2

        if self.sprite is None:
            # 修复点3:使用提前加载好的self.image,避免重复加载
            self.sprite = pyglet.sprite.Sprite(
                img=self.image, 
                x=x, y=y, 
                batch=self.batch, 
                group=self.group
            )
        else:
            self.sprite.x = x
            self.sprite.y = y

class AddWidgetsToWindow(glooey.Widget):
    def __init__(self, pyglet_window: pyglet.window.Window):
        super().__init__()
        self.gui = glooey.Gui(pyglet_window)
        vbox = glooey.VBox(default_cell_size=40)
        vbox.padding = 5
        vbox.alignment = 'left'
        # 示例:创建带不同图标的按钮
        menu_buttons = [
            BasicButton(button_text="Button 1", image_path="icon1.png"),
            BasicButton(button_text="Button 2", image_path="icon2.png"),
            BasicButton(button_text="Button 3", image_path="icon3.png")
        ]
        for button in menu_buttons:
            vbox.add(button)
        self.gui.add(vbox)

window = pyglet.window.Window()
AddWidgetsToWindow(window)
pyglet.app.run()

关键修复说明

  1. 提前加载图片:在__init__方法中就完成图片加载和尺寸缓存,避免每次绘制时重复读取文件,提升性能的同时消除了文件读取的不稳定因素。
  2. 修复变量引用:确保所有使用图片相关的资源都用实例自身的属性(self.image_path、self.image),彻底解决作用域混淆问题。
  3. 添加错误处理:捕获图片加载异常并打印信息,同时在绘制时做降级处理,保证按钮至少能显示文字,不会完全失效。
  4. 避免重复加载:创建精灵时直接使用预加载的self.image,减少不必要的I/O操作,让按钮图标加载更稳定。

这样修改后,每个按钮都会稳定加载自己的图标,不会再出现每次运行显示不同的情况了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:27:50