有时会绘制在glooey按钮pyglet上的图像有时不会

如何解决有时会绘制在glooey按钮pyglet上的图像有时不会

我有一个pyglet主窗口,要在其中添加一些控制按钮。每个按钮上均绘制一个图标。

这是我的简约示例:

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

    def do_draw(self):
        image_width,image_height = Image.open(self.image_path).size
        x = self.rect.left + self.rect.width/2 - image_width/2
        y = self.rect.bottom + self.rect.height/2 - image_height/2
        if self.sprite is None:
            self.sprite = pyglet.sprite.Sprite(img=pyglet.image.load(image_path),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 = [
            """
            All buttons listed here
            """
        ]

        for button in menu_buttons:
            vbox.add(button)

        self.gui.add(vbox)

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

如果我运行几次,我总是会得到另一组正确绘制的按钮:

enter image description here

问题是,为什么会这样?如何解决?

解决方法

我不完全知道发生了什么,但是我有一些评论可能会有所帮助:

  • 这种问题(图像不会随机显示)通常是两个图像位于同一OrderedGroup中的征兆。这导致图像被随机排序。当应该在后面的图像最终出现在前面时,看起来应该在前面的图像就不在了。

    在这种情况下,self.sprite与按钮在同一组中,因此看起来很可疑。

  • 您可能不应该继承Button并实现do_draw()Button类旨在使用类变量进行配置,如下所示:

    class BasicButton(glooey.Button):
        custom_base_image = pyglet.image.load('...')
        custom_over_image = pyglet.image.load('...')
        custom_down_image = pyglet.image.load('...')
    

    如果出于某些原因(在此简单示例中未显示)而需要实现do_draw(),则最好从Widget而不是Button派生一个新的小部件。 Button基本上是Stack / Image / Background小部件的可配置Label。如果我想对这些小部件做一些非常不寻常的事情,我只会从子类中重载Button方法。但是在这种情况下,do_draw()似乎根本没有对这些小部件做任何事情;只是用图像遮盖了它们。如果是这样,最好的办法是从Widget继承,这样一开始就没有什么可掩盖的。请注意,所有窗口小部件(不仅仅是Button)在单击时都会发出事件,并且您可以使用Rollover在自定义Widget子类中轻松实现翻转效果。

  • 这是一件小事,但是使用PIL获取图像的宽度和高度有点奇怪。您可以直接从pyglet获取此信息,例如:

    img = pyglet.image.load(image_path)
    x = self.rect.center.x - img.width / 2
    y = self.rect.center.y - img.height / 2
    

如果这些注释无济于事,如果您发布一个实际运行的代码段(以及必要的图像文件)并显示出问题,我可能会给出更好的答案。

,

这并不能完全回答原始问题,但似乎OP真正想做的是动态更改按钮的文本(例如,通过回调)。这很容易做到,并且不需要重载任何父类方法。

要理解的重要概念是按钮实际上只是其他小部件的专门容器。具体来说,一个按钮包含一个前景小部件和一些背景小部件(每个鼠标状态一个)。要动态更改按钮,您只需要访问包含的相关小部件(在本例中为前台)并进行更改即可。这种体系结构的优点在于,无论按钮中包含哪种小部件,它都可以工作。如果前景是Label,则可以设置button.foreground.text。如果是Image,则可以设置button.foreground.image,等等。

这是一个简单但完整的示例。在此示例中,按钮的滚动状态只是纯色而不是图像,按钮文本只是每次单击按钮时都会递增的数字,但希望它可以显示如何执行此操作。

import pyglet
import glooey

class MyButton(glooey.Button):
    custom_base_color =  40,40,40  # dark grey
    custom_over_color =  80,80,80  # normal grey
    custom_down_color = 240,240,240  # light grey

window = pyglet.window.Window()
gui = glooey.Gui(window)

# Note that arguments to the Button constructor are passed directly to the 
# constructor of the foreground widget,which is `Text` by default.
button = MyButton('1')
gui.add(button)

def on_click(button):
    i = int(button.foreground.text)
    button.foreground.text = str(i + 1)

button.push_handlers(on_click)

pyglet.app.run()

编辑:

我现在了解到OP需要一个在前景上既有图像又有标签的按钮(当然还有鼠标响应的背景)。上面相同的“按钮就是容器”概念也与此有关。一个按钮只能有一个前景小部件,但是前景小部件本身可以包含任意数量的小部件。例如,您可以将前景设置为HBox,以便将多个窗口小部件并排放置在一个按钮中。

要创建一个按钮,使前景小部件的图像上方带有文本,诀窍是使前景小部件成为Stack。然后,您可以将文本和图像添加到该堆栈中。

以下示例显示了执行此操作的一种方法。请注意,前台堆栈被分解到名为MyImageLabel的自定义窗口小部件类中。我认为这会使代码更清晰和可重用,但是您无需执行此操作即可获得相同的效果(即,直接在MyButton.Foreground中创建堆栈,甚至在实例化按钮并将其分配给之后创建堆栈button.foreground)。还要注意,文本和图像都可以通过回调进行修改,与上面的方法大致相同。

#!/usr/bin/env python3

import pyglet
import glooey

class MyImageLabel(glooey.Widget):
    Image = glooey.Image
    Label = glooey.Label

    def __init__(self):
        super().__init__()
        self._stack = glooey.Stack()
        self.label = self.Label()
        self.image = self.Image()

        self._stack.add(self.image)
        self._stack.add(self.label)

        self._attach_child(self._stack)

class MyButton(glooey.Button):

    class Foreground(MyImageLabel):

        class Image(MyImageLabel.Image):
            custom_image = pyglet.image.load('img0.png')

        class Label(MyImageLabel.Label):
            custom_text = '1'
            custom_alignment = 'center'

    custom_base_color =  40,240  # light grey

window = pyglet.window.Window()
gui = glooey.Gui(window)

button = MyButton()
gui.add(button)

def on_click(button):
    i = int(button.foreground.label.text)
    button.foreground.label.text = str(i + 1)
    button.foreground.image.image = pyglet.image.load(f'img{i%2}.png')

button.push_handlers(on_click)

pyglet.app.run()

screenshot

如果要运行上面的示例,则需要下载这些图像并分别命名为img0.pngimg1.png

green border orange border

,

@Kale Kundert一定会给我正确的方向,以解决此问题。是的,组顺序是基本的,并且在此文档的帮助下:https://pyglet.readthedocs.io/en/latest/modules/graphics/通过确保将实现中的Sprite对象添加到前台组中,我设法获得了所需的行为, >

class BasicButton(glooey.Button):
    def __init__(self,*,button_text,image_path):
        super().__init__(button_text)
        self.sprite = None
        self.image_path = image_path

    def do_draw(self):
        image_width,image_height = Image.open(self.image_path).size
        x = self.rect.left + self.rect.width/2 - image_width/2
        y = self.rect.bottom + self.rect.height/2 - image_height/2
        if self.sprite is None:
            self.sprite = pyglet.sprite.Sprite(
                img=pyglet.image.load(image_path),x=x,y=y,batch=self.batch,group=self._foreground.get_group()
        )
        else:
            self.sprite.x = x
            self.sprite.y = y

请注意self._foreground.get_group()上的更改。

考虑到@Kale Kundert的回答,也许这不是最正确的实现,但是我的目的是让按钮的行为具有响应性的悬停/单击背景,这也使我可以编辑显示在通过回调。如果我为每种潜在情况添加按钮图标(图像),我将无法达到这种自由度。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-