No Image
No Image
No Image
How to set and retrieve column data using wxListCtrl and wxMax Print E-mail
Monday, 21 January 2008

When writing my multicolumn listbox routines I was amazed at how thin on the ground documentation was re setting and retrieving individual column fields via wxListItem. Although this is a BlitzMax oriented post, the general approach should work for all implementations of wxWidgets.

The main structure of interest is wxListItem. wxListItem encapsulates the contents of a given listbox cell. So each row/column combination has its own wxListItem structure. There is actually an alternate route for working with most wxListCtrl data but I am under the happy delusion that wxListItem is more efficient if you are dealing with multiple item contents at once (as I do here). 

1. How to set Column Titles in a wxListCtrl.

'    For each column in the table
For Local col:Int = 0 Until s_ColumnTitles.length

    ' Set the column name
    item.SetText(s_ColumnTitles[col])
   
    ' Set the column number    
    item.SetColumn(col)
   
    ' Set the alignment for column contents. Possible values are wxLIST_FORMAT_CENTRE, wxLIST_FORMAT_RIGHT, wxLIST_FORMAT_LEFT
    item.SetAlign(Alignment[col])
   
    ' Set the column width - put your specific pixel width in here if you have one
    'item.SetWidth(ColWidths[col])
   
    ' Insert our new column header   
    InsertColumnItem(col, item)
   
    ' If you want AUTO_SIZED columns it has to be after the fact
    SetColumnWidth( col, wxLIST_AUTOSIZE )
               
Next

 2. How to set Row/Column contents in a wxListCtrl.

Assuming you have a valid empty item:wxListItem structure ready:

 '    Apply an icon image it one exists
If _icon > -1 And ImageList
    item.SetImage(_icon)
Else
    item.SetImage(-1)
EndIf

'    Set row text
item.SetText(_s_row_text)

'    Set the item row
item.SetId(_row)

'     Please note that client data is associated with the item And Not with subitems.
'     Also note that in BlitzMax, this is only a reference to the data. You will need to manage that reference yourself, otherwise it may be garbage-collected.
item.SetData(_s_context)

'    Which column are we destined for?
item.SetColumn(_col)

'    Set font, font_colour and background colour if required
If _font Then item.SetFont(_font)
If _background_colour Then item.SetBackgroundColour(New wxColour.Create(_background_colour.r,_background_colour.g,_background_colour.b))
If _font_colour Then item.SetTextColour(New wxColour.Create(_font_colour.r,_font_colour.g,_font_colour.b))
           
'    Blitzmax only: Manage the context reference as .data is just an unmanaged pointer internally. If we don't do this GC may eat out context! This management of the user data should be obsolete by the time you read this as wxMax is being changed to handle all this internally.
If Not ContextList Then ContextList = New TList
ContextList.AddFirst(_s_context)

'    Place the item on the listbox - col 0 must always be InsertItem, not SetItem
If _col  = 0
     InsertItem(item )
'    Note we can't use SetItem until we have col 0 in place - app with crash otherwise -InsertItem on a col> 0 does nothing but overwrite col 0
Else
    SetItem(item)
EndIf   

NB the weird InsertItem/SetItem toggle. That was a real puzzle for me! Apparently Column 0 requires InsertItem, but Column n > 0 requires SetItem (assuming that Column 0 has been previously inserted). I couldn't find that in any docs anywhere, but it's what seems to work. 

3. How to retrieve an individual column's field contents in a wxListCtrl.

 '    Which row has been selected?                                                
CurrentSelectionRow = GetFirstSelected()

'    Holding struct for all the info on this selection
Local item:wxListItem = New wxListItem.Create()

'    We need to set the row # else we won't know which item to get
item.SetId(CurrentSelectionRow)

'    OK which column are we in?
Local x:Int
'    Note you can use GetPosition() (or equiv) from your click event to get this MouseX value
'    I'm using a global set via a OnMouseMove event capture in this instance
Local mouse_x:Int = TMouse.GetX()
Local col:Int

'    For each column starting from the left
For col= 0 Until GetColumnCount()

    '    Grab how wide the col is
    x :+ GetColumnWidth(col)

    '    If the mouse is in this column, quit
    If mouse_x <= x Then Exit

Next

'    Store the column
CurrentSelectionCol = col

'    Inform the structure which column we want to get    
item.SetColumn(col)

'    Use this to flag we are interested in BOTH text and data
item.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_DATA)

' Grab item info
GetItem(item)
    
' Grab the selected text
s_CurrentSelection = item.GetText()
        
'    Grab the context, if any
s_CurrentSelectionContext = String(item.GetData())

You'd think there'd be a GetSelectedColumn() Method wouldn't you? Instead you have to grab the mouse position manually - which you'd normally do by hooking into the wxListCtrl's MouseEvent. Event.GetPosition() may help you here also.

NB the SetMask field. This is essential on retrieving data. It basically tells the system which particular items you are interested in retrieving. The mask is also valid for SetItem() calls - though in most cases you won't need to explicitly set it as calls like item.SetText() set the mask bit for you. At least that is my assumption!

Oh and finally and for completeness: these are the events I hook into:

        Connect(Id, wxEVT_COMMAND_LIST_ITEM_SELECTED, _OnSelect)
        Connect(Id, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, _OnRightClick)
        Connect(Id,wxEVT_MOTION, _OnMouseMove)

And I create my gadget with the following flags:

_style:Int = wxLC_VRULES | wxLC_REPORT |  wxLC_SINGLE_SEL

And that's the end of the story. Good luck! 

 
< Prev   Next >
No Image
No Image No Image No Image
No Image
© 2009 Gibbon Games
No Image