Psionman
Psionman

Reputation: 3677

wx python how to place panels in a sizer

I have an app in which I want to use one panel to hold images that I can drag and drop, and one that will hold various controls

I cannot make the image panel display correctly:

import  wx

class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          'Display panels',
                            size=(900, 700))
        sizer = wx.GridBagSizer()
        image_panel = ImagePanel(self)
        sizer.Add(image_panel, pos=(1, 2))
        #self.SetSizer(sizer)
        self.Centre()
        self.Show()

class ImagePanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.Bind(wx.EVT_PAINT, self.on_paint)

    def on_paint(self, event):
        dc = wx.PaintDC(self)
        dc.Clear()
        self.PrepareDC(dc)
        dc = wx.PaintDC(self)
        dc.SetPen(wx.Pen(wx.BLACK, 4))
        dc.DrawLine(0, 0, 500, 500)

if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

If the SetSizer line is commented out it works; if it's not commented, it just appears as a small box in top-left

Can anyone help please?

Upvotes: 1

Views: 1351

Answers (2)

Mike Driscoll
Mike Driscoll

Reputation: 33071

The key is to have a single panel that is the ONLY child widget of the frame. Then you add your other panels as children of that top-level panel.

Now, I prefer using wx.BoxSizer over wx.GridBagSizer, although I'm sure you could make it work. Anyway, for this example, I will use the BoxSizer:

import  wx

class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          'Display panels',
                            size=(900, 700))
        main_panel = wx.Panel(self)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        image_panel = ImagePanel(main_panel)
        sizer.Add(image_panel, 1, wx.EXPAND|wx.ALL, 5)
        
        # Add your control panel here
        
        main_panel.SetSizer(sizer)
        self.Centre()
        self.Show()

class ImagePanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.Bind(wx.EVT_PAINT, self.on_paint)

    def on_paint(self, event):
        dc = wx.PaintDC(self)
        dc.Clear()
        self.PrepareDC(dc)
        dc = wx.PaintDC(self)
        dc.SetPen(wx.Pen(wx.BLACK, 4))
        dc.DrawLine(0, 0, 500, 500)

if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

As you can see, when we add the ImagePanel to the sizer, I also pass in the proportion it should be, 1, which means that the ImagePanel should take up 100% of the space. I also pass the wx.EXPAND flag which tells wxPython to expand that widget to fill the space.

You can do something similar with GridBagSizer, but you will need to make the widget cross cell boundaries, and frankly, I find it a bit of a pain. You are welcome to dig into the documentation though if you really want to use that sizer.

Upvotes: 1

vdaghan
vdaghan

Reputation: 16

ImagePanel seems to need a fixed size, maybe modified per image shown/drawn, but nothing dynamic. So if the child panel has fixed size, wx.FIXED_MINSIZE option for wx.Sizer.Add accomplishes what is needed.

(Obviously this answer does not help OP after years, but I would have a better day if someone posted about this obscure setting -which should've been the default behaviour IMO-)

Upvotes: 0

Related Questions