== Introduction == This recipe is an adaptation of one of the wxPython demos currently available (as of 2004-05-12). It shows how to arrange: * to redefine column names (and, presumably, other attributes of columns at run-time, and * to repopulate a list from an iterator, in this case a MySQL cursor `Execute`. I have chopped out a lot of events machinery that was present in the original demo (merely to preserve my own sanity). == What Objects are Involved == `wxListCtrl`, `wxListCtrlAutoWidthMixin`, `wxColumnSorterMixin` == Process Overview == One can postpone columns definition until the list control is actually displayed. In this recipe column names are provided to the panel that hosts the list control as an attribute of the panel. It appears to be safe to delete all of the items from a list even when the list is empty. In this recipe the Execute method of a MySQL cursor is started to provide an iterator as a source of rows or records for populating the list using `CreateRecords`. Finally `PopulateList` blends information about column names and from the iterator to make the list. == Special Concerns == Column names must be presented in the same order in which field values appear in rows from the iterator. Additional field values in iterator rows are ignored. == Code Sample == {{{ #!python from wxPython.wx import * from wxPython.lib.mixins.listctrl import wxColumnSorterMixin, wxListCtrlAutoWidthMixin from DisplayRecordsImages import getWhiteSquareBitmap, getSmallUpArrowBitmap, getSmallDnArrowBitmap, getXOnWhBitmap class DisplayRecordsCtrl ( wxListCtrl, wxListCtrlAutoWidthMixin ) : def __init__ ( self, parent, ID, pos = wxDefaultPosition, size = wxDefaultSize, style = 0 ) : wxListCtrl . __init__ ( self, parent, ID, pos, size = parent . GetClientSize ( ), style = style ) wxListCtrlAutoWidthMixin . __init__ ( self ) class DisplayRecordsCtrlPanel ( wxPanel, wxColumnSorterMixin ) : def __init__ ( self, parent, columnNames = [ ], size = ( -1, -1 ) ) : wxPanel . __init__ ( self, parent, -1, size = size ) listId = wxNewId ( ) self . il = wxImageList ( 16, 16 ) self . idx1 = self . il . Add ( getWhiteSquareBitmap ( ) ) self . sm_up = self . il . Add ( getSmallUpArrowBitmap ( ) ) self . sm_dn = self . il . Add ( getSmallDnArrowBitmap ( ) ) self . deleted = self . il . Add ( getXOnWhBitmap ( ) ) self . list = DisplayRecordsCtrl ( self, listId, style = wxLC_REPORT | wxSUNKEN_BORDER ) self . list . SetImageList ( self . il, wxIMAGE_LIST_SMALL ) self . columnNames = columnNames wxColumnSorterMixin . __init__ ( self, len ( columnNames ) ) EVT_SIZE ( self, self . OnSize ) EVT_LIST_ITEM_SELECTED ( self, listId, self . OnItemSelected ) def CreateRecords ( self, recordsIterator ) : self . itemDataMap = { } for i, row in enumerate ( recordsIterator ) : self . itemDataMap [ i ] = tuple ( row [ : len ( self . columnNames ) ] ) def PopulateList ( self ) : info = wxListItem ( ) info . m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT info . m_image = -1 info . m_format = 0 while self . list . GetColumnCount ( ) : self . list . DeleteColumn ( 0 ) for c, columnName in enumerate ( self . columnNames ) : info.m_text = columnName self . list . InsertColumnInfo ( c, info ) items = self . itemDataMap . items ( ) for itemNumber, ( key, data ) in enumerate ( items ): self . list . InsertImageStringItem ( itemNumber, data [ 0 ], self . idx1 ) for j in range ( 1, len ( data ) ) : dataAsString = '' if data [ j ] : dataAsString = str ( data [ j ] ) self . list . SetStringItem ( itemNumber, j, dataAsString ) self . list . SetItemData ( itemNumber, key ) for c in range ( len ( self . columnNames ) ) : self . list . SetColumnWidth ( c, wxLIST_AUTOSIZE ) self.currentItem = 0 def GetListCtrl ( self ) : return self . list def GetSortImages ( self ) : return self . sm_dn, self . sm_up def OnSize ( self, event ) : w, h = self . GetClientSizeTuple ( ) self . list . SetDimensions ( 0, 0, w, h ) def getColumnText(self, index, col): item = self . list . GetItem ( index, col ) return item . GetText ( ) def OnItemSelected(self, event): self . currentItem = event . m_itemIndex event . Skip ( ) if __name__ == "__main__" : import adodb db = adodb . NewADOConnection ( 'mysql' ) db . Connect ( '', '', '', 'FWOTS' ) def AddMenuItem ( menu, label, parent, handler, helpText = '' ) : anId = wxNewId ( ) menu . Append ( anId, label, helpText ) EVT_MENU ( parent, anId, handler ) return anId class MainFrame ( wxFrame ) : def __init__ ( self, * args ) : wxFrame . __init__ ( self, * args ) self . CreateStatusBar ( ) self . SetStatusText ( "Click on column heading to sort" ) menuBar = wxMenuBar ( ) mainItem = wxMenu ( ) AddMenuItem ( mainItem, "List 1", self, self . list1 ) AddMenuItem ( mainItem, "List 2", self, self . list2 ) menuBar . Append ( mainItem, '&File' ) self . SetMenuBar ( menuBar ) self . panel = DisplayRecordsCtrlPanel ( self ) def list1 ( self, event = None ) : self . panel . columnNames = [ 'Company', 'City', 'Telephone 1', ] self . panel . list . DeleteAllItems ( ) rs = db . Execute ( 'select COMPANY, CITY, PHONE1, IDENTIFIER from CUSTOMERS where IDENTIFIER < 30 order by COMPANY' ) self . panel . CreateRecords ( rs ) self . panel . PopulateList ( ) def list2 ( self, event = None ) : self . panel . columnNames = [ 'Company', 'City', ] self . panel . list . DeleteAllItems ( ) rs = db . Execute ( 'select COMPANY, CITY, PHONE1, IDENTIFIER from CUSTOMERS where IDENTIFIER < 30 order by COMPANY' ) self . panel . CreateRecords ( rs ) self . panel . PopulateList ( ) app = wxPySimpleApp ( ) frame = MainFrame ( None, wxNewId (), 'Customers List' ) frame . Show ( ) app . MainLoop ( ) }}} === Comments === I welcome your comments. [[Bill Bell]]