wx中如何同步两个网格的滚动条

2022-01-18 00:00:00 python scrollbar grid wxwidgets sync

问题描述

创建一个自定义 wx.frame 以包含一个拆分器窗口,其中包含两个网格控件.它用于比较每个网格中的数据.此时两个网格的滚动条需要支持同步滚动.

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.

问题:

  1. 如何获取这两个网格的滚动事件?我试图在框架上绑定 wx.EVT_SCROLL 事件但失败了.我也尝试在自定义网格控件中绑定滚动事件,也失败了.
  2. 如何同步滚动两个网格的滚动条?提到使用 gridInstance.Scroll 的相对 问题 的答案(row, col) 滚动网格客户端窗口.但它不包含如何同步滚动条.
  1. 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.
  2. 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.

自定义框架的init方法

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())


解决方案

当你抓住一个或另一个时,下面的代码让 2 个滚动条一起移动.

The following code gets 2 scrollbars moving together when you grab one or the other.

Python 版本 2.7.3 &wxpython 2.9.4.0 &Windows XP.

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()

相关文章