1#!/usr/bin/env python 2 3import wx 4import wx.grid as gridlib 5 6#--------------------------------------------------------------------------- 7 8class CustomDataTable(gridlib.GridTableBase): 9 def __init__(self, log): 10 gridlib.GridTableBase.__init__(self) 11 self.log = log 12 13 self.colLabels = ['ID', 'Description', 'Severity', 'Priority', 'Platform', 14 'Opened?', 'Fixed?', 'Tested?', 'TestFloat'] 15 16 self.dataTypes = [gridlib.GRID_VALUE_NUMBER, 17 gridlib.GRID_VALUE_STRING, 18 gridlib.GRID_VALUE_CHOICE + ':only in a million years!,wish list,minor,normal,major,critical', 19 gridlib.GRID_VALUE_NUMBER + ':1,5', 20 gridlib.GRID_VALUE_CHOICE + ':all,MSW,GTK,other', 21 gridlib.GRID_VALUE_BOOL, 22 gridlib.GRID_VALUE_BOOL, 23 gridlib.GRID_VALUE_BOOL, 24 gridlib.GRID_VALUE_FLOAT + ':6,2', 25 ] 26 27 self.data = [ 28 [1010, "The foo doesn't bar", "major", 1, 'MSW', 1, 1, 1, 1.12], 29 [1011, "I've got a wicket in my wocket", "wish list", 2, 'other', 0, 0, 0, 1.50], 30 [1012, "Rectangle() returns a triangle", "critical", 5, 'all', 0, 0, 0, 1.56] 31 32 ] 33 34 35 #-------------------------------------------------- 36 # required methods for the wxPyGridTableBase interface 37 38 def GetNumberRows(self): 39 return len(self.data) + 1 40 41 def GetNumberCols(self): 42 return len(self.data[0]) 43 44 def IsEmptyCell(self, row, col): 45 try: 46 return not self.data[row][col] 47 except IndexError: 48 return True 49 50 # Get/Set values in the table. The Python version of these 51 # methods can handle any data-type, (as long as the Editor and 52 # Renderer understands the type too,) not just strings as in the 53 # C++ version. 54 def GetValue(self, row, col): 55 try: 56 return self.data[row][col] 57 except IndexError: 58 return '' 59 60 def SetValue(self, row, col, value): 61 def innerSetValue(row, col, value): 62 try: 63 self.data[row][col] = value 64 except IndexError: 65 # add a new row 66 self.data.append([''] * self.GetNumberCols()) 67 innerSetValue(row, col, value) 68 69 # tell the grid we've added a row 70 msg = gridlib.GridTableMessage(self, # The table 71 gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED, # what we did to it 72 1 # how many 73 ) 74 75 self.GetView().ProcessTableMessage(msg) 76 innerSetValue(row, col, value) 77 78 #-------------------------------------------------- 79 # Some optional methods 80 81 # Called when the grid needs to display labels 82 def GetColLabelValue(self, col): 83 return self.colLabels[col] 84 85 # Called to determine the kind of editor/renderer to use by 86 # default, doesn't necessarily have to be the same type used 87 # natively by the editor/renderer if they know how to convert. 88 def GetTypeName(self, row, col): 89 return self.dataTypes[col] 90 91 # Called to determine how the data can be fetched and stored by the 92 # editor and renderer. This allows you to enforce some type-safety 93 # in the grid. 94 def CanGetValueAs(self, row, col, typeName): 95 colType = self.dataTypes[col].split(':')[0] 96 if typeName == colType: 97 return True 98 else: 99 return False 100 101 def CanSetValueAs(self, row, col, typeName): 102 return self.CanGetValueAs(row, col, typeName) 103 104 105#--------------------------------------------------------------------------- 106 107 108class CustTableGrid(gridlib.Grid): 109 def __init__(self, parent, log): 110 gridlib.Grid.__init__(self, parent, -1) 111 112 table = CustomDataTable(log) 113 114 # The second parameter means that the grid is to take ownership of the 115 # table and will destroy it when done. Otherwise you would need to keep 116 # a reference to it and call it's Destroy method later. 117 self.SetTable(table, True) 118 119 self.SetRowLabelSize(0) 120 self.SetMargins(0,0) 121 self.AutoSizeColumns(False) 122 123 self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnLeftDClick) 124 125 126 # I do this because I don't like the default behaviour of not starting the 127 # cell editor on double clicks, but only a second click. 128 def OnLeftDClick(self, evt): 129 if self.CanEnableCellControl(): 130 self.EnableCellEditControl() 131 132 133#--------------------------------------------------------------------------- 134 135class TestFrame(wx.Frame): 136 def __init__(self, parent, log): 137 138 wx.Frame.__init__( 139 self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480) 140 ) 141 142 p = wx.Panel(self, -1, style=0) 143 grid = CustTableGrid(p, log) 144 b = wx.Button(p, -1, "Testing with another control...") 145 b.SetDefault() 146 self.Bind(wx.EVT_BUTTON, self.OnButton, b) 147 b.Bind(wx.EVT_SET_FOCUS, self.OnButtonFocus) 148 bs = wx.BoxSizer(wx.VERTICAL) 149 bs.Add(grid, 1, wx.GROW|wx.ALL, 5) 150 bs.Add(b) 151 p.SetSizer(bs) 152 153 def OnButton(self, evt): 154 print("button selected") 155 156 def OnButtonFocus(self, evt): 157 print("button focus") 158 159 160#--------------------------------------------------------------------------- 161 162if __name__ == '__main__': 163 import sys 164 app = wx.App() 165 frame = TestFrame(None, sys.stdout) 166 frame.Show(True) 167 app.MainLoop() 168 169 170#--------------------------------------------------------------------------- 171