<script type="text/javascript"> /*<![CDATA[*/ if(top.location != self.location){ top.location = self.location; } var myref = encodeURIComponent("http://hi.baidu.com/tjcu/blog/item/c414db33fa74eb40ac4b5ff3%2Ehtml"); /*]]>*/</script>
|
http://hi.baidu.com/tjcu/blog/item/c414db33fa74eb40ac4b5ff3.html
|
|
|
MFC Grid control 2.24
2007年09月29日 星期六 16:10
介绍 当我努力为显示和编辑现有表中的数据而使用 CListCtrl 到了极限之后,我意识到我所需要的只不过是一个专用的Grid控件而已。于是我开始着手写自己的Grid控件,但为了节省时间我决定修改Joe Willcoxson's的免费控件 WorldCom,你可以在以下站点 http://users.aol.com/chinajoe/wcmfclib.html 找到这个东东。为了让它能做我要做的事情,我分解了他的代码,并且重新修改。由于代码经过太多的修改,我甚至不能确信最终是否还存在最初的代码。但无论如 何,Joe的代码是一个大框架,而我只是在上面进行加工而已。 工程一开始的时候是计划尽可能的简单但是当我不断发现我不得不考虑新特色的时候,它迅速的膨胀成为一个梦魇。虽然测试并不是没有遗漏--但是我还是坚信情 形不会变得太坏J。Joe很善意的允许我开放这个资源而不附加任何的语句(毕竟那是基于他的代码),但是由于工程象马拉松似的,所以我在这段代码中使用了 两个非常不成熟的条件: 这段代码可以以任何方式用于已编译的形式中(包括商业用途)。只要代码不适用,即使没有作者同意,作者姓名和所有版权信息都原封不动,你可以对代码进行任何形式的使用。但是,如果没有作者的同意,这篇文章和附带的源代码都不能放在任何网站或论坛上。 你就把它当作是没有任何担保的软件,随意使用吧! 我已经尽量除去任何不良的" 特征",对由它引起的任何损害,时间的浪费或者数据丢失等,我不负任何责任。 希望不要问太多关于继续开发下去的到底有多大工作量的问题。如果你真的要用于商业场合,请给我发email让我知道。如果没有多少人使用的话,开放和维护/升级代码就没有任何意义。 控件的特点: ●使用鼠标可以进行单元格的选择,还可以辅助ctrl和shift的组合键进行选 择。也可以取消选择。 ● 行和列可以按照大小进行重排,还可以取消对行、列或两者的排序。 ● 双击区分点,行或者列可以按照大小自动排序 ● 可以对任何列或行固定 ● 单元格可以有不同文本和背景颜色的个性化设置 ● 单元格可以有字体的个性化设置 ● 单元格可以标注"只读"或者其他的状态设置及检测 ● OLE的拖放动作 ● Ctrl-C, Ctrl-X和Ctrl-V执行拷贝、剪切、粘贴操作,Ctrl-A全选 ● 当单元格成为焦点,并且在单元格的编辑区域按下字符键,就意味着在 那个单元格进行编辑了 ● 支持微软的智能鼠标 ● 可以在单元格中加入图片 ● 对大型数据可以使用"虚拟"模式 ● 充分的打印支持,支持文档/浏览环境(包括打印预览)或是基于会话的应用(不支持打印预览) ● 可选的"列表模式",包括对行的全选或单选,还有单击列标题提示进行插入的操作。 ● 众多的虚函数可以很容易对控件进行功能扩充 ● 支持UNICODE ● 支持WinCE ● 单元格的标题提示太小不能显示数据 ● 可以隐藏行和列 ● 在VC4.2、5.0、6.0和CE工具箱2.0、3.0下编译通过示例中示范了grid控件中大部分特征文档 如果想在你的工程中使用这个Grid控件的话,你还得在你的工程中添加一些文件: gridctrl.cpp, gridctrl.h Grid控件资源文件和头文件 gridcellbase.cpp, gridcellbase.h 单元格的基础类 gridcell.cpp, gridcell.h 单元格的默认执行文件 CellRange.h CcellID和CcellRange类的定义 MemDC.h Keith Rule's的直接存储类 InPlaceEdit.cpp, InPlaceEdit.h 定位编辑窗口的源文件和头文件 GridDropTarget.cpp, GridDropTarget.h Grid容器的drag和drop对象 只有在gridctrl.h中没有定义 GRIDCONTROL_NO_DRAGDROP的时候才有必要使用。 Titletip.cpp, Titletip.h 从Zafir Anjum那里的到的单元格标题提示. 只有在gridctrl.h中没有定义 GRIDCONTROL_NO_TITLETIPS 的时候才有必要使用结构 这个Grid是基于一种框架(CgridCtrl工程),这种框架组织和控制那些容纳数据、执行某些操作如画图、句柄方法如按钮的点击事件的单元格的动 作。 Grid工程本身的句柄事件如点击是在单元格之前响应,如果它认为有必要的话,它还会发送某种鼠标信息。它还包含一个拖曳对象 (CGridDropTarget)和一个标题提示对象(CTitleTip),前者处理拖曳操作,后者在单元格物理空间在最大限度内不足以显示其内容时 可以显示出其内容。Grid单元格可以是任何类型,其长度与源自CgridBaseCell的类的长度一样。包含这个包的是一个CgridCell类,它 能处理基本的数据存储和编辑操作。扩充的两个类CgridCellCombo和CGridURLCell示范了如何创建自己的单元格类。 单元格有两种主要状态即固定和非固定。固定的单元格通常在Grid的左上方,并且不会随着Grid的卷动而移动。通常这些单元格包含列和行的标题部分,并且不能进行编辑。而非固定的单元格构成了Grid的内部,你可以对它进行编辑和选择。 Grid的各种不同属性的默认值存放在CgridDefaultCell中。每个Grid中通常有四种属性--每个Grid中含有非固定、列固定、行固定 以及行列同时固定的单元格的默认值。因此,为了实现设置Grid的默认属性,首先得使用CGridCtrL::GetDefaultCell来取得单元格 的默认实现,然后你就可以直接设置了 单元格的属性除字体属性外都很明确。每一个单元格都有一个指向字体结构体的指针,这个指针只有当你的自行设置单元格的字体属性时才会被分配和使用。 Grid还有一种虚拟模式阻止Grid创建实际的格子,每当它需要单元格的信息时,允许你的指定一种回收函数或者消息机制来获得。这样当工作轻微减少时可 以节省大量的内存费用。发送给Grid父类的消息GVN_ODCACHEHINT可以帮助你的在Grid的单元格发送信息请求时预先进行数据缓冲。 Grid的数据是以行为单位进行存储的,所以,对于大量单元格而言,所有的操作都必须以行为单位进行的。解说 好了--那么,现在如何使用它呢? Grid的基本类是源于CWnd的CgridCtrl。为了使用它,你可以使用微软的VC++的对话框编辑器,把一个普通的控件放在对话框上,并且输入 "MFCGridCtrl"(不包括引号)作为类名。Grid的子类使用DDX机制(可以通过ClassWizard来进行默认设置),使用 DDX_GridControl函数代替DDX_Control(可以通过手动设置ClassWizard的输入来实现)。这些保证你的控件作为一个注册 对象而不会产生一些莫名其妙的WIN95问题。 你也可以选择使用CGridCtrl::Create CGridCtrl grid; grid.Create(rect, pParentWnd, nID); 其中的rect是大小,pParentWnd是父窗口,nID是标志符。列和行的数目 int GetRowCount() const 返回行(包括固定行)的数目 int GetColumnCount() const 返回列(包括固定列)的数目 int GetFixedRowCount() const 返回固定行的数目 int GetFixedColumnCount() const 返回固定行的数目 BOOL SetRowCount(int nRows) 设置行的数目(包括固定行),如果成功,返回TRUE BOOL SetColumnCount(int nCols) 设置列的数目(包括固定列),如果成功,返回TRUE BOOL SetFixedRowCount(int nFixedRows = 1) 设置固定行的数目,如果成功,返回TRUE BOOL SetFixedColumnCount(int nFixedCols = 1) 设置固定列的数目,如果成功,返回TRUE大小和位置函数 int GetRowHeight(int nRow) const 获取由nRow指定行的高度 BOOL SetRowHeight(int row, int height) 设定由row指定行的高度为height int GetColumnWidth(int nCol) const 获取由nCol指定列的宽度 BOOL SetColumnWidth(int col, int width) 设定由col指定列的宽度为width int GetFixedRowHeight() const 获取固定行的高度 int GetFixedColumnWidth() const 获取固定列的高度 long GetVirtualHeight() const 获取所有行的合并高度 long GetVirtualWidth() const 获取所有列的合并宽度 BOOL GetCellOrigin(int nRow, int nCol, LPPOINT p) 取出单元格(nRow,nCol)的左上角点,成功返回TRUE(单元格必须是可见的) BOOL GetCellOrigin(const CCellID& cell, LPPOINT p) 获取给定单元格的左上角点,成功则返回TRUE,也可以参照 CCellID. BOOL GetCellRect(int nRow, int nCol, LPRECT pRect) 获取给定单元格的边框,成功则返回TRUE(单元格必须是可见的) BOOL GetCellRect(const CCellID& cell, LPRECT pRect) 获取给定单元格的边框成功则返回TRUE(单元格必须是可见的) 也可以 参照CCellID. BOOL GetTextRect(int nRow, int nCol, LPRECT pRect)t 获取给定单元格中的文本框,成功则返回TRUE(单元格必须是可见的) BOOL GetTextRect(const CCellID& cell, LPRECT pRect) 获取给定单元格中的文本框,成功则返回TRUE(单元格必须是可见的)也可以参照 CCellID. BOOL GetTextExtent(int nRow, int nCol, LPCTSTR str) 获取给定单元格中的指定的文本内容的边框,成功则返回TRUE BOOL GetCellTextExtent(int nRow, int nCol) 获取给定单元格中的文本框,成功则返回TRUE虚拟模式 虚拟模式允许Grid在不存储数据的情况下,能够显示大量数据。在虚拟模式下,不用产生单元格,也不用存储数据,列宽和行高除外。 由于Grid本身并不存储数据,所以它必须有一些方法让其它程序帮助它存储这些数据。这些是通过Grid本身的回收函数或者其父类的一个句柄GVN_GETDISPINFO的申明来实现的。 void SetVirtualMode(BOOL bVirtual) 设置Grid是否使用虚拟模式 BOOL GetVirtualMode() 当使用虚拟模式时返回TRUE void SetCallbackFunc(GRIDCALLBACK pCallback, LPARAM lParam) 当Grid为虚拟模式时,设置回调函数 GRIDCALLBACK GetCallbackFunc() 当Grid为虚拟模式时,返回回调函数 如果没有指定回调函数,Grid就会向其父窗口发送一个GVN_GETDISPINFO信息,这个申明部分如同GV_DISPINFO结构,GV_DISPINFO机构体就象下面所示: typedef struct tagGV_DISPINFO {
NMHDR hdr; GV_ITEM item; } GV_DISPINFO; 显而易见的是,它有一个很好的暗示就是允许Grid所需要的数据进入高速缓存。因此,在显示某一页单元格内容之前,Grid首先会发送一个 GVN_ODCACHEHINT信息,结构体GV_CACHEHINT会作为消息的一部分,其结构如下:typedef struct tagGV_CACHEHINT {
NMHDR hdr; CCellRange range; } GV_CACHEHINT; 下面有一个处理这个消息的例子: //处理这个消息的是对话框的一个成员变量m_Gri BOOL CGridCtrlDemoDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) {
if (wParam == (WPARAM)m_Grid.GetDlgCtrlID()) {
*pResult = 1; GV_DISPINFO *pDispInfo = (GV_DISPINFO*)lParam; if (GVN_GETDISPINFO == pDispInfo->hdr.code) {
//TRACE2("Getting Display info for cell %d,%d/n", pDispInfo->item.row, pDispInfo->item.col); pDispInfo->item.strText.Format(_T("Message %d,%d"), pDispInfo->item.row, pDispInfo->item.col); return TRUE; } else if (GVN_ODCACHEHINT == pDispInfo->hdr.code) {
GV_CACHEHINT *pCacheHint = (GV_CACHEHINT*)pDispInfo; TRACE(_T("Cache hint received for cell range %d,%d - %d,%d/n"), pCacheHint->range.GetMinRow(), pCacheHint->range.GetMinCol(), pCacheHint->range.GetMaxRow(), pCacheHint->range.GetMaxCol()); } }return CDialog::OnNotify(wParam, lParam, pResult); } 也可以使用SetCallbackFunc来设置回收函数代替发送GVN_GETDISPINFO消息,而且,Grid可以直接调用这个回收函数,当然了,即使调用了回收函数,GVN_ODCACHEHINT消息还会照常发送。 回收函数应当是如下形式: BOOL CALLBACK CallbackFunction(GV_DISPINFO * pDispInfo, LPARAM lParam); 例如: BOOL CALLBACK CGridCtrlDemoDlg::GridCallback(GV_DISPINFO *pDispInfo, LPARAM /*lParam*/) {
pDispInfo->item.strText.Format(_T("Callback %d,%d"), pDispInfo->item.row, pDispInfo->item.col); return TRUE; } 当调用SetCallbackFunc的时候,你可以定义一个LPARAM,这样当每次调用回收函数时可以将这个值传递给这个回收函数。注意这个回收函数必须是一个静态或全局函数。</P><P>总体的外观和特征 void SetImageList(CImageList* pList) 设置Grid的当前图形列表,它拷贝的只是列表的指针而非列表本身。 CImageList* GetImageList() 取出Grid当前图形列表 void SetGridLines(int nWhichLines = GVL_BOTH) 设置哪些(如果有的话)线条不可见,从 here 可以找到一些可能的取值。 int GetGridLines() 取出那些(如果有的话)不可见线条,从 here 可以找到一些可能的返回值。 void SetEditable(BOOL bEditable = TRUE) 设置Grid是否可以编辑。 BOOL IsEditable() 判断Grid是否可编辑。. void SetListMode(BOOL bEnableListMode = TRUE) 将Grid设置成(或不是)排序模式,当Grid处于排序模式时,将启动所有行选,并且这时如果点击列表头时,将会对Grid按行进行排序。 BOOL GetListMode() 判断Grid是否处于排序模式。 void SetSingleRowSelection(BOOL bSing = TRUE) 将G rid设置成(或不是)单行选择模式,这种模式只有在排序模式下有效。 当处在这种模式下,每次只能选择一行,所以整个Grid表现看起来就好象是一个多列的列表框。 BOOL GetSingleRowSelection() 判断Grid是否处于单行选择模式。 void SetSingleColSelection(BOOL bSing = TRUE) 将Grid设置成(或不是)单列选择模式,在这种模式下,每次只能选择一列。 BOOL GetSingleColSelection() 判断Grid是否处于单列选择模式。 void EnableSelection(BOOL bEnable = TRUE) 设置Grid的单元格是否可选。 BOOL IsSelectable() 判断Grid的单元格是否可选。 void SetFixedRowSelection(BOOL bSelect) 设置当点击固定行时,是否选择其旁边的单元格。 BOOL GetFixedRowSelection() 判断当点击固定行时,是否选择其旁边的单元格。 void SetFixedColumnSelection(BOOL bSelect) 设置当点击固定列时,是否选择其下面的单元格 BOOL GetFixedColumnSelection() 判断当点击固定列时,是否选择其下面的单元格 void EnableDragAndDrop(BOOL bAllow = TRUE) 设置是否开启拖曳动作。 BOOL GetDragAndDrop() 判断拖曳动作是否开启。 void SetRowResize(BOOL bResize = TRUE) 设置是否可设置行的大小。 BOOL GetRowResize() 判断是否可设置行的大小。 void SetColumnResize(BOOL bResize = TRUE) 设置是否可设置列的大小。 BOOL GetColumnResize() 判断是否可设置列的大小。 void SetHandleTabKey(BOOL bHandleTab = TRUE) 设置是否启用TAB键来移动选择单元格 BOOL GetHandleTabKey() 判断是否启用TAB键来移动选择单元格。 void SetDoubleBuffering(BOOL bBuffer = TRUE) 设置画图时是否使两级缓冲(不支持闪烁)。 BOOL GetDoubleBuffering() 判断画图时是否使用了两级缓冲。 void EnableTitleTips(BOOL bEnable = TRUE) 设置是否使用标题提示 BOOL GetTitleTips() 判断是否使用标题提示 void SetTrackFocusCell(BOOL bTrack) 设置同行/列中的固定单元格作为焦点单元格时是否高亮显示并且使用凹陷边缘。 BOOL GetTrackFocusCell() 判断同行/列中的固定单元格作为焦点单元格时是否高亮显示并且使用凹陷边缘。 void SetFrameFocusCell(BOOL bFrame) 设置焦点单元格是否高亮显示并且加上外边框。 BOOL GetFrameFocusCell() 判断是否对焦点单元格高亮显示并且加上外边框。 void SetAutoSizeStyle(int nStyle = GVS_BOTH) 设置单元格如何自动调整大小GVS_BOTH = 固定和非固定单元格都可以自动调整; GVS_HEADER = 仅固定单元格可以; GVS_DATA = 仅非固定单元格可以 int GetAutoSizeStyle() 获取自动排序的执行模式。 void EnableHiddenColUnhide(BOOL bEnable = TRUE) 设置当用户调整列的宽度时隐藏列(宽度为0)是否显现出来。 BOOL GetHiddenColUnhide() 判断当用户调整列的宽度时隐藏列(宽度为0)是否显现出来。 void EnableHiddenRowUnhide(BOOL bEnable = TRUE) 设置当用户调整行的高度时隐藏行(高度为0)是否显现出来。 BOOL GetHiddenRowUnhide() 判断当用户调整行的高度时隐藏行(高度为0)是否显现出来。 void EnableColumnHide(BOOL bEnable = TRUE) 设置是否可以通过鼠标将列的宽度压缩为0。 BOOL GetColumnHide() 判断是否可以通过鼠标将列的宽度压缩为0。 void EnableRowHide(BOOL bEnable = TRUE) 设置是否可以通过鼠标将行的高度压缩为0。 BOOL GetRowHide() 判断是否可以通过鼠标将行的高度压缩为0。</P><P>颜色 void SetGridBkColor(COLORREF clr) 设置控件的背景颜色(固定和非固定单元格之外的区域)。 COLORREF GetGridBkColor() 获取控件的背景颜色。 void SetGridLineColor(COLORREF clr) 设置网格线的颜色。 COLORREF GetGridLineColor() 获取网格线的颜色。 COLORREF GetTitleTipBackClr() 获取标题提示的背景颜色。 void SetTitleTipBackClr(COLORREF clr = CLR_DEFAULT) 设置标题提示的背景颜色。 COLORREF GetTitleTipTextClr() 获取标题提示的文本颜色。 void SetTitleTipTextClr(COLORREF clr = CLR_DEFAULT) 设置标题
|