wx.grid.Grid及其相关类用于显示和编辑表格数据。它们提供了一组丰富的功能,用于显示、编辑和与各种数据源交互。
wx.grid.Grid是一个功能强大的但是又稍微有一些复杂的窗口类,它用来显示表格类型的数据。可以使用wx.Grid来作为一个包含名称和值两栏的属性编辑器。或者是通过代码使其作为一个一般意义上的表格,用来显示一个数据库或者是应用程序产生的特定统计数据。
一、wx.grid相关类
对于简单的应用程序,我们只需要简单地使用wx.grid.Grid类,它将设置其他相关类的默认实例并自动管理它们。对于更复杂的应用,我们可以为自定义网格视图、网格数据表、单元格编辑器和渲染器(Renderer)派生自己的类。wx.grid提供一组类来实现表格应用。
wx.grid.Grid:主网格控件类本身。
wx.grid.GridTableBase:类控制要显示的实际数据。
wx.grid.GridStringTable:简单的GridTableBase实现,只支持字符串数据项,并将它们全部存储在内存中(因此只适用于不太大的网格)。
wx.grid.GridCellAttr:保存用于渲染表格的属性数据。可以显式的通过类似SetCellTextColour这样的函数更改表格的属性。也可以通过SetAttr函数设置某个单独的表格的属性或者是通过SetRowAttr和SetColAttr函数设置某一列或者某一行的属性。还可以在定义的表格类中通过GetAttr函数返回指定表格的属性。
wx.grid.GridCellAttrProvider:负责存储和检索单元格属性的对象。
wx.grid.GridColLabelWindow:显示网格列标签的窗口。
wx.grid.GridRowLabelWindow:显示网格行标签的窗口。
wx.grid.GridCornerLabelWindow:在左上角网格角中使用的窗口。
wx.grid.GridWindow:表示网格的主要部分窗口。
wx.grid.GridCellRenderer是用于在单元格中呈现内容的抽象基类,负责对单元格进行绘画。wxPython默认提供了几种派生类来实现具体的绘制。
- wx.grid.GridCellBoolRenderer:显示单元格为选中或未选中的框。
- wx.grid.GridCellFloatRenderer:格式化输出单元格中的浮点数数据。
- wx.grid.GridCellNumberRenderer:格式化输出单元格中的整数数据。
- wx.grid.GridCellStringRenderer:格式化输出单元格中的字符串数据。
- wx.grid.GridCellDateRenderer:格式化输出日期。
- wx.grid.GridCellDateTimeRenderer:格式化输出日期时间。
wx.grid.GridCellEditor是用于编辑单元格值的抽象基类。负责实现对表格数据的即时编辑功能的控件。wxPytho 默认提供了几种派生类来实现具体的即时编辑功能。
- wx.grid.GridCellBoolEditor:布尔值单元格的编辑器。
- wx.grid.GridCellChoiceEditor:允许选择一个预定义的字符串(也可能输入一个新的字符串)的编辑器。
- wx.grid.GridCellFloatEditor:用于浮点数的单元格的编辑器。
- wx.grid.GridCellNumberEditor:用于整数的单元格的编辑器。
- wx.grid.GridCellTextEditor:用于文本的单元格的编辑器。
- wx.grid.GridCellDateEditor:用于日期的单元格的编辑器。
wx.GridEvent这个类包含了各种网格相关事件的信息,比如鼠标在表格上单击事件,表格数据改变事件,表格被选中事件,表格编辑器被显示或者隐藏事件等。
二、wx.grid.Grid成员函数
wx.grid.Grid的成员函数较多,下面按相关功能列举了一些常用的成员函数。
用于创建,删除和数据交互的函数:
- AppendCols(self, numCols=1, updateLabels=True):将一个或多个新列追加到网格的右侧。
- AppendRows(self, numRows=1, updateLabels=True):将一个或多个新行追加到网格的底部。
- InsertRows(self, pos=0, numRows=1, updateLabels=True):在网格指定位置插入一列或者多列。
- InsertCols(self, pos=0, numCols=1, updateLabels=True):在网格指定位置插入一行或者多行。
- GetNumberCols(self):返回网格的总列数。
- GetNumberRows(self):返回网格的总行数。
- CreateGrid(self, numRows, numCols, selmode=GridSelectCells):创建具有指定初始行数和列数的网格。直接在网格构造函数之后调用它。当您使用这个函数时,wx.grid.Grid将为您创建和管理一个简单的字符串值表。所有网格数据都将存储在内存中。
- ClearGrid(self):清除所有的网格绑定表格中的数据并且刷新网格的显示。表格本身并不会被释放。
- DeleteCols(self, pos=0, numCols=1, updateLabels=True):从指定位置开始从网格中删除一列或多列。
- DeleteRows(self, pos=0, numRows=1, updateLabels=True):从指定位置开始从网格中删除一行或多行。
- GetColLabelValue(self, col):返回指定的列标签。默认的网格表类提供了A,B…Z,AA,AB…ZZ,AAA…这种形式的列标签。如果使用的是自定义网格表,则可以重写wx.grid.GridTableBase.GetColLabelValue来提供自己的标签。
- GetCellValue (self, row, col):返回单元格中包含的指定位置的字符串。
界面相关函数:
- BeginBatch(self):增加网格的批处理计数。当计数大于零时,网格的重绘将被抑制。每个对BeginBatch的调用都必须与后面对EndBatch的调用相匹配。做大量网格修改的代码可以被封装在BeginBatch和EndBatch调用之间,以避免屏幕闪烁。最后的EndBatch调用将导致网格被重新绘制。
- EndBatch(self):减少网格的批处理计数。当计数大于零时,网格的重绘将被抑制。每个之前对BeginBatch的调用都必须与后面对EndBatch的调用相匹配。做大量网格修改的代码可以被封装在BeginBatch和EndBatch调用之间,以避免屏幕闪烁。最后的EndBatch将导致网格被重新绘制。
- GetBatchCount(self):返回BeginBatch被调用的次数。网格的批处理计数等零时,网格将刷新显示。
- EnableGridLines(self, enable=True):打开或关闭网格线的绘制。
- GridLinesEnabled(self):如果打开绘制网格线,则返回True,否则返回False。
- ForceRefresh(self):强制立即重新绘制网格。
- Fit(self):使网格控件将自己的大小更改为当前行数和列数所要求的最小大小。
- GetCellAlignment(self, row, col):返回指定单元格在垂直和水平方向上的对齐方式。
- GetColLabelAlignment(self):返回列标签的对齐方式。
- GetRowLabelAlignment(self):返回行标签的对齐方式。
- GetDefaultCellAlignment(self):返回默认单元格的对齐方式。
- GetCellBackgroundColour(self, row, col):返回指定单元格背景颜色。
- GetDefaultCellBackgroundColour(self):返回单元格的当前默认背景色。
- GetLabelBackgroundColour(self):返回行标签和列标签的背景颜色。
- GetCellFont(self, row, col):返回指定单元格的字体。
- GetDefaultCellFont(self):返回单元格文本的当前默认字体。
- GetLabelFont(self):返回用于行和列标签的字体。
- GetCellTextColour(self, row, col):返回指定单元格的文本颜色。
- GetDefaultCellFont(self):返回单元格文本的当前默认字体。
- GetLabelTextColour(self):返回用于行和列标签文本的颜色。
- GetGridLineColour(self):返回网格线使用的颜色。
注:以上Get方法都有相应的Set方法。
- SetColAttr(self, col, attr):为指定列中的所有单元格设置单元格属性。
- SetRowAttr(self, row, attr):为指定行中的所有单元格设置单元格属性。
尺寸相关函数:
- AutoSize(self):自动设置所有行和列的高度和宽度以适应其内容。
- AutoSizeColumn(self, col, setAsMin=True):自动调整列的大小以适应其内容。
- AutoSizeColumns(self, setAsMin=True):自动调整所有列的大小以适应其内容。
- AutoSizeRow(self, row, setAsMin=True):自动调整行的大小以适应其内容。
- AutoSizeRows(self, setAsMin=True):自动调整所有行的大小以适应其内容。
- CellToRect (self, row, col):返回与网格单元格的大小和逻辑坐标位置对应的矩形。
- GetColMinimalWidth(self, col):获取给定列的最小宽度。
- GetRowMinimalHeight(self, row) :获取给定行的最小高度。
- GetColLabelSize(self):返回列标签的当前高度。
- GetDefaultColLabelSize(self):返回列标签的默认高度。
- GetDefaultColSize(self):返回网格列的当前默认宽度。
- GetColSize(self, col):返回指定列的宽度。
- GetRowLabelSize(self):返回行标签的当前宽度。
- GetDefaultRowLabelSize(self):返回行标签的默认宽度。
- GetDefaultRowSize(self):返回网格行的当前默认高度。
- GetRowSize(self, row):返回指定行的高度。
注:以上Get方法都有相应的Set方法。
选择和光标函数:
- GetGridCursorCol(self):返回当前单元格列的位置。
- GetGridCursorRow(self):返回当前单元格行的位置。
- MoveCursorDown, MoveCursorLeft, MoveCursorRight和MoveCursorUp:以每次一格的方式移动光标。
- MoveCursorDownBlock, MoveCursorLeftBlock, MoveCursorRightBlock和MoveCursorUpBlock:移动的时候跳到第一个非空单元格。
- MovePageDown和MovePageUp:一次移动一页,页大小由网格窗口的大小决定。
- GetSelectionMode(self):返回当前选择模式。
- GetSelectedCells(self):返回由单独选择的单元格组成的数组。
- GetSelectedCols(self):返回所选列的数组。请注意,这个方法本身并不足以找到所有被选中的列,因为它只包含被单独选中的列。
- GetSelectedRows(self):返回选定行的数组。请注意,这个方法本身并不足以找到所有被选中的行,因为它只包含被单独选中的行。
- GetSelectionBlockTopLeft(self):返回所选单元格块的左上角数组。
- GetSelectionBlockBottomRight(self):返回所选单元格块的右下角的数组。
- SelectAll(self):选择网格中的所有单元格。
其他函数:
- GetTable(self):返回网格用于保存内部数据的绑定表格对象。
- GetCellEditor(self, row, col):返回一个指向指定位置单元格的编辑器指针。
- GetDefaultEditor(self):返回指向当前默认网格单元格编辑器的指针。
- GetCellRenderer(self, row, col):返回指向指定位置网格单元格的渲染器的指针。
- GetDefaultRenderer(self):返回指向当前默认网格单元格渲染器的指针。
注:以上Get方法都有相应的Set方法。
- ShowCellEditControl(self):显示当前单元格被隐藏的编辑器。
- HideCellEditControl(self):隐藏当前单元格被隐藏的编辑器。
- SetReadOnly(self, row, col, isReadOnly=True):将指定单元格设置为可读或者可编辑。
图1:wx.grid.Grid类继承关系
三、wx.grid.Grid演示
#网格控件(wx.grid)
import wx
import wx.grid
#grid column type
class GridColumnControlKind:
Text = "Text"
CheckBox = "CheckBox"
Colour = "Colour"
class GridCellColorEditor(wx.grid.GridCellEditor):
def Create(self, parent, id, evtHandler):
"""
创建一个控件, 该控件必须继承自wx.Control
*必须重载*
"""
self.__parent = parent
self.__dlgColor = None
self.__btnColor = wx.Button(parent, id, "")
self.SetControl(self.__btnColor)
#添加新的事件句柄,防止窗口弹出后,单元格自动调用编辑器
newEventHandler = wx._core.EvtHandler()
if evtHandler:
self.__btnColor.PushEventHandler(newEventHandler)
self.__btnColor.Bind(wx.EVT_BUTTON, self.OnClick)
def OnClick(self, e):
self.__btnColor.SetFocus()
self.ShowColorDialog()
def SetSize(self, rect):
"""
用于在单元格矩形中定位/调整编辑控件的大小。
如果没有填充单元格(矩形),那么一定要重写
PaintBackground做一些必要的事情。
"""
self.__btnColor.SetDimensions(rect.x, rect.y, rect.width + 2, rect.height + 2, wx.SIZE_ALLOW_MINUS_ONE)
def Clone(self):
"""
创建一个新对象,它是这个对象的副本
*必须重载*
"""
return GridCellColorEditor()
def BeginEdit(self, row, col, grid):
"""
从表中获取值并准备编辑控件开始编辑。将焦点设置为编辑控件。
*必须重载*
"""
self.startValue = grid.GetTable().GetValue(row, col)
self.endValue = self.startValue
self.__btnColor.SetBackgroundColour(self.startValue)
def EndEdit(self, row, col, grid):
"""
完成当前单元格的编辑。如果已发生改变,则返回True
如有必要,可以销毁控件。
*必须重载*
"""
changed = False
if self.endValue != self.startValue:
changed = True
grid.GetTable().SetValue(row, col, self.endValue) # 更新该表
self.startValue = ""
return changed
def ShowColorDialog(self):
colorDlg = wx.ColourDialog(self.__parent)
self.__dlgColor = colorDlg
colorDlg.GetColourData().SetColour(self.startValue)
if wx.ID_OK == colorDlg.ShowModal():
data = colorDlg.GetColourData()
colour = data.GetColour()
self.__btnColor.SetBackgroundColour(colour)
self.endValue = colour
del self.__dlgColor
self.__dlgColor = None
class GridCellColorRender(wx.grid.GridCellRenderer):
def __init__(self):
wx.grid.GridCellRenderer.__init__(self)
def Draw(self, grid, attr, dc, rect, row, col, isSelected):
color = grid.GetTable().GetValue(row, col)
dc.SetBrush(wx.Brush(color, wx.BRUSHSTYLE_SOLID))
dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangle(rect)
dc.SetBackgroundMode(wx.BRUSHSTYLE_TRANSPARENT)
def GetBestSize(self, grid, attr, dc, row, col):
return wx.Size(-1, -1)
def Clone(self):
return GridCellColorRender()
#根据具体业务逻辑定制grid的 table
class CustomGridTable(wx.grid.GridTableBase):
def __init__(self):
wx.grid.GridTableBase.__init__(self)
#添加表的列的头
self.colLabels = ["名字", "可见", "最小门限", "最大门限", "颜色"]
#指定一个列的控制类型
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 = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_INSERTED, index, 1)
self.GetView().ProcessTableMessage(msg)
# ... same thing for columns ....
self.GetView().EndBatch()
msg = wx.grid.GridTableMessage(self, wx.grid.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 = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, rowIndex, 1)
self.GetView().ProcessTableMessage(msg)
# ... same thing for columns ....
self.GetView().EndBatch()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
self.GetView().ProcessTableMessage(msg)
def Clear(self):
self.GetView().BeginBatch()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberRows())
self.GetView().ProcessTableMessage(msg)
# ... same thing for columns ....
self.GetView().EndBatch()
self.data = []
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
self.GetView().ProcessTableMessage(msg)
def AppendRow(self, row):
self.data.append(row)
self.GetView().BeginBatch()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED)
self.GetView().ProcessTableMessage(msg)
# ... same thing for columns ....
self.GetView().EndBatch()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
self.GetView().ProcessTableMessage(msg)
#对grid的功能进行封装 以方便处理
class CustomGrid(wx.grid.Grid):
def __init__(self, parent, id, rowLabelSize = 0, customGridTable = None):
wx.grid.Grid.__init__(self, parent, id)
self.rowLabelSize = rowLabelSize
self.__customTableSource = customGridTable
self.SetTable(self.__customTableSource, True)
self.__InitStyle()
#设置column 对应的 editor
self.__InitColumnsEditor()
# self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK,self.__OnMouse)
self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.__OnCellSelected)
self.Bind(wx.grid.EVT_GRID_EDITOR_CREATED, self.__OnEditorCreated)
def __InitStyle(self):
#设置选中后的背景色
self.SetSelectionBackground(wx.Colour(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 = wx.grid.GridCellAttr()
attr.SetEditor(wx.grid.GridCellBoolEditor())
attr.SetRenderer(wx.grid.GridCellBoolRenderer())
self.SetColAttr(columnIndex, attr)
def __InitColorColumnEditor(self, columnIndex):
attr = wx.grid.GridCellAttr()
attr.SetEditor(GridCellColorEditor())
attr.SetRenderer(GridCellColorRender())
self.SetColAttr(columnIndex, attr)
def __OnCellSelected(self, e):
if self.__customTableSource.colControlEditorEnableStatus[e.Col]:
wx.CallAfter(self.EnableCellEditControl)
e.Skip()
#设置行为选中状态
self.SelectRow(e.Row)
def __OnEditorCreated(self, event):
pass
def ForceRefresh(self):
wx.grid.Grid.ForceRefresh(self)
class SampleGrid(wx.Frame):
def __init__(self, *args, **kw):
super(SampleGrid, self).__init__(*args, **kw)
self.InitUi()
def InitUi(self):
self.SetTitle("实战wxPython: Gird演示")
self.SetSize(500, 300)
sizer = wx.BoxSizer(wx.HORIZONTAL)
addButton = wx.Button(self, -1, "添加")
deleteButton = wx.Button(self, -1, "删除")
clearButton = wx.Button(self, -1, "清理")
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)
self.Centre()
def OnClearClick(self, e):
table = self.__grid.GetTable()
table.Clear()
print(self.__grid.GetTable().data)
def OnDeleteClick(self, e):
table = self.__grid.GetTable()
firstRow = table.data[0]
table.DeleteRow(firstRow)
print(self.__grid.GetTable().data)
def OnAddClick(self, e):
table = self.__grid.GetTable()
table.InsertRow(0, ['insert index ', 1, "2.5","110.6",(50,200,30)])
print(self.__grid.GetTable().data)
def main():
app = wx.App()
sample = SampleGrid(None)
sample.Show()
app.MainLoop()
if __name__ == "__main__":
main()
上面的代码演示了如何从基类实现自定义的单元编辑器和渲染器,是一个使用wx.grid比较完整的例子,可以尝试修改其中的代码,观察如何操控wx.grid.Grid。
图2:wx.grid.Grid演示
四、本文知识点
- 了解wx.gird相关类。
- 掌握如何使用wx.grid.Grid网格控件。