How can I determine which child windows will be visible in a ScrolledWindow during/after a EVT_SCROLLED_WIN event?

80 views Asked by At

I'm building a panel for my application which contains a large number of thumbnail images; they won't all fit in the window, so I'm using a ScrolledWindow to hold them and allow the user to scroll to view them.

It takes some time to generate the thumbnail images, so I'm attempting to prioritize the production of the images for the thumbnails that are currently visible in the window. I'm also wanting to capture which thumbnails are visible so that if I add or remove a subset of the thumbnails I know where to position the scrollbar to include as many of the previously visible ones as possible.

The problem I'm having is that EVT_SCROLLWIN appears to be posted before the child windows are repositioned in the client area of the ScrolledWindow; in other words, I'm measuring the visible objects from before the scrollbar moved. Is there a way to: a) force the ScrolledWindow to update the child window positions, b) reliably determine what the new client window offset will be as compared to what it is now, or c) call the event handler after this update has occurred?

If it matters, I'm running Python 2.7.11 and wxPython 3.0.2.0 on this computer.

A code segment follows:

class ThumbsViewer(wx.ScrolledWindow):
    def __init__(self, parent, info, style = wx.BORDER_RAISED | wx.HSCROLL):
        wx.ScrolledWindow.__init__(self, parent = parent, id = wx.ID_ANY, size = wx.DefaultSize, 
                                   pos = wx.DefaultPosition, style = style, name = "ThumbsViewer")

        self.__info__ = info
        self.__bitmapctrls__ = []
        self.__selected__ = []
        self.__lastclicked__ = []

        self.Bind(wx.EVT_SCROLLWIN, self.__OnScroll__)

        # ... Code to generate placeholder thumbnails, arrange buttons, size window, etc. ...


    # ... Various functions to handle clicking on thumbnails, etc. ...


    # EVT_SCROLLWIN Handler - Measure client window positions and determine which are
    #                         visible on the screen.  
    def __OnScroll__(self, event):
        if event:
            event.Skip()

        priority = []
        clientsize = self.GetClientSize()

        for ctrl in self.__bitmapctrls__:
            pos = ctrl.GetPosition()
            size = ctrl.GetSize()

            # Test to see if any part of the thumbnail control falls within the client
            # area...append to the priority list if it does.

            # This appears to be where the problem is - the child window positions
            # have not been updated to reflect the new scrollbar position yet.

            if (((pos[0] >= 0 and pos[0] <= clientsize[0]) or (pos[0] + size[0] >= 0 and pos[0] + size[0] <= clientsize[0]))
                    and ((pos[1] >= 0 and pos[1] <= clientsize[1]) or (pos[1] + size[1] >= 0 and pos[1] + size[1] <= clientsize[1]))): 
                priority.append(ctrl.GetPage())

        self.__info__.SetPriorityPages(priority)
1

There are 1 answers

0
TPDMarchHare On BEST ANSWER

After struggling with this for a while, I decided to Bind EVT_PAINT instead of EVT_SCROLLWIN, and do my scroll bar checks when that occurs. The repaint happens after EVT_SCROLLWIN and the child window positions are updated.

I'm not super happy with this solution, because EVT_PAINT happens for a lot of reasons having nothing to do with the scroll bars, so please feel free to point out a better solution if you have one. Fortunately, in this case the computations fall through very quickly except when I'm adding or removing thumbnails (which doesn't occur on most paint events) so the performance hit is minimal.