使用 FreezeTo 冻结 wx.Grid 列时出现的问题:网格中的单元格位置错误,以及 HOME 键盘键行为

问题描述

背景

我使用 wx.grid.Grid 方法Freezeto 中设置了列冻结。

    def __init__(self,parent):
        # relevant lines
        self.grid = wx.grid.Grid(self.sBox_grid,size=(1000,800))
        self.grid.CreateGrid(self.row_number,self.col_number)
        self.grid.Freezeto(0,self.frozen_column_number)

只要我保留标准标签渲染器 (*),就可以很好地进行冻结。 我冻结的前几列始终保持可见,手动移动水平滚动条也可以。

(*) 我最初使用 GridWithLabelRenderersMixinwx.lib.mixins.gridlabelrenderer,但它完全破坏了列标签宽度和列宽之间的一致性。反正我可以处理标准渲染器,所以这不是问题。

我遇到了几个问题,现在都解决了,详情如下。

捕获冻结列的单元格位置:单元格或标签(已解决

对于单元格,可以使用 GetFrozenColGridWindow 捕获窗口。

所以鼠标悬停可以简单地完成:

    if widget == self.grid.GetFrozenColGridWindow():
        (x,y) = self.grid.CalcUnscrolledPosition(event.GetX(),event.GetY())
        row = self.grid.YToRow(y)
        col = self.grid.XToCol(x)
        # do whatever your want with row,col

对于标签,窗口存在但不能通过方法访问。 网格上有一个 GetChildren,我发现它是列表的最后一个(对应于最新定义的)。

所以它不是很可靠,但对于缺少的 GetGridFrozenColLabelWindow 方法来说是一个相对较好的占位符。

    wlist = self.grid.GetChildren()
    frozen_col_label_window = wlist[-1]
    if widget == frozen_col_label_window:
        x = event.GetX()
        y = event.GetY()
        col = self.grid.XToCol(x,y)
        # do stuff with col

鼠标位置从非冻结列(标签或单元格)移动(已解决

非冻结列标签或单元格的有效位置从所有冻结列的总宽度偏移。

这一点很容易通过位置转移来处理,在调用 YToRowXToCol 方法之前计算。

以下代码显示了位置更正:

class Report(wx.Panel):

    def _freeze_x_shit(self):
        """Returns the horizontal position offset induced by columns freeze"""
        offset = 0
        for col in range(self.frozen_column_number):
            offset += self.grid.GetColSize(col)
        return offset

    def on_mouse_over(self,event):
        widget = event.GetEventObject()
        
        # grid header
        if widget == self.grid.GetGridColLabelWindow():
            x = event.GetX()
            y = event.GetY()
            x += self._freeze_x_shit()  # <-- position correction here
            col = self.grid.XToCol(x,y)
            # do whatever grid processing using col value

        # grid cells
        elif widget == self.grid.GetGridWindow():
            (x,event.GetY())
            x += self._freeze_x_shit()  # <-- and also here
            row = self.grid.YToRow(y)
            col = self.grid.XToCol(x)
            # do whatever grid cell processing using row and col values

        event.Skip()

HOME 键盘键无法按预期工作(已解决

我通常使用 HOME 键立即移动到网格的最左侧,使用 END 键移动到最右侧。这是非冻结网格的正常行为。

END 键完成其工作,但 HOME 键不起作用。

在任何网格单元上按下 HOME 时,我得到了两个效果

  • 选中的单元格成为第一列:没问题
  • 但滚动条位置根本没有改变:我希望滚动位置完全离开

我已经通过使用 EVT_KEY_DOWN 事件的简单重新映射更正了它:

    def __init__(self,parent):
        self.grid.Bind(wx.EVT_KEY_DOWN,self.on_key_event)

        def on_key_event(self,event):
            """Remap the HOME key so it scrolls the grid to the left,as it did without the frozen columns

            :param event: wx.EVT_KEY_DOWN event on the grid
            :return:
            """
            key_code = event.GetKeyCode()
            if key_code == wx.WXK_HOME:
                self.grid.Scroll(0,-1)

            event.Skip()

解决方法

我关于网格中列冻结的 3 个问题现已解决。我已经用我的解决方案编辑了我的初始帖子。