Centering and keeping aspect ratio of DirectGui.DirectFrame

Hi, I am struggling with positioning and sizing issue with pixel2d.
I would like to have centered directframe with same size and aspect ratio of the frame even when the panda3d window is resized.
The positioning behaves as if the screen was the initial size so when let’s say make the window wider it stretches the frame and also the position is not what I expect.

panda3d==1.10.7

from direct.showbase.ShowBase import ShowBase
from direct.gui.DirectGui import DirectFrame


class App(ShowBase):
    def __init__(self):
        super().__init__()
        self._root = self.pixel2d
        self._frame_size = (0, 300, -100, 0)
        self._frame = DirectFrame(
            parent=self._root,
            frameColor=(1.0, 0., 1.0, 1.0),
            frameSize=self._frame_size
        )
        self.accept("window-event", self._handle_window_event)

    def _handle_window_event(self, window):
        win_props = window.get_properties()
        w = win_props.get_x_size()
        h = win_props.get_y_size()
        self._frame.destroy()
        self._frame = DirectFrame(
            parent=self._root,
            pos=((w - 300.) / 2., 0., -(h - 100) / 2.),
            frameColor=(1.0, 0., 1.0, 1.0),
            frameSize=self._frame_size
        )
        # self._frame.set_pos((w - 300.) / 2., 0., -(h - 100) / 2.)


if __name__ == "__main__":
    app = App()
    app.run()

Thanks

Hi, welcome to the community!

It’s because you have handled window-event on the ShowBase object itself, which overrides the default ShowBase window-event handler.

Just add a call to ShowBase.windowEvent(self, window) call to your _handle_window_event.

If you want to do this for the main (default) window, then you could handle the "aspectRatioChanged" event instead, which seems to be defined for such purposes, as noted in the source code:

            # If anybody needs to update their GUI, put a callback on this event
            messenger.send("aspectRatioChanged")

Your event handler then only needs to be changed slightly, as follows:

        self.accept("aspectRatioChanged", self._handle_window_event)

    def _handle_window_event(self):
        win_props = self.win.get_properties()
        w = win_props.get_x_size()
        h = win_props.get_y_size()
        self._frame.destroy()
        self._frame = DirectFrame(
            parent=self._root,
            pos=((w - 300.) / 2., 0., -(h - 100) / 2.),
            frameColor=(1.0, 0., 1.0, 1.0),
            frameSize=self._frame_size
        )
2 Likes

Thanks… So I suppose the best practice to avoid unitentionally overriding any behaviour is to instantiate separate DirectObject and then put listeners there?

Thank you, that but that would be called only if the window aspect ratio is changed…
If the aspect ratio is the same lets say the resize is from 400x300 pixels to 800x600 it would not be called. I would like to keep the frameSize of the frame on screen in pixels exactly the same regardless of the size of the window.

Yes, but I think the only situation where ShowBase is overriding an event is “window-event”.

In fact, I am considering changing Panda to use its own DirectObject for that event, since this appears to be a common stumbling block.

1 Like

Ah, you’re right, sorry! Although a (manual) window resize rarely maintains the aspect ratio, it can still happen of course.
Fair enough, handling the "window-event" is the way to go, then :slight_smile: .

On a side note, I wonder why you destroy and re-create the frame in your handler? If you simply want to adjust the position, you could just do this:

    def _handle_window_event(self, window):
        win_props = window.get_properties()
        w = win_props.get_x_size()
        h = win_props.get_y_size()
        self._frame.set_pos((w - 300.) / 2., 0., -(h - 100) / 2.)
1 Like

I know I wasn’t sure, why it wasn’t working and I was recreating it to just rule out other possibilities of what might be wrong. (It is even commented out in the snippet.)

Thanks for the help in any case!

Edit: wanted to quote epihaus.

Thanks.

From a panda novice perspective, the main confusing bit for me is that it reminds me of publish-subscribe pattern, where you would have multiple handlers for same event.