I am used to Java GUI building where I have a frame, and then add a main panel that gets any layout and then more Panels are added as childs to that main panel. These childs have their own layout manager and maybe even more added panels that get added some buttons or whatever GUI elements.
With xwPython I see a mixture of adding panels and sizers and I am confused how to use them.
I want a Frame. Then I want two main sections within it. One with horizontally aligned buttons in the top (essentially a TAB panel), and then a big panel stretching over the rest of the frame. That big panel shall contain some rectangles with individual text on them and some lines connecting the rectangles showing a path between them.
I wrote two classes extending wx.Panel, one to display / manage the rectangles with the data and one for the map that will show the rectangles before digging deeper into ui features and discovering the sizers.
Now I am unsure what panels are used for since I saw lots of examples and the sizer explanation where you have one main panel and then just add all other objects to sizers instead of child panels. Do I have to change my panel classes to sizer classes instead?
It is possible to make a wxPython application that doesn’t use panels at all: wx.Frame or wx.Dialog at the top, then sizers, and sizers within sizers, until at the leaves you’ll find simple controls like wx.TextCtrl.
What panels give you is a surface to paint on: A wx.Panel can handle an EVT_PAINT event, or you can just set a background colour. Typically, the panel is the root of a new, nested, sizer hierarchy, one that uses the panel as a background. But it doesn’t have to be. You can also make a completely custom widget implemented as a wx.Panel with handlers for wx.EVT_PAINT and other events.
When you see people making designs with deep sizer nesting and very few panels, it may be because they want resizing to re-layout with entire frame fluently. Panels can be used to break up the layouting algorithm: If you run panel.Layout() that relayouts only what’s in the panel, leaving the rest of the frame/dialog untouched.
Finally, panels serve a role in grouping radio buttons and tabbing.
Good, that can be a nice way of structuring your code. Even if perhaps you could have done without the panels and just run sizers the whole way through, that doesn’t mean the panels are a bad idea, if it keeps your code modular and managable.
Thanks for your explanation. I also found wx.Glade and experimented a bit with it. I now understood how to use Sizers in combination with the other objects.
With Java, if I want to create different layers of child objects, I add objects to Panels, and the layout manager is a property of the parent object that checks what properties the child has set to figure out how the layout has to look like (indirect layout).
With Python, the Sizer acts as its own object in the hierarchy. All objects need a sizer as a parent (except for the first panel within a Frame). The sizer manages the objects directly. It acts as an adapter for other child objects.
I can keep my panels as they are and just have to adjust the way I reach them in the hierarchy with the Sizers from the Frame downwards.
Frame->Sizer instead of Frame->Panel->Sizer is not recommended, especially if your program should ever run on Windows.
There without a panel, background colours will look odd and and keyboard navigation between widgets (using the Tab key) won’t work.
Strictly speaking, that’s not correct. You can omit sizers and place your widgets on frames and panels by pixel coordinates.
This used the way to do GUIs for a long time, but is no fun and certainly not recommended for the most cases. wxGlade only supports the sizer approach. Sometimes you might need pixel placement, but probably only if you place them by some own layout code.
For your requirements you probably can use wxGlade and use CustomWidget for your data display class. Have a look at the wxGlade manual and search for “Custom Widget”.
For drawing the connection lines you probably have to derive from the created frame class. You probably then can set the “Instance class” property to your own class.