wxPython 201: Syncing Scrolling Between Two Grids

This week I saw a question on StackOverflow about putting two grids into a SplitterWindow which itself was in a Notebook page. Personally I think that’s a little convoluted, but I thought it was an interesting challenge and I came up with a solution. Then the fellow wanted to know how to sync the scrolling of the two grids. Well, I found an answer and modified my code and decided it was worth writing an article about. Here is a screenshot of the finished result:

wxScrollGrid

Yes, for some reason the person who wanted this also wanted a panel below the two grids. I think it’s a bit ugly, especially with the pink background, but to each their own. Let’s take a look at the code:

import wx
import wx.grid as gridlib
 
class ScrollSync(object):
    def __init__(self, panel1, panel2):
        self.panel1 = panel1
        self.panel2 = panel2
        self.panel1.grid.Bind(wx.EVT_SCROLLWIN, self.onScrollWin1)
        self.panel2.grid.Bind(wx.EVT_SCROLLWIN, self.onScrollWin2)
 
    def onScrollWin1(self, event):
        if event.Orientation == wx.SB_HORIZONTAL:
            self.panel2.grid.Scroll(event.Position, -1)
        else:
            self.panel2.grid.Scroll(-1, event.Position)
        event.Skip()
 
    def onScrollWin2(self, event):
        if event.Orientation == wx.SB_HORIZONTAL:
            self.panel1.grid.Scroll(event.Position, -1)
        else:
            self.panel1.grid.Scroll(-1, event.Position)
        event.Skip()
 
########################################################################
class RegularPanel(wx.Panel):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.SetBackgroundColour("pink")
 
 
########################################################################
class GridPanel(wx.Panel):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.grid = gridlib.Grid(self, style=wx.BORDER_SUNKEN)
        self.grid.CreateGrid(25,8)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid, 1, wx.EXPAND)
        self.SetSizer(sizer)
 
 
########################################################################
class MainPanel(wx.Panel):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
 
        notebook = wx.Notebook(self)
 
        page = wx.SplitterWindow(notebook)
        notebook.AddPage(page, "Splitter")
        hSplitter = wx.SplitterWindow(page)
 
        panelOne = GridPanel(hSplitter)
        panelTwo = GridPanel(hSplitter)
        ScrollSync(panelOne, panelTwo)
 
        hSplitter.SplitVertically(panelOne, panelTwo)
        hSplitter.SetSashGravity(0.5)
 
        panelThree = RegularPanel(page)
        page.SplitHorizontally(hSplitter, panelThree)
        page.SetSashGravity(0.5)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.EXPAND)
        self.SetSizer(sizer)
 
########################################################################
class MainFrame(wx.Frame):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Nested Splitters",
                          size=(800,600))
        panel = MainPanel(self)
        self.Show()
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

The piece we care about most is the ScrollSync class. It accepts the two panels that the grids are on as arguments. We then bind the grids to wx.EVT_SCROLLWIN and then during that event, we change the position of the opposite grid. Now this code has several limitations. It only works when you are physically moving the scrollbars with your mouse. If you use the mouse’s scroll wheel, the arrow keys or Page up/down, then the two grids no longer sync. I attempted to add mouse wheel support via the wx.EVT_MOUSEWHEEL event, but it doesn’t provide Orientation or Position in the same way as EVT_SCROLLWIN does. In fact, its Position is a wx.Point whereas EVT_SCROLLWIN returns an Integer. Adding those bits of functionality would be fun, but they are outside the scope of this article.

This code should get you started on your way in getting the syncing working though. I also found a couple of other articles related to this subject that you might find helpful should you need to sync scrolling up in a couple of widgets:

The post wxPython 201: Syncing Scrolling Between Two Grids appeared first on The Mouse Vs. The Python.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>