【问题标题】:Obtaining Column number from wxPython ListCtrl/UltimateListCtrl in Virtual mode在虚拟模式下从 wxPython ListCtrl/UltimateListCtrl 获取列号
【发布时间】:2012-07-28 08:00:21
【问题描述】:

我是 wxPython 的新手,所以请温柔一点。

我正在尝试制作虚拟列表控件,当用户按下鼠标右键时,该控件通过上下文菜单弹出来控制。

根据我的一点点经验,虚拟列表控件似乎喜欢使用“项目”(阅读:“行”)和“列”数字进行操作。很公平。

当我收到一个右键单击事件时,我可以通过调用 event.GetIndex() 轻松获取行(项目)编号。但是如何获取被点击对象的列号呢?

import wx
import wx.lib.agw.ultimatelistctrl as ULC

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Right-click example")
        self.list = MyListCtrl(parent=self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.list, 1, wx.EXPAND)
        self.SetSizer(sizer)

class MyListCtrl(ULC.UltimateListCtrl):
     def __init__(self, parent, *args, **kwargs):
         ULC.UltimateListCtrl.__init__(self, parent, 1, agwStyle=wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)

        self.InsertColumn(0, "Column0")
        self.InsertColumn(1, "Column1")
        self.SetItemCount(5)
        # Bindings
        self.Bind(ULC.EVT_LIST_ITEM_RIGHT_CLICK, self.OnRightClick)

    def OnGetItemText(self, item, column):
        return "%d, %d" % (item, column)

    def OnGetItemToolTip(self, item, column):
        pass

    def OnGetItemTextColour(self, item, column):
        pass

    def OnRightClick(self, event):
        # Get the index (i.e. which row was clicked)
        print("OnColRightClick: GetIndex = %r\n" %(event.GetIndex()))
        # How can I get which column was clicked?

if __name__ == "__main__":
    # Start the GUI
    app = wx.App()
    frame = MyFrame()
    app.SetTopWindow(frame)
    frame.Show()
    app.MainLoop()

【问题讨论】:

  • 有趣的是,有一个 GetColumn() 方法,但文档指出它仅适用于特殊事件(如列拖动),无论我右键单击哪一列,它都会始终为我返回 0

标签: python wxpython


【解决方案1】:

遗憾的是,没有获取列信息的好方法。不过,我确实找到了关于此事的讨论:http://wxpython-users.1045709.n5.nabble.com/Getting-row-col-of-selected-cell-in-ListCtrl-td2360831.html

听起来您必须自己计算。根据 Robin 的说法,wx.lib.mixins.listctrl.TextEditMixin 中有一些代码可能会有所帮助。我还找到了 ObjectListView(ListCtrl 的包装器)的配方,它也可能有所帮助:http://code.activestate.com/recipes/577543-objectlistview-getcolumnclickedevent-handler/

