Does anyone know how to make wx.Panel and wx.lib.sized_controls.SizedPanel work together.
The problem is that some of the components in wxPython are based on wx.Panel. When I try to use them together, I get the following error
File "<redacted>/pyenv-3.12.4/lib/python3.12/site-packages/wx/lib/sized_controls.py", line 183, in SetSizerProp
# flag = item.GetFlag()
# AttributeError: 'NoneType' object has no attribute 'GetFlag'
# OnInit returned false, exiting...
A use case for me is that I want to simplify building pages. WizardPageSimple is a wx.Panel. Thus, if build a SizedPanel parented by WizardPageSimple I get the above.
I know why, because I should be using all sized containers. I attached a small sample app that illustrates this.
I wonder if someone does not have a clever solution.
Traceback (most recent call last):
File “C:\Users\Me\Documents\Programming\Python\Mylib\experimental\PanelContainingSizedPanel.py”, line 31, in OnInit
self._outerFrame = Frame(parent=None, id=ID_ANY, size=(WINDOW_WIDTH, WINDOW_HEIGHT), style=frameStyle, title=title)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
wx._core.wxAssertionError: C++ assertion ““Assert failure”” failed at …..\src\msw\toplevel.cpp(226) in wxTopLevelWindowMSW::MSWGetParent(): wxFRAME_FLOAT_ON_PARENT but no parent?
OnInit returned false, exiting…
the return code of ‘PanelContainingSizedPanel.py’ is 1
“Controls added to it will automatically be added to its sizer.”
Is this the only difference? Then I would suggest to avoid it. It reminds me of the “easy to use wrapper around wxPython” that many of us have created at some point and abandoned at another.
If you want to make your life easier, then many dialogs and windows can easily be created using a GUI builder like wxGlade.
I don’t know much about sized controls, apart from reading the documentation.
It seems to me that you should only call a control’s SetSizerProps() method if that control is being laid out by a sized control.
In your example, sizedPanel is a SizedPanel object, but it is not being laid out by another sized control, so you shouldn’t call its SetSizerProps() method. Instead, it should be added to boxSizer.
However, if you needed to set the sizer properties of any of its children, then you should call the children’s SetSizerProps() methods.
I modified your example along these lines and it appears to run OK using wxPython 4.2.2 gtk3 (phoenix) wxWidgets 3.2.6 + Python 3.12.3 + Linux Mint 22
from typing import cast
import wx
from wx import App
from wx import DEFAULT_FRAME_STYLE
from wx import FRAME_FLOAT_ON_PARENT
from wx import Frame
from wx import ID_ANY
from wx import Panel
from wx import StaticText
from wx.lib.agw.buttonpanel import BoxSizer
from wx.lib.sized_controls import SizedFrame
from wx.lib.sized_controls import SizedPanel
WINDOW_WIDTH: int = 400
WINDOW_HEIGHT: int = 200
class SizedPanelApp(App):
def __init__(self):
super().__init__()
self._outerFrame: SizedFrame = cast(SizedFrame, None)
def OnInit(self) -> bool:
title: str = 'Demo Sized Panel in Panel'
frameStyle: int = DEFAULT_FRAME_STYLE
self._outerFrame = Frame(parent=None, id=ID_ANY, size=(WINDOW_WIDTH, WINDOW_HEIGHT), style=frameStyle, title=title)
# This simulates a wizard page (which is a panel)
mainPanel: Panel = Panel(parent=self._outerFrame)
boxSizer: BoxSizer = BoxSizer()
mainPanel.SetSizer(boxSizer)
# This simulate a component that is a sized panel
sizedPanel: SizedPanel = SizedPanel(parent=mainPanel) # This is problematic
sizedPanel.SetSizerType('vertical')
boxSizer.Add(sizedPanel, 1, wx.EXPAND, 0)
# noinspection PyUnusedLocal
topLabel: StaticText = StaticText(sizedPanel, ID_ANY, 'Top Label')
# noinspection PyUnusedLocal
bottomLabel: StaticText = StaticText(sizedPanel, ID_ANY, 'Bottom Label')
self._outerFrame.Show(True)
return True
testApp = SizedPanelApp()
testApp.MainLoop()
Having said that, I still prefer to use wxGlade to layout sizers directly, rather than use sized controls.
I’ve realised that what I posted above is not correct.
The critical thing is that a control must be added to a sizer before its SetSizerProps() method is called. That includes being added to a sizer explicitly, or by making it a child of a SizedPanel which automatically adds it to a sizer.
So in the modified example in my previous post, instead of:
Note: when you import the wx.lib.sized_controls module, it monkey patches several wxPython classes. This includes adding a number of methods to the wx.Window class (and thus any classes derived from it). One of those methods is SetSizerProps(). However, if a control of any of those classes has not been added to a sizer, it will raise an AttributeError exception if you call its SetSizerProps() method, as you got in your original post.