Reputation: 16097
I'm new to wxPython, so please be gentle.
I'm attempting to make virtual list control that is controlled via a context menu popup when the user presses the right mouse button.
From my little bit of experience, it seems that the virtual list control likes to operate with "item" (read: 'row') and "column" numbers. Fair enough.
When I receive a right-click event, I can get the row (item) number easy enough by calling event.GetIndex(). But how do I get the column number of the object that was clicked?
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()
Upvotes: 0
Views: 3228
Reputation: 81
this works for me in a listctrl. it isn't perfect but it works. the only limitation is all the column on the left the one we want to select must be visible.
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()
Upvotes: 1
Reputation: 327
You can use event.GetColumn() from the EVT_LIST_COL_CLICK or EVT_LIST_COL_RIGHT_CLICK event handler. This returns the m_col value.
Upvotes: 0
Reputation: 3139
This works for a grid, might be easily adapted to a 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
Upvotes: 0
Reputation: 11
I don't know if you can get the column number in a listctrl when clicking a row (because it selects the entire row, not a single cell) ... however, if you want the number of the column when clicking on the column (like I did and after a lot of searches ended up here) you can bind an event (wx.EVT_LIST_COL_CLICK/wx.EVT_LIST_COL_RIGHT_CLICK) to your listctrl and in the event method use event.m_col ... it stores the column number there
self.Bind(wx.EVT_LIST_COL_CLICK, self.onColumnClick, self.myListCtrl)
...
def onColumnClick(self, evt):
column_clicked = evt.m_col
Got my inspiration from here: http://wxpython.org/Phoenix/docs/html/ListCtrl.html , at the 'Events Emitted by this Class' section
Upvotes: 1
Reputation: 33071
Sadly there is not a good way to get the column information. I did find this discussion on the matter though: http://wxpython-users.1045709.n5.nabble.com/Getting-row-col-of-selected-cell-in-ListCtrl-td2360831.html
It sounds like you'd have to calculate it yourself. According to Robin, there's some code in wx.lib.mixins.listctrl.TextEditMixin that might help. I also found the recipe for ObjectListView (a wrapper for ListCtrl) that also might help: http://code.activestate.com/recipes/577543-objectlistview-getcolumnclickedevent-handler/
Upvotes: 1
Reputation: 16097
"If at first you don't succeed, try again. Then quit; there's no use being a damn fool about it." -- Mark Twain
I'm embarrassed to admit that I wasted a week on this. To avoid others falling into this same trap, let me simplify things:
If you have a list of things, where each thing has sub-elements that you want to display together but are happy to operate on as a group, then a ListCtrl may work for you.
If you have a list of things, where each thing has sub-elements, but you're interested in operating on those sub-elements independently, ListCtrl appears to not be what you want.
I've started using the Grid widget, and so far it seems to be working for my purposes. This may come back to bite me later, but for now it seems to work. Here's some slightly modified code from the Wx Huge Grid demo to illustrate how a click on the grid widget will return both row and column "addresses".
If anyone has suggestions for how to get the column numbers from ListCtrl, I'm certainly all ears.
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()
Upvotes: 1