分类: C/C++
2008-08-01 16:54:44
幸运的是,CGridCtrl类已经为我们提供了这种机制,它是采用虚模式的方式,要使用这种方式,按照以下的步骤就可以了:
步骤一 初始化
void SetVirtualMode(TRUE) 设为虚模式 BOOL SetRowCount(int nRows) 设置总的行数。 BOOL SetFixedRowCount(int nFixedRows = 1)设置固定的行数据 BOOL SetColumnCount(int nCols) 设置列数 BOOL SetFixedColumnCount(int nFixedCols = 1)设置固定的列数步骤二 响应消息 显示数据
BOOL CMyOdbcDlg::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) { /*这是我们自己加的函数,在这个函数里我们设置当前要显示的数据*/ SetGridItem(pDispInfo); return TRUE; } } return CDialog::OnNotify(wParam, lParam, pResult); }在上面的代码中,SetGridItem(pDispInfo)是我们自己加的函数,在这个函数里我们设置当前要显示的数据,pDispInfo是一个GV_DISPINFO的结构体对象,在这个结构中包含了每个单元格的信息,如行号,列号,有没有位图,背景色,前景色等,CGRIDCTRL会在当前要显示那个单元格时,会把这个单元格的行号,列号传递给我们,我们只要在里面设置要显示的数据就可以了。如下面是一个显示数据的例子。
int CMyOdbcDlg::SetGridItem(GV_DISPINFO *pDispInfo) { pDispInfo->item.strText.Format("row%d,col%d",pDispInfo->item.row, pDispInfo->item.col); return 0; }通过上面的介绍,我们应该已经会使用CGridCtrl虚模式,下面说明一下用CGridCtrl虚模式做DBGRID的原理,大家都知道,MFC的CRecordset类支持多种游标机制,如双向游标的,如果我们是用ClassWizard来生成一个查询的CRecordset的派生类的话,那么可以调用函数CRecordset::SetAbsolutePosition(),用这种方式方式来做DBGRID真是太简单了,因为在上面的int CMyOdbcDlg::SetGridItem(GV_DISPINFO *pDispInfo)函数中,我们已经知道要显示的是哪一行,哪一列的数据,所以只要通过CRecordset::SetAbsolutePosition(pDispInfo->item.row)函数,把游标定位到那一行,然后获取每个字段的数据就可以了。
COdbcDBGridFILE(CGridCtrl *pGrid = NULL, CDatabase *pDatabase = NULL, CString strSql = "", CString strFilePath = ""); //构造函数,必须把所要的变量传递进去。 int InitGrid();//初始化函数 int SetGridText(GV_DISPINFO *pDispInfo);//被外部函数调用接口,用来返回每个单元格应该显示的 int Release();//释放资源按照下面的步骤做一遍,你就能够知道它是不是很实用了。
步骤二
在对话框上,按照上面的样例放上一个CURSTOMER CTROL(就是一个人头的那个控件),在属性的CLASS上输入MFCGridCtrl,ID为IDC_GRIDODBC,然后在放上其它编辑框和按钮控件,为四个编辑框控件通过CLASSWIZARD关联变量
CString m_strPass;//口令 CString m_strSource;//数据源名 CString m_strSql;//查询sql CString m_strUser;//用户名在类CDemo2Dlg中加入下面的几个成员变量
CGridCtrl m_Grid; COdbcDBGRIDFILE *m_pMapFile; CImageList m_ImageList; CDatabase m_db;当然你要在CDemo2Dlg的声明文件中加入
#include "gridctrl.h" #include "OdbcDBGRIDFILE.h"在CDemo2Dlg::DoDataExchange(CDataExchange* pDX)函数中加入DDX_Control(pDX, IDC_GRIDODBC, m_Grid);
m_pMapFile = NULL;步骤三
BOOL CDemo2Dlg::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) { SetGridItem(pDispInfo); return TRUE; } } return CDialog::OnNotify(wParam, lParam, pResult); }在上面的代码中,SetGridItem(pDispInfo)是我们自己加的函数,在这个函数里我们设置当前要显示的数据
void CDemo2Dlg::OnBtnquery() { this->Release();/*这个函数用于释放资源的*/ CString strConn; UpdateData(TRUE); strConn.Format("ODBC;DSN=%s;UID=%s;PWD=%s",m_strSource,m_strUser, m_strPass); BOOL bResult = m_db.Open(strConn); if(bResult == FALSE) { return; }/*上面的代码用于连接数据库*/ m_pMapFile = new COdbcDBGRIDFILE(&m_Grid, &m_db, m_strSql, "c:\\csl.txt"); m_pMapFile->InitGrid();/*初始化函数,用于创建内存映射文件等*/ }在上面的代码中,调用了COdbcDBGRIDFILE的构造函数,它的原型是
void CDemo2Dlg::SetGridItem(GV_DISPINFO *pDispInfo) { /* 在这儿你可自己进行设置,如第一行为查询的字段中文名, 第一行为行的序号等,如果你不进行设置,那么默认会取每 个查询得到的字段名,每一行的序号 */ m_pMapFile->SetGridText(pDispInfo); /* 上面的函数只是用来得到了本来,你还可以用它来进行另 外一些属性,如当超过一定的值是显示DBGRID的不同的前 景色和前景色等 */ }步骤六
void CDemo2Dlg::Release() { if(this->m_pMapFile) { m_pMapFile->Release(); m_db.Close(); delete m_pMapFile; m_pMapFile = NULL; } }在上面的代码中 m_pMapFile->Release()是COdbcDBGRIDFILE的成员函数,用于释放所有的资源。
步骤七
添加对话框的消息响应函数OnClose(),释放所有资源
void CDemo2Dlg::OnClose() { this->Release(); CDialog::OnClose(); }完成好上面的工作,你就可以编译运行了,在上面的编辑框上输入数据源名、用户名、口令和查询的sql语句,你就可以试试效果了,你可以找一张大一点的表,最好有几十万条记录来测试一下,这个DBGRID怎么样。
四、总结
使用这个DBGRID的好处在于我们在查询时,不需要进行先绑定的操作,而且它比微软的DBGRID控件方便多了,希望它能为我们用VC开发数据库项目提高一点效率。如果你看过上一篇文章,用类CMYODBC和CODBCSet来代替MFC的CDatabase和CRecordset的话,那么运行的效率会有很大的提高,我也写了一个相似的类CMyODBCDBGRIDFile,并且用这个类做了一个样例,就是文章篇头提供的配套代码二。