GridCtrl 控件FAQ
目录
1. 一个固定用法
一个常用的用法是将CridCtrl当做ListCtrl那样的用,同时又增加了即时编辑的功能:
以下假设在一个Dlg增加一个GridCtrl的控件:
我们可以按以下步骤进行:
第一步:表格控件加到工程中去
可以有两种方法:
(1)可以使用controls panel中的custom control添加,添加后如下设置:
(2)也可以用菜单View-Resource Symbol添加一个ID号(适用于Create出来的GridCtrl)
第二步:在Dlg的头文件中加入
CGridCtrl m_Grid;
第三步:Create控件(如果是用controls panel中的custom control添加的可以跳过)
在Dlg的OnCreate函数中添加
m_Grid.Create(……)代码
第四步:创始化控件
在DoDataExchange中添加
DDX_GridControl(pDX, IDC_GRID, m_Grid);
在Dlg的OnInitialDialog中添加如下代码:
//设置控件类似于ListCtrl的表现
m_Grid.SetListMode(TRUE);
//设置控件的初始行数和列数
m_Grid.SetRowCount(1);
m_Grid.SetColumnCount(4);
//设置控件背景颜色,这里GetDefaultCell的两个参数分别表示是否是固定行或者是固定列。如果不设定,缺省的颜色为白色。
m_Grid.GetDefaultCell(FALSE, FALSE)->SetBackClr(Color);
//设置控件的固定行为一行,一般是必须的
m_Grid.SetFixedRowCount(1);
//设置控件的固定列为一列,
m_Grid.SetFixedColumnCount(1); //
第一列为固定列一列
//设置控件的固定行或者固定列不能被选中(默认就是固定的不能被选)
m_Grid.SetFixedColumnSelection(FALSE);
m_Grid.SetFixedRowSelection(FALSE);
//设置控件是否允许隐藏行或者列
m_Grid.EnableColumnHide(FALSE);
m_Grid.EnableRowHide(FALSE);
//设置控件是否允许编辑
m_Grid.SetEditable(FALSE);
//设置控件是否允许选择
m_Grid.EnableSelection(TRUE);
//设置控件是否允许点击表头排序
m_Grid.SetHeaderSort(TRUE);
//设置控件是否允许多选或者单选
m_Grid.SetSingleRowSelection(TRUE);
m_Grid.SetSingleColSelection(TRUE);
//设置控件是否允许自动调整行列大小
m_Grid.SetRowResize(FALSE);
m_Grid.SetColumnResize(FALSE);
//设置控件不要焦点和焦点外框
m_Grid.SetTrackFocusCell(FALSE);
m_Grid.SetFrameFocusCell(FALSE);
第五步:设置控件的内容
强烈建议添加以下Dlg的两个成员函数:
void FillColumn(); //
具体内容见
4
void FillItem(); //
具体内容见
5
第六步:设置控件的响应
具体可见6、7、8
其它
在使用过程中经常需要由程式设定选中行,请始终连续使用以下两个语句:
m_Grid.SetSelectedRange(nRow,0, nRow,m_Grid.GetColumnCount()-1)
m_Grid.EnsureVisible(nRow, 0);
其中nRow
为要选中的那一行,强烈建议不要将这两句语句放在FillItem()
中,这样会导致不灵活。
2. 可以控制单元格是否可以编辑
l 可以设定整张表格为只读
void
CGridCtrl::SetEditable(BOOL bEditable = TRUE)
参数设为FALSE,则整张表格为只读。
l 也可以设定某个单元格为只读
BOOL
CGridCtrl::SetItemState(
int nRow,
int nCol, UINT state)
一般需配合使用UINT
CGridCtrl::GetItemState(
int nRow,
int nCol)
const
比如将单元格(1,1)设为只读
CGridCtrlObject.SetItemState(1,1, m_Grid.GetItemState(1,1) | GVIS_READONLY);
将单元格(1,1)设为正常
CGridCtrlObject.SetItemState(1,1, m_Grid.GetItemState(1,1) & ~GVIS_READONLY);
单元格可用的状态常量
&nnbsp; GVIS_FOCUSED // Cell has focus
GVIS_SELECTED // Cell is selected
GVIS_DROPHILITED // Cell is drop highlighted
GVIS_READONLY // Cell is read-only and cannot be edited
GVIS_FIXED // Cell is fixed
GVIS_FIXEDROW // Cell is part of a fixed row
GVIS_FIXEDCOL // Cell is part of a fixed column
GVIS_MODIFIED // Cell has been modified
3. 在选定一个单元格时,选择整行
void
CGridCtrl::SetListMode(BOOL bEnableListMode = TRUE)
先设定表格为ListMode
4. 说明添加固定列头和固定行头的方法
CGridCtrlObject.SetFixedColumnCount(NumberFixCol);
CGridCtrlObject.SetFixedRowCount(NumberFixRow);
CGridCtrlObject.SetFixedColumnSelection(FALSE);
CGridCtrlObject.SetFixedRowSelection(FALSE);
添加固定表头的方法如下:
m_Grid.SetFixedRowCount(1); //
设定固定行数为
1
行
const int nColumnNum=3;
m_Grid.SetColumnCount(nColumnNum);
int nWidth[nColumnNum];
nWidth[0]=60;
nWidth[1]=120;
nWidth[2]=120;
for(int i=0; i<m_ nColumnNum; i++)
m_Grid.SetColumnWidth(i, nWidth[i]);
i=0;
m_Grid.SetItemText(0,i++,"
第一列
");
m_Grid.SetItemText(0,i++,"
第二列
");
m_Grid.SetItemText(0,i++,"
第三列
");
5. 说明填写表格内容的方法
l 简单的方法是调用
BOOL
CGridCtrl::SetItemText(
int nRow,
int nCol, LPCTSTR str)
例如
CGridCtrlObject.SetItemText(1,1, _T("12345"));
l 复杂但更灵活的方法是采用如下的方法:
GV_ITEM Item;//一个结构
设定这个结构的成员参数,然后将这个结构传递给表格,
CGridCtrlObject.SetItem(&Item);
注:
typedef struct _GV_ITEM {
int row,col; // Row and Column of item
UINT mask; // Mask for use in getting/setting cell data
UINT state; // cell state (focus/hilighted etc)
UINT nFormat; // Format of cell. Default imaplentation
// used CDC::DrawText formats
CString szText; // Text in cell
int iImage; // index of the list view item’s icon
COLORREF crBkClr; // Background colour (or CLR_DEFAULT)
COLORREF crFgClr; // Forground colour (or CLR_DEFAULT)
LPARAM lParam; // 32-bit value to associate with item
LOGFONT lfFont; // cell font
} GV_ITEM;
例如以下代码可以设置表格内容:
m_GridCtrl.SetRowCount(3);
m_GridCtrl.SetItemText(1, 0, "
第一格
");
m_GridCtrl.SetItemText(1, 1, "
第二格
");
m_GridCtrl.SetItemText(1, 2, "
第三格
");
m_GridCtrl.SetItemText(2, 0, "
第四格
");
m_GridCtrl.SetItemText(2, 1, "
第五格
");
m_GridCtrl.SetItemText(2, 2, "
第六格
");
m_GridCtrl.ExpandColumnsToFit();
6. 在选定一行时有响应函数
7. 由双击的响应函数
8. 由响应右键点击的函数
A:
当进行单击,双击或右击单元格等操作时,表格会发送响应的消息,可以在父窗口添加处理消息的函数,做法如下:
GVN_BEGINDRAG // Sent when dragging starts
GVN_BEGINLABELEDIT // Sent when inplace editing starts
GVN_ENDLABELEDIT // Sent when inplace editing stops
GVN_SELCHANGING // Sent just before cell selection changes
GVN_SELCHANGED // Sent after cell selection changes
GVN_GETDISPINFO // A request for cell information when the grid is
// in virtual mode
GVN_ODCACHEHINT // Cache hint when in virtual mode
右键点击,按键盘响应消息在扩展中实现了,可参见条款21
以下需要手工添加
H文件中:
// Generated message map functions
//{{AFX_MSG(CDlgSectionLib)
//}}AFX_MSG
afx_msg void OnGridDblClick(NMHDR *pNotifyStruct, LRESULT* pResult);
afx_msg void OnGridClick(NMHDR *pNotifyStruct, LRESULT* pResult);
afx_msg void OnGridEndSelChange(NMHDR *pNotifyStruct, LRESULT* pResult);
DECLARE_MESSAGE_MAP()
CPP文件中:
BEGIN_MESSAGE_MAP(CDlgSectionLib, CDialog)
//{{AFX_MSG_MAP(CDlgSectionLib)
//}}AFX_MSG_MAP
ON_NOTIFY(NM_DBLCLK, IDC_GRID, OnGridDblClick)
ON_NOTIFY(NM_CLICK, IDC_GRID, OnGridClick)
ON_NOTIFY(GVN_SELCHANGED, IDC_GRID, OnGridEndSelChange)
END_MESSAGE_MAP()
然后自定义响应函数
void CDlgSectionLib::OnGridDblClick(NMHDR *pNotifyStruct, LRESULT* pResult)
{
NM_GRIDVIEW* pItem = (NM_GRIDVIEW*) pNotifyStruct;
pItem->iRow, pItem->iColumn;//得到当前行、列
}
// This structure sent to Grid's parent in a WM_NOTIFY message
typedef struct tagNM_GRIDVIEW {
NMHDR hdr;
int iRow;
int iColumn;
} NM_GRIDVIEW;
typedef struct tagNMHDR {
HWND hwndFrom; // handle of control sending message
UINT idFrom;// identifier of control sending message
UINT code; // notification code; see below
} NMHDR;
NM_CLICK The user has clicked the left mouse button within the control.
NM_DBLCLK The user has double-clicked the left mouse button within the control.
NM_KILLFOCUS The control has lost the input focus.
NM_OUTOFMEMORY The control could not complete an operation because there is not enough memory available.
NM_RCLICK The user has clicked the right mouse button within the control.
NM_RDBLCLK The user has double-clicked the right mouse button within the control.
NM_RETURN The control has the input focus, and the user has pressed the ENTER key.
NM_SETFOCUS The control has received the input focus.
9. 可以方便的删除和添加固定列头
10.可以设置、删除、添加固定行头
A:
参考(4)&(5)
删除可以用以下一些函数
BOOL DeleteColumn(int nColumn);
BOOL DeleteRow(int nRow);
BOOL DeleteNonFixedRows();
BOOL DeleteAllItems();
11.可以在第一个单元格中加入Check控件
A:
#include "NewCellTypes/GridCellCheck.h"//包含头文件
BOOL
CGridCtrl::SetCellType(
int nRow,
int nCol, CRuntimeClass* pRuntimeClass);
比如:
CGridCtrlObject.SetCellType(1,1, RUNTIME_CLASS(CGridCellCheck));
12.可设表格的背景和字体,可设单元格的颜色和字体
设置表格的颜色CGridCtrlObject.GetDefaultCell(FALSE, ALSE)->SetBackClr(RGB(xxx,xxx,xxx));
下面的函数均可以调用:
virtual void CGridCtrl::SetTextClr(COLORREF clr);
virtual void CGridCtrl::SetBackClr(COLORREF clr);
virtual void CGridCtrl::SetFont(const LOGFONT* plf);
设置单元格的背景颜色和前景颜色
BOOL
CGridCtrl::SetItemBkColour(
int nRow,
int nCol, COLORREF cr = CLR_DEFAULT)
BOOL
CGridCtrl::SetItemFgColour(
int nRow,
int nCol, COLORREF cr = CLR_DEFAULT)
BOOL
CGridCtrl::SetItemFont(
int nRow,
int nCol, LOGFONT*lf)
颜色:
COLORREF clr = RGB(xxx,xxx,xxx);
字体:
CFont* pFont = m_Grid.GetFont();
LOGFONT lf;
pFont->GetLogFont(&lf);
memcpy(lf.lfFaceName, _T("Arial"), 6);
lf.lfEscapement = 900;
lf.lfOrientation = 900;
关于单元格的格式都可以通过下述方法设定,同前面关于设置单元格内容(4)的方法
GV_ITEM Item
设置单元格格式
Item.crBkClr = ?;
Item.crFgClr = ?;
Item.mask |= (GVIF_BKCLR|GVIF_FGCLR);
Item.lfFont=?;
SetItem(&Item);
13.可以方便的添加或者删除一行
int
CGridCtrl::InsertColumn(LPCTSTR strHeading,UINT nFormat,
int nColumn = -
1)
int
CGridCtrl::InsertRow(LPCTSTR strHeading,
int nRow = -
1)
BOOL DeleteColumn(
int nColumn)
BOOL DeleteRow(
int nRow)
例如:
CGridCtrlObject.InsertRow(_T("Newest Row"), nRow);
CGridCtrlObject.DeleteRow(nRow);
CGridCtrlObject.Invalidate();//这句是必需的。
14.可以由程序选定某一行
可以调用以下函数:
void SelectRow
(int row) //
该函数在扩展中实现了,具体可参见条款
21
也可以调用以下函数:
void SetSelectedRange(
const CCellRange& Range, BOOL bForceRepaint = FALSE);
void SetSelectedRange(
int nMinRow,
int nMinCol,
int nMaxRow,
int nMaxCol, BOOL bForceRepaint = FALSE);
CCellID SetFocusCell(CCellID cell);
CCellID SetFocusCell(
int nRow,
int nCol);
class CCellID
{
public:
int row, col; // The zero based row and column of the cell.
CCellID(int nRow = -1, int nCol = -1)
int IsValid();
int operator==(const CCellID& rhs);
int operator!=(const CCellID& rhs);
}
也可以调用BOOL CGridCtrl::SetRowFocusAndSelection(int nRow,int nCol=0)
这个函数选中第nRow行,同时将焦点置于第nRow行0,第nCol列。成功则返回TRUE,失败则返回FALSE.
15.可以由程序自动滚动到某一行,显示在用户面前
调用void CGridCtrl::AutoScrollToRow(int nRow)
也可以使用
void EnsureVisible(CCellID &cell)
void EnsureVisible(int nRow, int nCol);
16.说明添加排序功能的方法
调用如下函数:
void
CGridCtrl::SetListMode(BOOL bEnableListMode = TRUE)
void
CGridCtrl::SetHeaderSort(BOOL bSortOnClick = TRUE)
void
CGridCtrl::SetCompareFunction(PFNLVCOMPARE pfnCompare)
如果想实现排序,必须先调用
CGridCtrlObject.SetListMode(TRUE);
CGridCtrlObject.SetHeaderSort(TRUE);
然后设置比较函数:
CGridCtrlObject.SetCompareFunction(CGridCtrl::pfnCellNumericCompare);//数值排序
CGridCtrlObject.SetCompareFunction(CGridCtrl:: pfnCellTextCompare);//字符排序
CGridCtrlObject.SetCompareFunction(NULL);//调用缺省的排序模式,即字符排序
字符排序和数值排序是控件已提供的排序模式,也可以自定义排序函数,例子如下:
int CALLBACK pfnCellCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
比较函数必须是全局的或是静态的。
int CALLBACK MyClass::pfnCellNumericCompare(LPARAM lParam1,
LPARAM lParam2,
LPARAM lParamSort)
{
CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
if (!pCell1 || !pCell2) return 0;
int nValue1 = _ttol(pCell1->GetText());
int nValue2 = _ttol(pCell2->GetText());
if (nValue1 < nValue2)
return -1;
else if (nValue1 == nValue2)
return 0;
else
return 1;
}
17.说明在单元格中添加或者改变图形的方法
也可以这样实现
头文件CImageList m_ImageList;
实现文件中
m_ImageList.Create(MAKEINTRESOURCE(BitMap的ID如:IDB_IMAGES), 16, 1, RGB(255,255,255));
CGridCtrlObject.SetImageList(&m_ImageList);
然后调用
BOOL
CGridCtrl::SetItemImage(
int nRow,
int nCol,
int iImage)
也可以采用(4)中设置单元格的文字内容的方法:
GV_ITEM Item;
Item.iImage =index;
Item.mask |= (GVIF_IMAGE);
CGridCtrlObject.SetItem(&Item);
18.遍历所有的选中行的方法
GVNI_FOCUSED // Search for focus cell
GVNI_SELECTED // Search for selected cells
GVNI_DROPHILITED // Search for drop highlighted cells
GVNI_READONLY // Search for read-only cells
GVNI_FIXED // Search for fixed cells
GVNI_MODIFIED // Search for modified cells
GVNI_ABOVE // Search above initial cell
GVNI_BELOW // Search below initial cell
GVNI_TOLEFT // Search to the left of the initial cell
GVNI_TORIGHT // Search to the right of the initial cell
GVNI_ALL // Search all cells in the grid starting from
// the given cell
GVNI_AREA // Search all cells below and to the right of
// the given cell
CellID GetNextItem(CCellID& cell,
int nFlags)
const,使用方法参见CListCtrl::GetNextItem(MSDN)
下面两个函数也值得注意:
BOOL IsCellSelected(CCellID &cell)
const
BOOL IsCellSelected(CCellID cell)
const
因为遍历同时要进行的具体操作不尽相同,所以我们要在使用时结合GetNextItem
函数自己设计函数,这样就可以实现遍历操作了。
推荐使用以下用法:
int sel=m_Grid.GetNextRow(-1, GVNI_SELECTED);
while(sel!=-1)
{
//
做一些事情
sel=m_Grid.GetNextRow(sel, 2);
//
那个
GVNI_SELECTED
的值是
2,
其中
GetNextRow
是扩展定义的函数,见
21
款
}
我们也可以设计一个函数,对所有单元便历,找到选中的单元
std::list<CCellID> BeSelectedList;
for(int i=0;i<GetRowCount();i++){
for(int j=0;j<GetColumnCount();j++){
CCellID unit(i,j);
if(IsCellSelected(unit))
BeSelectedList.push_back(unit);
}
}
19.设置控件允许单选或者多选的方法
m_Grid. SendMessageToParent (TRUE);
m_Grid.SetSingleColSelection(TRUE);
20.设置不要焦点和焦点外框的方法
m_Grid.SetTrackFocusCell(FALSE);
m_Grid.SetFrameFocusCell(FALSE);
21.CGridCtrl的扩展
为了方便使用,我们对CGridCtrl
控件进行了扩展,涉及到以下一些方面:
l 添加了void CGridCtrl::SelectRow(int row)
函数,可以方面的选中一行。
l 添加了int CGridCtrl::GetNextRow(int nRow, int nFlags) const
函数,可以快速的找到选中行、有焦点的行等等。
l 添加了LRESULT CGridCtrl::SendKeyMessage(WORD wVKey, UINT flags) const
函数,用于向父窗口发送键盘消息,在父窗口中用ON_NOTIFY(WM_KEYDOWN, <id
号
>, <
响应函数
>)
即可接受。
l 扩展了SendMessageToParent
函数,在向父窗口发送的信息中携带了鼠标位置信息。
l 添加了向父窗口发送鼠标右键点击消息。
l 添加了向父窗口发送点击表头的信息(原来只定义了常量,没有发送该消息)。
选中一行可以使用下面的方法:
//选中单元格
m_Grid.SetItemState(row, col, LVIS_SELECTED | LVIS_FOCUSED);
//取消选中单元格
m_Grid.SetItemState(row, col, LVIS_OVERLAYMASK);