kxgames / glooey

An object-oriented GUI library for pyglet.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Randomly removed button (or doesn't render it?) from custom widget

PSMusicalRoc opened this issue · comments

My custom widget named EmptySlot is supposed to be a widget that has a background widget with a button widget over it. For the most part, I've done that, however when I load my program, which iterates over 2 loops and creates a 3x3 grid filled with these widgets, the program randomly allows some of the created widgets to show (or have) their buttons, while others don't have them. Which ones happen to have their buttons seems random. I was wondering if someone could help me figure out why the widget is bugging, and if there is a better way to create the EmptySlot widget.

What happens: https://drive.google.com/file/d/1QLaoDQX6urg7_OfGs_zdPt13hX90E6gE/view?usp=sharing

Code:

main.py:

import pyglet, glooey
import Widgets

gui_batch = pyglet.graphics.Batch()

window = pyglet.window.Window(1920, 1080,
                              caption="Smash Scoreboard 4.0")
gui = glooey.Gui(window, batch=gui_batch)

grid = glooey.Grid(3, 3)
for y in range(3):
  for x in range(3):
    grid[x, y] = Widgets.EmptySlot()

gui.add(grid)

@window.event
def on_draw():
  window.clear()
  gui_batch.draw()

pyglet.app.run()

__init__.py in the Widgets module

import glooey, pyglet

##################################
# WIDGET PRIMITIVES DEFINED HERE #
##################################

class Slot(glooey.Background):
  custom_center = pyglet.resource.texture('Widgets/Textures/BaseWidget/DefaultBackgroundColor.png')
  custom_top = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetTop.png')
  custom_bottom = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetBottom.png')
  custom_left = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetLeft.png')
  custom_right = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetRight.png')
  custom_top_left = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetTopLeft.png')
  custom_top_right = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetTopRight.png')
  custom_bottom_left = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetBottomLeft.png')
  custom_bottom_right = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetBottomRight.png')

class AddButton(glooey.Button):
  
  class Background(glooey.Background):
    custom_center = pyglet.resource.texture('Widgets/Textures/BaseWidget/WidgetAdd.png')

class EmptySlot(glooey.Widget):
  def __init__(self):
    super().__init__()
    
    self.background = Slot()
    self._attach_child(self.background)

    self.board = glooey.Board()
    button = AddButton()

    self.board.add(button, left=50, bottom=50, width=1, height=1)
    self._attach_child(self.board)
  
  def do_claim(self):
    return self.background.do_claim()

#####################################
# END WIDGET PRIMITIVES DEFINITIONS #
#####################################

Update:

I ended up fixing the weird inconsistency by inheriting from a Stack, which gave my widget the functionality it needed. However, I would like an explanation as to why my first attempt was inconsistent if anyone has an answer

New Class Definition

class EmptySlot(glooey.Stack):

  def __init__(self):
    super().__init__()

    self.background = Slot()
    self.button = AddButton()
    self.board = glooey.Board()

    self.board.add(self.button, right=50, bottom=50, height=1, width=1)

    self.add_back(self.background)
    self.add_front(self.board)

I can't see the image you uploaded (it appears to be 382 MB?!), so this is a little bit of a guess, but I'm pretty sure the problem is that you didn't reimplement the _do_regroup_children() method. This method is important here because groups (specifically, OrderedGroup) are how you make control z-ordering in pyglet. By default, all the children of a widget just go in the same group as that widget. But when two widgets in the same group overlap, it's basically random which one will appear in front.

Here's an example of how you might handle this:

from pyglet.graphics import OrderedGroup

def _do_regroup_children(self):
    self.background._regroup(OrderedGroup(1, self.group))
    self.board._regroup(OrderedGroup(2, self.group))

(Note: I can't remember off-hand whether higher- or lower-numbered groups go in front, so you might have to switch the numbers.)

All that said, if you haven't already, I'd recommend reading the tutorial on composing widgets. It goes over some examples very similar to what you're trying to do here. In particular, I would probably recommend using Stack rather than writing your own _do_regroup_children() method, just because it'll keep your code simpler. But I wouldn't recommend inheriting from Stack, because Stack does a bunch of things that don't make sense for your widget (e.g. adding/removing widgets). Instead, I would inherit from Widget, add a single Stack as a child, then add the Background and the Button to the Stack. (If that doesn't make sense, the tutorial says basically the same thing in more detail.)

Thank you for that, doing things with a Stack worked beautifully! Now for another, unrelated to topic, question (I'm not sure if that should go in its own issue or not, still figuring out the customs of GitHub!) When I try to implement a ScrollBox widget with a 6x6 grid that is too big attached to it, it throws a sizing error. Specifically:

RuntimeError: Gui(id=2040) is only 300x300, but its children are 431x431.

For context, here is the code I've been using. It's being put into a 300x300 window (as shown in the error log):

class TestScroll(glooey.ScrollBox):
  def __init__(self):
    super().__init__()

    self.grid = Grid(6, 6)

    for x in range(6):
      for y in range(6):
        self.grid[y, x] = TextInputButton((0, 0))
    
    self.add(self.grid)

...where Grid is a custom grid inherited from your Grid function that has 5 cell padding on it, and TextInputButton is a simple button with an image on it.

Any idea how to remedy this?

It's probably better to open new issues for unrelated questions, because I think that makes it easier for other people to find the issue if they have a similar question. It also makes it a little more clear what's meant if the issue gets referenced in a commit or a PR. But that's just for future reference, don't worry about creating a new issue for this question.

Regarding the actual question: I think the problem is that the TestScroll doesn't define either the HBar or VBar inner classes. Glooey interprets that to mean that the box is not scrollable in either the horizontal or vertical directions, and therefore the content of the box must fit within the window. I realize that this isn't actually mentioned anywhere in the docs, and it's a pretty easy mistake to make, so I'll definitely try to update the docs and make this more clear.

Awesome, thanks! That suggestion worked, although I figured out that defining the Grid as being a 6x6 grid was the mistake. I had only wanted vertical scrolling, and I accidentally kept the Grid too large to fit in the ScrollBox.