1

By using the accepted solution from ScrolledPanel with vertical scrollbar only and WrapSizer, here is a way of putting some custom MyControl into WrapSizer with a vertical scrollbar :

Unfortunately, the items that are not drawn at startup won't draw later, even after moving the scrollbar. Here only the first 9 buttons (among 20) are drawn :

import wx
import wx.lib.scrolledpanel as scrolled

class MyControl(wx.PyControl):
    def __init__(self, parent, i):
        wx.PyControl.__init__(self, parent, wx.ID_ANY, wx.DefaultPosition, size=(100,100)) 
        wx.Button(self, wx.ID_ANY, "btn %d" % i, (0,0), (50,50), 0)
        # some other things here 

class MyPanel(scrolled.ScrolledPanel):
    def __init__(self, parent):
        scrolled.ScrolledPanel.__init__(self, parent, style=wx.VSCROLL)
        self.sizer = wx.WrapSizer()
        self.SetupScrolling(scroll_x = False)
        for i in range(1, 20):
            btn = MyControl(self, i)
            self.sizer.Add(btn, 0, wx.ALL, 10)
        self.SetSizer(self.sizer)
        self.Bind(wx.EVT_SIZE, self.onSize)

    def onSize(self, evt):
        size = self.GetSize()
        vsize = self.GetVirtualSize()
        self.SetVirtualSize((size[0], vsize[1]))        

app = wx.App(redirect=False)
frame = wx.Frame(None, size=(400,400))
MyPanel(frame)
frame.Show()
app.MainLoop()

How to correctly draw all the items in such a WrapSizer ?


enter image description here

Community
  • 1
  • 1
Basj
  • 41,386
  • 99
  • 383
  • 673

3 Answers3

1

It's very suspicious to use both sizers and explicit wxEVT_SIZE handler. Basically, your sizer is not used at all. Remove your size event handler and check what happens.

VZ.
  • 21,740
  • 3
  • 39
  • 42
  • Both seem to be needed (see accepted answer on http://stackoverflow.com/questions/21431366/scrolledpanel-with-vertical-scrollbar-only-and-wrapsizer), or maybe do you see another solution for this question without it ? – Basj Jan 29 '14 at 21:24
  • That answer is different in one crucial aspect: it calls `evt.Skip()`, making it possible for the sizer to work. Your code doesn't do it, so the sizer is not used at all. – VZ. Jan 30 '14 at 04:48
  • I checked with adding `evt.Skip()` in the `EVT_SIZE` handler but it doesn't change anything. I also tried by completement removing the size event handler, and it doesn't change as well... – Basj Jan 30 '14 at 08:17
1

I tried using a sizer in the MyControl class and all the buttons were displayed:

class MyControl(wx.PyControl):
    def __init__(self, parent, i):
    wx.PyControl.__init__(self, parent, wx.ID_ANY, wx.DefaultPosition, size=(100,100))

    # Just saving the button in a variable
    btn = wx.Button(self, wx.ID_ANY, "btn %d" % i, (0,0), (50,50), 0)

    # Creating sizer and placing the button in sizer
    sizer = wx.BoxSizer()
    sizer.Add(btn)
    self.SetSizer(sizer)

You can mess around with the sizer arguments to make them fill up the space how you want it. Is this the type of solution you were looking for?

RandomGuy
  • 419
  • 4
  • 14
  • Thank you @Daniel, it works ! But then I wanted to put some `StaticText` at some precise position in the `MyControl` : `txt1 = wx.StaticText(self, -1, 'blah', (6,160))` and `txt2 = wx.StaticText(self, -1, 'blah2', (6,180))`... Now we see that I should add them in the sizer that you created. Is it possible to add them in the sizer *AND* keep my own positionning ((6,160) and (6,180)) ? – Basj Jan 30 '14 at 08:21
  • @Basj I do not think that is possible, since sizers are not meant to use positioning like (x,y). How do you want your widgets to look like? With sizers you can pretty much do the same things as using coordinates like how you want. – RandomGuy Jan 30 '14 at 20:18
1

Solution:

Add another panel into the Sizer of "MyControl".

You can put the button and text into this panel as you like.

class MyControl(wx.PyControl):
    def __init__(self, parent, i):
        wx.PyControl.__init__(self, parent, wx.ID_ANY, wx.DefaultPosition, size=(100,100))

        panel = wx.Panel(self)
        btn  =  wx.Button(panel, wx.ID_ANY, "btn %d" % i, (0,0), (50,50), 0)
        txt1 = wx.StaticText(panel, -1, 'blah', (50,50))
        txt2 = wx.StaticText(panel, -1, 'blah2', (50,80))
        sizer = wx.BoxSizer()
        sizer.Add(panel)
        self.SetSizer(sizer)
Jerry_Y
  • 1,724
  • 12
  • 9
  • Nice solution indeed ! It works ! But then we have a `StaticText` inside a `Panel` inside a `sizer` inside a `PyControl` inside a `WrapSizer` inside the `ScrollPanel` inside the `Frame` ! Don't you think there is sampler solution ? – Basj Jan 30 '14 at 15:42
  • I'm new to python, I have no idea how to make it simpler :) But compare to previous solution, there is only one additional panel added to make all this work. – Jerry_Y Jan 30 '14 at 16:15
  • I accepted Daniel's answer because he was the first to answer on adding a extra sizer, but if I could set 2 answers as "accepted answer", I would do it with yours too @Jerry_Y ! Thanks for this solution – Basj Jan 30 '14 at 20:30
  • It's ok. I feel glad that my answer is helpful. – Jerry_Y Jan 31 '14 at 13:53