Are there any events generated when a panel is created or destroyed

Greetings,

I have a VB and C# background and am looking for events like PanelOpening, PanelOpen, PanelClosing, PanelClosed and the like. Do they even exist in wxPython?

I ask this because after having created a frame, a panel within this frame, a richtextcontrol within the panel I found out that the (default?) width and height of the panel is only 20 * 20.

If you have configured the layout of the controls in an appropriate way, it shouldn’t be necessary to need these sort of events. The best way to create the layout is to use sizers and to then specify the appropriate expand and proportion values.

Could you post some code to show how you are currently managing the layout?

A very useful tool for designing frames and dialogs in wxPython is the GUI builder wxGlade.

http://wxglade.sourceforge.net/docs/index.html

#
# display.py
# 
import wx
from wx.core import WXK_END
import wx.richtext as rt
import wx.lib.mixins.inspection

DEBUG = False

class MainFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="MainFrame")
        #
        (self.width, self.height)  = wx.GetDisplaySize()
        #
        if DEBUG:
            self.width = 1000
            self.height = 800
        print (self.width, self.height)
        #
        self.SetBackgroundColour (wx.BLUE)
        self.SetSize ((self.width, self.height))
        self.SetPosition((0,0))
        #
        mp = MessagePanel(self)
        #

class MessagePanel (wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.SetBackgroundColour (wx.BLACK)
        #
        # Make a RichTextControl after __init__ has completed because after
        # that the actual .Size of this panel has been estableshed. 
        #
        wx.CallAfter (self.MakeRichTextControl)

    def MakeRichTextControl(what):
        (width, height) = what.Size
        rt_width = int(width / 2)
        rt_height = int(height * 5 / 7)
        rt_x = int(width / 4)
        rt_y = int(height / 7)
        print (rt_width, rt_height, rt_x, rt_y)
        #
        what.rtc = rt.RichTextCtrl(what, style=wx.VSCROLL|wx.NO_BORDER,
            pos=(rt_x,rt_y), size=(rt_width,rt_height))
        #
        wx.CallAfter (what.Fill)

    def Fill(what):
        print ("Fill")
        for i in range (1,90):
            what.rtc.WriteText ("Hello RchTextControl!" + str(i))
            what.rtc.Newline()
            what.rtc.ScrollIntoView (what.rtc.GetLastPosition(), WXK_END)

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frm = MainFrame()
    #
    if DEBUG:
        frm.Show(show=True)
        wx.lib.inspection.InspectionTool().Show()
    else:
        frm.ShowFullScreen(show=True)
    #        
    app.MainLoop()

I have tried to adapt your code to a slightly more typical wxPython style:

import wx
import wx.richtext as rt
import wx.lib.mixins.inspection

DEBUG = False

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetBackgroundColour(wx.BLUE)

        if DEBUG:
            width, height = 1000, 800
        else:
            width, height = wx.GetDisplaySize()
        print(width, height)
        self.SetSize((width, height))

        self.panel_1 = wx.Panel(self, wx.ID_ANY)
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add((0, 0), 0, 0, 0)
        self.panel_1.SetSizer(sizer_1)
        self.Layout()

        self.panel_1.SetBackgroundColour(wx.BLACK)

        width, height = self.panel_1.GetSize()
        rt_width = width // 2
        rt_height = height * 5 // 7
        rt_x = width // 4
        rt_y = height // 7
        print (rt_width, rt_height, rt_x, rt_y)

        self.rtc = rt.RichTextCtrl(self,
                                   pos=(rt_x, rt_y),
                                   size=(rt_width, rt_height),
                                   style=wx.VSCROLL|wx.NO_BORDER)

        for i in range(1, 90):
            self.rtc.WriteText ("Hello RichTextControl!" + str(i))
            self.rtc.Newline()
            self.rtc.ScrollIntoView (self.rtc.GetLastPosition(), wx.WXK_END)


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)

        if DEBUG:
            self.frame.Show(show=True)
            wx.lib.inspection.InspectionTool().Show()
        else:
            self.frame.ShowFullScreen(show=True)

        return True


if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

It works using Python 3.8.10 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.3 without needing to use wx.CallAfter().

However, being a full screen app, I don’t know if it will work OK on other platforms.

1 Like

Thank You. I’ll have a look and the bottom line is (I guess) using a BoxSizer…

I think it’s the self.Layout() call that’s having the most impact here.

Here is an alternative idea that uses 2 sizers to automatically centre and resize the RichTextCtrl when the size of the frame changes, without having to explicitly program the sizes.


import wx
import wx.richtext as rt

DEBUG = True

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)

        if DEBUG:
            width, height = 1000, 800
        else:
            width, height = wx.GetDisplaySize()
        print(width, height)
        self.SetSize((width, height))
        self.SetBackgroundColour(wx.BLUE)

        self.panel_1 = wx.Panel(self, wx.ID_ANY)
        self.panel_1.SetBackgroundColour(wx.BLACK)
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add((20, 20), 1, wx.EXPAND, 0)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1.Add(sizer_2, 3, wx.ALL | wx.EXPAND, 0)
        sizer_2.Add((20, 20), 1, wx.EXPAND, 0)
        self.rtc = rt.RichTextCtrl(self.panel_1, wx.ID_ANY, style=wx.VSCROLL|wx.NO_BORDER)
        sizer_2.Add(self.rtc, 2, wx.EXPAND, 0)
        sizer_2.Add((20, 20), 1, wx.EXPAND, 0)
        sizer_1.Add((20, 20), 1, wx.EXPAND, 0)
        self.panel_1.SetSizer(sizer_1)
        self.Layout()

        for i in range(1, 90):
            self.rtc.WriteText ("Hello RichTextControl!" + str(i))
            self.rtc.Newline()
            self.rtc.ScrollIntoView (self.rtc.GetLastPosition(), wx.WXK_END)


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        if DEBUG:
            self.frame.Show(show=True)
        else:
            self.frame.ShowFullScreen(show=True)
        self.frame.Show()
        return True


if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

Lines such as:

sizer_1.Add((20, 20), 1, wx.EXPAND, 0)

add a spacer to the sizer with an arbitrary initial size of (20, 20) which is then overridden by the proportion values and the wx.EXPAND flag.

By varying the proportion values of the spacers and of the RichTextCtrl you can determine the ratio of the dimensions of the RichTextCtrl compared to the Panel.