One custom wx.frame is created to contain a splitter window with two grid controls inside. It's used to compare the data in each of the grid. At this point the scrollbar of two grids need to support sync scroll.
Questions:
- How to get these two grid's scroll event? I have tried to bin the wx.EVT_SCROLL event at the frame but failed. I also try to bind the scroll event in the custom grid control, it's failed too.
- How to sync scroll the scrollbar of the two grids? An answer of a relative question mentioned to use gridInstance.Scroll(row, col) to scroll the grid client window. But it doesn't contain how to sync the scrollbar.
Many thanks for any suggestion.
The init method of the custom frame
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, title='', size=(640,480))
main_panel = wx.Panel(self, -1)
self.TBFLAGS = ( wx.TB_HORIZONTAL| wx.NO_BORDER| wx.TB_FLAT)
self.controller = None
self.isSyncScroll = True
#hsizer = wx.BoxSizer(wx.VERTICAL)
gsizer = wx.FlexGridSizer(rows = 1,
cols = 1,
vgap = 2,
hgap = 2)
gsizer.AddGrowableRow(0)
gsizer.AddGrowableCol(0)
self.tb = self.init_toolbar()
(sub_panel0, sub_panel1) = self.init_splitter(main_panel)
self.grid0 = self.init_grid(sub_panel0)
self.grid1 = self.init_grid(sub_panel1)
self.init_status_bar()
gsizer.Add(main_panel, 1, wx.EXPAND)
self.SetSizer(gsizer)
ico = wx.Icon(u'Compare.ico', wx.BITMAP_TYPE_ICO)
self.SetIcon(ico)
self.Maximize()
#can't catch the scroll event at the frame
self.Bind(wx.EVT_SCROLL, self.OnScroll, self.grid0)
#self.Bind(wx.EVT_SCROLL, self.OnScroll)
#self.Bind(wx.EVT_SCROLL, self.OnScroll, id=self.grid0.GetId())
The following code gets 2 scrollbars moving together when you grab one or the other.
Python version 2.7.3 & wxpython 2.9.4.0 & windows Xp.
import wx
import wx.grid as grid
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Grid", size=(350, 250))
self.grid = grid.Grid(self)
self.grid.CreateGrid(20, 20)
class ScrollSync(object):
def __init__(self, frame1, frame2):
self.frame1 = frame1
self.frame2 = frame2
self.frame1.grid.Bind(wx.EVT_SCROLLWIN, self.onScrollWin1)
self.frame2.grid.Bind(wx.EVT_SCROLLWIN, self.onScrollWin2)
def onScrollWin1(self, event):
if event.Orientation == wx.SB_HORIZONTAL:
self.frame2.grid.Scroll(event.Position, -1)
else:
self.frame2.grid.Scroll(-1, event.Position)
event.Skip()
def onScrollWin2(self, event):
if event.Orientation == wx.SB_HORIZONTAL:
self.frame1.grid.Scroll(event.Position, -1)
else:
self.frame1.grid.Scroll(-1, event.Position)
event.Skip()
if __name__ == '__main__':
app = wx.App()
frame1 = Frame(None)
frame1.Show()
frame2 = Frame(None)
frame2.Show()
ScrollSync(frame1, frame2)
app.MainLoop()
Here is another version that uses a timer to check and set scroll positions, so it cover any type of scroll change.
import wx
import wx.grid as grid
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Grid", size=(350, 250))
self.grid = grid.Grid(self)
self.grid.CreateGrid(20, 20)
class ScrollSync(wx.EvtHandler):
def __init__(self, frame1, frame2):
super(ScrollSync, self).__init__()
self.frame1 = frame1
self.frame2 = frame2
self.frame1ScrollPos = self.getFrame1Pos()
self.frame2ScrollPos = self.getFrame2Pos()
self.Bind(wx.EVT_TIMER, self.onTimer)
self.timer = wx.Timer(self)
self.timer.Start(20)
def onTimer(self, event):
if not self.frame1 or not self.frame2:
self.timer.Stop()
return
if self.frame1ScrollPos != self.getFrame1Pos():
self.frame1ScrollPos = self.getFrame1Pos()
self.frame2.grid.Scroll(self.frame1ScrollPos)
elif self.frame2ScrollPos != self.getFrame2Pos():
self.frame2ScrollPos = self.getFrame2Pos()
self.frame1.grid.Scroll(self.frame2ScrollPos)
def getFrame1Pos(self):
horizontal = self.frame1.grid.GetScrollPos(wx.SB_HORIZONTAL)
vertical = self.frame1.grid.GetScrollPos(wx.SB_VERTICAL)
return horizontal, vertical
def getFrame2Pos(self):
horizontal = self.frame2.grid.GetScrollPos(wx.SB_HORIZONTAL)
vertical = self.frame2.grid.GetScrollPos(wx.SB_VERTICAL)
return horizontal, vertical
if __name__ == '__main__':
app = wx.App()
frame1 = Frame(None)
frame1.Show()
frame2 = Frame(None)
frame2.Show()
ScrollSync(frame1, frame2)
app.MainLoop()