Editing fields in a wxListCtrl

I thought that was really cool and would like to edit all the fields
of a selected line in place rather than creating a new frame. I was
able to duplicate editing the label in place in my application but was
unable to figure out how to edit the other fields of the line in a
similar fashion. Is this possible? I'm using wxPython-2.4.

Gary, it is only possible to edit the first field of the ListCtrl using the
native capabilities of the ListCtrl widget. However, it is not that
difficult to catch the raw mousedown event and put up a text widget in the
appropriate row/column that looks very similar to the built in textctrl of
the ListCtrl. The performance is surprisingly fast.

The following is pseudocode but will give you an idea of what can be done.

(Note self.editor is just a simple textctrl with style wx.TE_PROCESS_ENTER)

wx.EVT_TEXT_ENTER(self, self.editor.GetId(), self.CloseEditor)
wx.EVT_KILL_FOCUS(self.editor, self.CloseEditor)

def OnLeftDown(self, evt=None):
        
    x,y = evt.GetPosition()
    row,flags = self.LCtrl.HitTest((x,y))

    if row != self.curRow: # self.curRow keeps track of the current row
        evt.Skip()
        return
        
    if x < self.LCtrl.GetColumnWidth(0):
        self.DisplayEditor(row, 0)
    elif x < self.LCtrl.GetColumnWidth(0) + self.LCtrl.GetColumnWidth(1):
        self.DisplayEditor(row, 1)

   ...

def DisplayEditor(self, row, col):

    x0 = X0 + sum([self.LCtrl.GetColumnWidth(x) for x in range(col)])
    x1 = X1 + self.LCtrl.GetColumnWidth(col)
    y0 = Y0 + self.LCtrl.GetItemPosition(row)[1]
    y2 = 23 # determined by font size of ListCtrl

    # note that in reality the 'adjustment factors'
    # can be determined empirically.
     
    editor = self.editor
    editor.SetDimensions(x0,y0,x1,y1)
    editor.SetValue(self.LCtrl.GetItem(row, col).GetText())
    editor.Show()
    editor.Raise()
    editor.SetSelection(-1,-1)
    editor.SetFocus()

    self.curRow = row
    self.curCol = col

def CloseEditor(self, evt=None):
    text = self.editor.GetValue()
    self.editor.Hide()
    self.LCtrl.SetStringItem(self.curRow, self.curCol, text)

···

-------------------------------------------------------

Hope this helps,

Steve

<snip ...>

Thanks for helping me out. Sorry for being such a newbie, but I'm
having trouble implementing your code.

I tried getting to OnLeftDown() with a line like

EVT_LIST_BEGIN_LABEL_EDIT(self.myList, ID_list, self.OnBeginEdit)
or
EVT_LIST_ITEM_SELECTED(self.myList, ID_list, self.OnBeginEdit)

In both cases, I get 'AttributeError: GetPosition' on the line

x,y = evt.GetPosition()

Am I using the wrong EVT line? Or is it a problem that I'm using
wxPython version 2.4?

Gary

···

On Sun, 25 Apr 2004 15:24:45 -0400 "Zatz, Steve" <SZatz@webmd.net> wrote:

>I thought that was really cool and would like to edit all the fields
>of a selected line in place rather than creating a new frame. I was
>able to duplicate editing the label in place in my application but
>was unable to figure out how to edit the other fields of the line in
>a similar fashion. Is this possible? I'm using wxPython-2.4.

Gary, it is only possible to edit the first field of the ListCtrl
using the native capabilities of the ListCtrl widget. However, it is
not that difficult to catch the raw mousedown event and put up a text
widget in the appropriate row/column that looks very similar to the
built in textctrl of the ListCtrl. The performance is surprisingly
fast.

The following is pseudocode but will give you an idea of what can be
done.

(Note self.editor is just a simple textctrl with style
wx.TE_PROCESS_ENTER)

wx.EVT_TEXT_ENTER(self, self.editor.GetId(), self.CloseEditor)
wx.EVT_KILL_FOCUS(self.editor, self.CloseEditor)

def OnLeftDown(self, evt=None):
        
    x,y = evt.GetPosition()
    row,flags = self.LCtrl.HitTest((x,y))

    if row != self.curRow: # self.curRow keeps track of the current
    row
        evt.Skip()
        return
        
    if x < self.LCtrl.GetColumnWidth(0):
        self.DisplayEditor(row, 0)
    elif x < self.LCtrl.GetColumnWidth(0) +
    self.LCtrl.GetColumnWidth(1):
        self.DisplayEditor(row, 1)

   ...

def DisplayEditor(self, row, col):

    x0 = X0 + sum([self.LCtrl.GetColumnWidth(x) for x in range(col)])
    x1 = X1 + self.LCtrl.GetColumnWidth(col)
    y0 = Y0 + self.LCtrl.GetItemPosition(row)[1]
    y2 = 23 # determined by font size of ListCtrl

    # note that in reality the 'adjustment factors'
    # can be determined empirically.
     
    editor = self.editor
    editor.SetDimensions(x0,y0,x1,y1)
    editor.SetValue(self.LCtrl.GetItem(row, col).GetText())
    editor.Show()
    editor.Raise()
    editor.SetSelection(-1,-1)
    editor.SetFocus()

    self.curRow = row
    self.curCol = col

def CloseEditor(self, evt=None):
    text = self.editor.GetValue()
    self.editor.Hide()
    self.LCtrl.SetStringItem(self.curRow, self.curCol, text)
        
-------------------------------------------------------

Hope this helps,

Steve