In my attempt to create an automatic layout system for DirectGui widgets, I stumbled upon a couple of issues.
This particular one is about retrieving the exact size of a DirectGui object, immediately after its creation.
There is the
getBounds method, which does seem to return correct values, but only after at least one frame has been rendered. Before that, it looks like it returns the bounds of the text(node) of that widget, without taking the frame size into account.
Then there is also the
guiItem.getFrame method, which seems to do the opposite and completely disregards the text, returning the size of the frame only (which I suppose is quite logical, given the name of the method).
This would give the desired results, but only if the text doesn’t stick out of the frame (e.g. because of
text_pos or due to the text being larger than the frame).
Here is some code to reproduce this:
from panda3d.core import * from direct.showbase.ShowBase import ShowBase from direct.gui.DirectGui import * class MyApp: def __init__(self): self.showbase = showbase = ShowBase() showbase.task_mgr.do_method_later(1., self.__create_widgets, "create_widgets") showbase.run() def __create_widgets(self, task): gui_root = self.showbase.pixel2d title = "Title bar" label = DirectLabel(parent=gui_root, text=title, text_align=TextNode.A_center, # pos=(400, 0, -100), textMayChange=1, scale=20, relief=DGG.SUNKEN, borderWidth=(.3, .3)) # pos=(400, 0, -100), textMayChange=1, frameSize=(0, 1, -.1, .1), scale=20, relief=DGG.SUNKEN) pos=(400, 0, -100), textMayChange=1, frameSize=(-10, 10, -.5, .5), scale=20, relief=DGG.SUNKEN) print("Size label text before render:", label.getBounds()) print("Size label frame before render:", label.guiItem.getFrame()) text = "My Button" button = DirectButton(parent=gui_root, text=text, borderWidth=(.3, .3), scale=20, pos=(400, 0, -300), textMayChange=1) print("Size button text before render:", button.getBounds()) print("Size button frame before render:", button.guiItem.getFrame()) self.showbase.graphicsEngine.render_frame() print("Size label after render:", label.getBounds()) print("Size button after render:", button.getBounds()) MyApp()
The output is as follows:
Size label text before render: [-1.8624999523162842, 1.975000023841858, -0.11250001192092896, 0.75] Size label frame before render: LVecBase4f(-10, 10, -0.5, 0.5) Size button text before render: [-2.3000001907348633, 2.3874998092651367, -0.32499998807907104, 0.7125000357627869] Size button frame before render: LVecBase4f(-2.6, 2.6875, -0.625, 1.0125) Size label after render: [-10.0, 10.0, -0.5, 0.75] Size button after render: [-2.6000001430511475, 2.687499761581421, -0.625, 1.0125000476837158]
So I seem to have two options currently:
- render a frame after creating one or more widgets (a bit annoying for the end users of my project, who will have to call some function to initialize the sizes of my custom wrapper class instances, each time they added new widgets);
- combine the results from both methods mentioned above; this seems ideal, but then I would like confirmation from the Panda developers that this would indeed work in all cases, without there being any other factors affecting the final size of a widget, not taken into account for those returned values.