使用FreezeTo冻结wx.Grid列时单元格错位、HOME键行为异常问题及解决方案
上下文
我使用FreezeTo方法在wx.grid.Grid中实现了列冻结功能,相关初始化代码如下:
def __init__(self, parent): # 相关代码行 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)
使用标准标签渲染器*的前提下,冻结功能本身运行正常,我设置的前几列冻结列会始终保持可见,手动拖动水平滚动条也没有问题。
- 我最初使用的是
wx.lib.mixins.gridlabelrenderer下的GridWithLabelRenderersMixin,但它会彻底破坏列标签宽度和列宽的一致性,我可以使用标准渲染器,所以这个问题影响不大。
我遇到了几个问题,目前均已解决,详情如下:
冻结列的单元格或标签位置捕获(已解决)
对于冻结列的单元格区域,可通过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) # 可根据获取到的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) # 可根据获取到的col执行对应操作
非冻结列的标签或单元格鼠标位置偏移(已解决)
非冻结列的标签或单元格的有效位置会偏移所有冻结列的总宽度,该问题可以在调用YToRow或XToCol方法前对坐标进行偏移修正即可解决,位置修正的代码示例如下:
class Report(wx.Panel): def _freeze_x_shit(self): """返回列冻结导致的水平位置偏移量""" 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() # 网格表头 if widget == self.grid.GetGridColLabelWindow(): x = event.GetX() y = event.GetY() x += self._freeze_x_shit() # <-- 此处执行位置修正 col = self.grid.XToCol(x, y) # 可根据获取到的col执行网格相关处理 # 网格单元格 elif widget == self.grid.GetGridWindow(): (x, y) = self.grid.CalcUnscrolledPosition(event.GetX(), event.GetY()) x += self._freeze_x_shit() # <-- 此处执行位置修正 row = self.grid.YToRow(y) col = self.grid.XToCol(x) # 可根据获取到的row、col执行网格单元格相关处理 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): """重映射HOME键,让网格可以像无冻结列时一样滚动到最左侧 :param event: 网格上触发的wx.EVT_KEY_DOWN事件 :return: """ key_code = event.GetKeyCode() if key_code == wx.WXK_HOME: self.grid.Scroll(0, -1) event.Skip()
内容的提问来源于stack exchange,提问作者Olivier
相关产品推荐
相关产品推荐