【讨论】:

    【解决方案2】:

    “如果一开始没有成功,请再试一次。 然后退出;做一个该死的傻瓜是没有用的。”——马克吐温

    我很尴尬地承认我在这件事上浪费了一个星期。为了避免其他人陷入同样的​​陷阱,让我简化一下:

    如果您有一个事物列表,其中每个事物都有您想要一起显示但乐于作为一个组进行操作的子元素,那么 ListCtrl 可能适合您。

    如果您有一个事物列表,其中每个事物都有子元素,但您有兴趣独立操作这些子元素,ListCtrl 似乎不是你想要的。

    我已经开始使用 Grid 小部件,到目前为止,它似乎可以满足我的目的。这可能会在以后回来咬我,但现在它似乎有效。这是来自 Wx Huge Grid 演示的一些稍作修改的代码,用于说明单击网格小部件如何返回行和列“地址”。

    如果有人对如何从 ListCtrl 获取列号有任何建议,我当然会全力以赴。

    import  wx
    import  wx.grid as  gridlib
    
    #---------------------------------------------------------------------------
    class HugeTable(gridlib.PyGridTableBase):
        def __init__(self, log):
            gridlib.PyGridTableBase.__init__(self)
            self.log = log
    
            self.odd=gridlib.GridCellAttr()
            self.odd.SetBackgroundColour("sky blue")
            self.even=gridlib.GridCellAttr()
            self.even.SetBackgroundColour("sea green")
    
        def GetAttr(self, row, col, kind):
            attr = [self.even, self.odd][row % 2]
            attr.IncRef()
            return attr
    
        # This is all it takes to make a custom data table to plug into a
        # wxGrid.  There are many more methods that can be overridden, but
        # the ones shown below are the required ones.  This table simply
        # provides strings containing the row and column values.
    
        def GetNumberRows(self):
            return 10000
    
        def GetNumberCols(self):
            return 10000
    
        def IsEmptyCell(self, row, col):
            return False
    
        def GetValue(self, row, col):
            return str( (row, col) )
    
        def SetValue(self, row, col, value):
            self.log.write('SetValue(%d, %d, "%s") ignored.\n' % (row, col, value))
    
    #---------------------------------------------------------------------------
     class HugeTableGrid(gridlib.Grid):
        def __init__(self, parent, log):
            gridlib.Grid.__init__(self, parent, -1)
    
            table = HugeTable(log)
    
            # The second parameter means that the grid is to take ownership of the
            # table and will destroy it when done.  Otherwise you would need to keep
            # a reference to it and call it's Destroy method later.
            self.SetTable(table, True)
    
            self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick)
    
        def OnCellRightClick(self, event):
            print "OnCellRightClick: (%d,%d)\n" % (event.GetRow(), event.GetCol())
    
    #---------------------------------------------------------------------------
     class TestFrame(wx.Frame):
        def __init__(self, parent, log):
            wx.Frame.__init__(self, parent, -1, "Huge (virtual) Table Demo", size=(640,480))
            grid = HugeTableGrid(self, log)
    
            grid.SetReadOnly(5,5, True)
    
    #---------------------------------------------------------------------------
    if __name__ == '__main__':
        import sys
        app = wx.App()
        frame = TestFrame(None, sys.stdout)
        frame.Show(True)
        app.MainLoop()
    

    【讨论】:

    • 由于 ListCtrl 不想给我列引用,我移动到“虚拟”网格(继续使用 ListCtrl 中使用的“虚拟”命名法;即只显示数据,不显示由 wx 对象持有。网格对象称之为“外部表”)。 Grid 很容易为我提供列引用,但我在 ListCtrl 中认为理所当然的其他事情(例如自动调整行标签大小)需要类似的自定义代码。用于获取列号的自定义代码或用于自动调整标签大小的自定义代码......选择你的毒药。
    【解决方案3】:

    我不知道单击一行时是否可以在 listctrl 中获取列号(因为它选择整行,而不是单个单元格)...但是,如果您想要单击时的列号在列上(就像我所做的那样,经过大量搜索后,您可以将事件(wx.EVT_LIST_COL_CLICK/wx.EVT_LIST_COL_RIGHT_CLICK)绑定到您的 listctrl 并在事件方法中使用 event.m_col ...它存储列那里的号码

        self.Bind(wx.EVT_LIST_COL_CLICK, self.onColumnClick, self.myListCtrl)
    ...
    def onColumnClick(self, evt):
        column_clicked = evt.m_col
    

    我的灵感来自这里:http://wxpython.org/Phoenix/docs/html/ListCtrl.html,在“此类发出的事件”部分

    【讨论】:

    • 感谢您的提示!我会在下一个项目中尝试一下。
    【解决方案4】:

    这在 listctrl 中对我有用。它并不完美,但它有效。 唯一的限制是我们要选择的左侧的所有列都必须可见。

    self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
    self.col=-1
    ....
    
    def OnDoubleClick(self, event):
        posx=event.GetX()
        self.col=-1
        while posx>0:
            self.col+=1
            posx=posx-self.GetColumnWidth(self.col)        
        event.Skip()
    

    【讨论】:

      【解决方案5】:

      这适用于网格,可能很容易适应 ListCtrl:

      def onclick(self,event):
          rows = cumsum(self.GetRowSize(i) for i in range(self.GetNumberRows()))
          cols = cumsum(self.GetColSize(i) for i in range(self.GetNumberCols()))
          irow = self.GetNumberRows() - sum(event.m_y < y for y in rows)
          icol = self.GetNumberCols() - sum(event.m_x < x for x in cols)
          print irow,icol
      

      【讨论】:

        【解决方案6】:

        您可以使用 EVT_LIST_COL_CLICK 或 EVT_LIST_COL_RIGHT_CLICK 事件处理程序中的 event.GetColumn()。这将返回 m_col 值。

        【讨论】:

          猜你喜欢
          • 2012-07-05
          • 1970-01-01
          • 1970-01-01
          • 2013-08-11
          • 1970-01-01
          • 1970-01-01
          • 2011-09-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多