wxPython控件学习之wx.grid.Grid (包括对GridCellEditor和GridCelRender的扩展,以支持更多的grid cell 样式, 以GridCellColorEditor为例) 2012年10月08日 ⁄ 综合 ⁄ 共 10983字 ⁄ 字号 小 中 大 ⁄ 评论关闭 30元程序员衣装优惠券,仅剩3天!点击领取 wx.Grid 及其相关的类是用来显示和编辑类表格样式的数据。该控件为显示,编辑数据源提及交互供了丰富的特征。 wx.GridTableBase类控制要显示的实际数据。可以call CreateGrid()产生一个该类的实例对象。 wx.GridCellRenderer 基类,负责对单元格进行绘画。现在提供了默认的几种派生。 wxGridCellBoolRenderer 显示CheckBox样式 wxGridCellFloatRenderer wxGridCellNumberRenderer wxGridCellStringRenderer wx.GridCellEditor 基类,负责在cell editing状态下,显示对应的控件。现在提供了默认的几种派生。 wxGridCellBoolEditor wxGridCellChoiceEditor wxGridCellFloatEditor wxGridCellNumberEditor wxGridCellTextEditor 如何添加、删除行,列和单元格? 本例中使用SetTable() 作为grid 的数据源。 那么重点来研究在这个情况下如何对grid 和 数据源进行增删改。 GridTableMessage 类,可以用来向表发送一些message,本例中 是对行的增删改操作, 那么我们只需要用其中的3个message: GRIDTABLE_NOTIFY_ROWS_INSERTED 行插入的消息 GRIDTABLE_NOTIFY_ROWS_APPENDED 附近新行的消息 GRIDTABLE_NOTIFY_ROWS_DELETED 删除行的消息 GRIDTABLE_REQUEST_VIEW_GET_VALUES cell 值如果有更改的消息 1.在index插入一新行 grd.GridTableMessage(self, grd.GRIDTABLE_NOTIFY_ROWS_INSERTED ,index 改行所在的索引 ,1 插入一行记录 ) 2. 删除rowIndex行 grd.GridTableMessage(self,grd.GRIDTABLE_NOTIFY_ROWS_DELETED, rowIndex, 改行所在的索引 1 只删除一行 ) 3. 附加一新行 grd.GridTableMessage(self, grd.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1 附近的新行个数 ) #-*-coding:utf-8 #------------------------------------------------------------------------------- # Name: 模块1 # Purpose: # # Author: ankier # # Created: 14/10/2012 # Copyright: (c) ankier 2012 # Licence: <your licence> #------------------------------------------------------------------------------- import wx, wx.grid as grd #grid column类型 class GridColumnControlKind: Text ="Text" CheckBox = "CheckBox" Colour = "Colour" #定购的Grid cell color editor class GridCellColorEditor(grd.PyGridCellEditor): def Create(self, parent, id, evtHandler): """ Called to create the control, which must derive from wx.Control. *Must Override* """ self.__Parent = parent self.__ColorDialog = None self.__ColorButton = wx.Button(parent, id, "") self.SetControl(self.__ColorButton) #添加新的event handler, 防止 弹出窗口后, cell 自动editor newEventHandler = wx._core.EvtHandler() if evtHandler: self.__ColorButton.PushEventHandler(newEventHandler) self.__ColorButton.Bind(wx.EVT_BUTTON, self.OnClick) def OnClick(self, event): self.__ColorButton.SetFocus() self.ShowColorDialog() def SetSize(self, rect): """ Called to position/size the edit control within the cell rectangle. If you don't fill the cell (the rect) then be sure to override PaintBackground and do something meaningful there. """ self.__ColorButton.SetDimensions(rect.x,rect.y,rect.width+2,rect.height+2,wx.SIZE_ALLOW_MINUS_ONE) def Clone(self): """ Create a new object which is the copy of this one *Must Override* """ return GridCellColorEditor() def BeginEdit(self, row, col, grid): """ Fetch the value from the table and prepare the edit control to begin editing. Set the focus to the edit control. *Must Override* """ self.startValue = grid.GetTable().GetValue(row, col) self.endValue = self.startValue self.__ColorButton.SetBackgroundColour(self.startValue) def EndEdit(self, row, col, grid): """ Complete the editing of the current cell. Returns True if the value has changed. If necessary, the control may be destroyed. *Must Override* """ changed = False if self.endValue != self.startValue: changed = True grid.GetTable().SetValue(row, col, self.endValue) # update the table self.startValue = '' return changed def ShowColorDialog(self): colorDialog = wx.ColourDialog(self.__Parent) self.__ColorDialog = colorDialog colorDialog.GetColourData().SetColour(self.startValue) if wx.ID_OK == colorDialog.ShowModal(): data = colorDialog.GetColourData() colour = data.GetColour() self.__ColorButton.SetBackgroundColour(colour) self.endValue = colour del self.__ColorDialog self.__ColorDialog = None #定购颜色cell colour column class GridCellColorRender(grd.PyGridCellRenderer): def __init__(self): grd.PyGridCellRenderer.__init__(self) def Draw(self, grid, attr, dc, rect, row, col, isSelected): color = grid.GetTable().GetValue(row, col) dc.SetBrush(wx.Brush(color, wx.SOLID)) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangleRect(rect) dc.SetBackgroundMode(wx.TRANSPARENT) def GetBestSize(self, grid, attr, dc, row, col): # text = grid.GetCellValue(row, col) # dc.SetFont(attr.GetFont()) # w, h = dc.GetTextExtent(text) return wx.Size(-1, -1) def Clone(self): return GridCellColorRender() #根据具体业务逻辑 定购grid的 table class CustomGridTable(grd.PyGridTableBase): def __init__(self): grd.PyGridTableBase.__init__(self) #添加Grid column head self.colLabels = ["Name", "Visibility", "Min threshold", "Max threshold", "Colour"] #指定column对应的kind control self.colControlKinds = [GridColumnControlKind.Text, GridColumnControlKind.CheckBox, GridColumnControlKind.Text, GridColumnControlKind.Text, GridColumnControlKind.Colour] self.colControlEditorEnableStatus =[True, True, False, False, True] self.rowLabels = ["","","","",""] #添加数据源 self.Data = [ ['Mask 1', 1, "2.5","320.6",(200,20,100)] ,['Mask 2', 1, "2.5","320.6",(50,0,200)] ] def GetNumberRows(self): return len(self.Data) def GetNumberCols(self): return len(self.colLabels) def IsEmptyCell(self, row, col): return False def GetValue(self, row, col): return self.Data[row][col] def SetValue(self, row, col, value): self.Data[row][col] = value def GetColLabelValue(self, col): return self.colLabels[col] def GetRowLabelValue(self, row): return self.rowLabels[row] def InsertRow(self, index, row): if len(self.Data) < index: return self.Data.insert(index, row) print self.Data self.GetView().BeginBatch() msg = grd.GridTableMessage(self, grd.GRIDTABLE_NOTIFY_ROWS_INSERTED ,index ,1 ) self.GetView().ProcessTableMessage(msg) # ... same thing for columns .... self.GetView().EndBatch() msg = grd.GridTableMessage(self, grd.GRIDTABLE_REQUEST_VIEW_GET_VALUES) self.GetView().ProcessTableMessage(msg) def DeleteRow(self, row): rowIndex = self.Data.index(row ) if rowIndex <0: return self.Data.remove(row) self.GetView().BeginBatch() msg = grd.GridTableMessage(self,grd.GRIDTABLE_NOTIFY_ROWS_DELETED, rowIndex, ) self.GetView().ProcessTableMessage(msg) # ... same thing for columns .... self.GetView().EndBatch() msg = grd.GridTableMessage(self, grd.GRIDTABLE_REQUEST_VIEW_GET_VALUES) self.GetView().ProcessTableMessage(msg) def Clear(self): self.GetView().BeginBatch() msg = grd.GridTableMessage(self,grd.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberCols()-1) self.GetView().ProcessTableMessage(msg) # ... same thing for columns .... self.GetView().EndBatch() self.Data = [] msg = grd.GridTableMessage(self, grd.GRIDTABLE_REQUEST_VIEW_GET_VALUES) self.GetView().ProcessTableMessage(msg) def AppendRow(self, row): self.Data.append(row) self.GetView().BeginBatch() msg = grd.GridTableMessage(self, grd.GRIDTABLE_NOTIFY_ROWS_APPENDED, ) self.GetView().ProcessTableMessage(msg) # ... same thing for columns .... self.GetView().EndBatch() msg = grd.GridTableMessage(self, grd.GRIDTABLE_REQUEST_VIEW_GET_VALUES) self.GetView().ProcessTableMessage(msg) #对grid的功能进行封装 以便能方便的处理 class CustomGrid(grd.Grid): def __init__(self, parent, id, rowLabelSize = 0, customGridTable = None): grd.Grid.__init__(self, parent,id) self.RowLabelSize = rowLabelSize self.__CustomTableSource = customGridTable self.SetTable(self.__CustomTableSource, True) self.__InitStyle() #设置column 对应的 editor self.__InitColumnsEditor() # self.Bind(grd.EVT_GRID_CELL_LEFT_CLICK,self.__OnMouse) self.Bind(grd.EVT_GRID_SELECT_CELL, self.__OnCellSelected) self.Bind(grd.EVT_GRID_EDITOR_CREATED, self.__OnEditorCreated) def __InitStyle(self): self.SetSelectionBackground(wx.Color(237 , 145 , 33 )) def __InitColumnsEditor(self): index = -1 for columnKind in self.__CustomTableSource.colControlKinds: index += 1 if columnKind == GridColumnControlKind.CheckBox: self.__InitCheckBoxColumnEditor(index) elif columnKind == GridColumnControlKind.Colour: self.__InitColorColumnEditor(index) def __InitCheckBoxColumnEditor(self, columnIndex): attr = grd.GridCellAttr() attr.SetEditor(grd.GridCellBoolEditor()) attr.SetRenderer(grd.GridCellBoolRenderer()) self.SetColAttr(columnIndex, attr) def __InitColorColumnEditor(self, columnIndex): attr = grd.GridCellAttr() attr.SetEditor(GridCellColorEditor()) attr.SetRenderer(GridCellColorRender()) self.SetColAttr(columnIndex, attr) def __OnCellSelected(self,evt): if self.__CustomTableSource.colControlEditorEnableStatus[evt.Col]: wx.CallAfter(self.EnableCellEditControl) evt.Skip() #设置改行为选中状态 self.SelectRow(evt.Row) def __OnEditorCreated(self, event): pass def ForceRefresh(self): grd.Grid.ForceRefresh(self) #主窗口 class TestFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None,title="GridTable",size=(500,200)) sizer = wx.BoxSizer(wx.HORIZONTAL) addButton = wx.Button(self, -1, "Add") deleteButton = wx.Button(self, -1, "Delete") clearButton = wx.Button(self, -1, "Clear") sizer.Add(addButton, 0, wx.SHAPED) sizer.Add(deleteButton, 0, wx.SHAPED) sizer.Add(clearButton, 0, wx.SHAPED) table = CustomGridTable() grid = CustomGrid(self, id = -1, customGridTable = table) self.__Grid = grid mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(sizer) mainSizer.Add(grid, 1, wx.EXPAND) self.SetSizerAndFit(mainSizer) addButton.Bind(wx.EVT_BUTTON, self.OnAddClick) deleteButton.Bind(wx.EVT_BUTTON, self.OnDeleteClick) clearButton.Bind(wx.EVT_BUTTON, self.OnClearClick) def OnClearClick(self, event): table = self.__Grid.GetTable() table.Clear() print self.__Grid.GetTable().Data def OnDeleteClick(self, event): table = self.__Grid.GetTable() firstRow = table.Data[1] table.DeleteRow(firstRow) print self.__Grid.GetTable().Data def OnAddClick(self, event): table = self.__Grid.GetTable() table.InsertRow(1, ['insert index ', 1, "2.5","110.6",(50,200,30)]) print self.__Grid.GetTable().Data def main(): app = wx.PySimpleApp() frame = TestFrame() frame.Show() app.MainLoop() if __name__ == '__main__': main() #-*-coding:utf-8 #------------------------------------------------------------------------------- # Name: 模块1 # Purpose: # # Author: ankier # # Created: 14/10/2012 # Copyright: (c) ankier 2012 # Licence: <your licence> #------------------------------------------------------------------------------- import wx, wx.grid as grd #定购的Grid cell ComboBox editor class GridCellComboBoxEditor(grd.PyGridCellEditor): def __init__(self, choices = []): grd.PyGridCellEditor.__init__(self) self.__Choices = choices def Create(self, parent, id, evtHandler): """ Called to create the control, which must derive from wx.Control. *Must Override* """ self.__Parent = parent self.__ComboBoxDialog = None self.__ComboBoxButton = wx.ComboBox(parent, id, value = "", choices =self.__Choices) self.__ComboBoxButton.SetEditable(False) self.SetControl(self.__ComboBoxButton) #添加新的event handler, 防止 弹出窗口后, cell 自动editor newEventHandler = wx._core.EvtHandler() if evtHandler: self.__ComboBoxButton.PushEventHandler(newEventHandler) self.__ComboBoxButton.Bind(wx.EVT_COMBOBOX, self.OnClick) def OnClick(self, event): self.endValue = self.__ComboBoxButton.GetStringSelection() def SetSize(self, rect): """ Called to position/size the edit control within the cell rectangle. If you don't fill the cell (the rect) then be sure to override PaintBackground and do something meaningful there. """ self.__ComboBoxButton.SetDimensions(rect.x,rect.y,rect.width+2,rect.height+2,wx.SIZE_ALLOW_MINUS_ONE) def Clone(self): """ Create a new object which is the copy of this one *Must Override* """ return GridCellComboBoxEditor() def BeginEdit(self, row, col, grid): """ Fetch the value from the table and prepare the edit control to begin editing. Set the focus to the edit control. *Must Override* """ self.startValue = grid.GetTable().GetValue(row, col) self.endValue = self.startValue self.__ComboBoxButton.SetStringSelection(self.startValue) def EndEdit(self, row, col, grid): """ Complete the editing of the current cell. Returns True if the value has changed. If necessary, the control may be destroyed. *Must Override* """ changed = False if self.endValue != self.startValue: changed = True grid.GetTable().SetValue(row, col, self.endValue) # update the table self.startValue = '' return changed #定购颜色cell colour column class GridCellComboBoxRender(grd.GridCellStringRenderer): def __init__(self): grd.GridCellStringRenderer.__init__(self)