MFC DataGrid





5.00/5 (15投票s)
2002 年 2 月 25 日
2分钟阅读

261723

7585
CDataGrid继承自CGridCtrl,并使用ADO访问数据库。
CDataGrid
之前我开始使用Visual C++操作数据库,但对MS DataGrid不满意。 我编写了自己的类CDataGrid
,它继承自Chris Maunder的CGridCtrl,并使用ADO访问数据库。
示例应用程序
用法 - 分步指南
步骤1- 使用CDataGid
添加到StdAfx.h字符串。
#import "c:\program files\common files\system\ado\msado15.dll" \ no_namespace \ rename ("EOF", "adoEOF") #include <afxtempl.h<afxtempl.h>><afxtempl.h>
在这个例子中,我使用了来自MS SQL 7、2000和Access的Northwind数据库。 你可以在Visual Studio 6.0的第1张光盘上找到nwind.mdb。
接下来,你应该将DataGrid.h和DataGrid.cpp添加到项目中。 你还需要将CGridCtrl
文件添加到项目中。 你可以从这里下载最新版本的CGridCtrl
。(本例使用CGridCtrl
v 2.23)
将ExString.h和ExString.cpp添加到项目中。
将DDXFields.h和DDXFields.cpp添加到项目中。
在这个例子中,我使用了这些类
- Davide Calabro的CButtonST。 这是一个非常有用的位图按钮类。
- Paolo Messina的CResizableDialog。 可调整大小的对话框类对于开发基于对话框的应用程序非常有用。
我开发了CDataComboBox
类,以便从组合框访问数据库。
如果你打算在你的项目中使用CDataComboBox
,你应该将DataComboBox.h和DataComboBox.cpp添加到项目中。
将CDataGrid
变量和连接添加到你的对话框头文件中
#include "DataGrid.h" class CDataGrid_DemoDlg : public CResizableDialog { // Construction public: CDataGrid m_Grid; _ConnectionPtr m_pConnection;
在你的对话框的DoDataExchange
中将网格窗口与C++对象关联起来
DDX_Control(pDX, IDC_GRID, m_Grid);
在OnInitDialog
中添加
m_pConnection.CreateInstance(__uuidof(Connection)); //Create connection try { //Open connection //I prefer to use udl //m_pConnection->Open // (L"File Name=C:\\Program Files\\Common Files\\" // "System\\Ole DB\\Data Links\\nwind.udl", L"", L"", -1); m_pConnection->Open (L"Provider=Microsoft.Jet.OLEDB.4.0;" "Data Source=D:\\DATA\\Nwind.mdb", L"", L"", -1); ...... ...... } catch(_com_error *e) { CString Error = e->ErrorMessage(); AfxMessageBox(e->ErrorMessage()); } catch(...) { } SetFields();
设置网格的字段并在SetFields()
中执行查询。
void CDataGrid_DemoDlg::SetFields() { int n; m_Grid.m_field.SetSize(2); n=0; m_Grid.m_field[n].Field=_T("ProductName"); m_Grid.m_field[n].Caption=_T("Product"); //m_Grid.m_field[n].With=75; m_Grid.m_field[n].Find=true; n=1; m_Grid.m_field[n].Field=_T("QuantityPerUnit"); m_Grid.m_field[n].Caption=_T("QuantityPerUnit"); //m_Grid.m_field[n].With=300; m_Grid.m_field[n].Find=true; ...... ...... m_Grid.Execute(m_pConnection,"ProductId","*","Products","",1); }
因为我们使用CGridCtrl
的虚拟模式,我们必须重写OnNotify
函数。
BOOL CDataGrid_DemoDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { // TODO: Add your specialized code here and/or call the base class if (wParam == (WPARAM)m_Grid.GetDlgCtrlID()) { *pResult = 1; GV_DISPINFO *pDispInfo = (GV_DISPINFO*)lParam; m_Grid.SetValue(pDispInfo); } return CResizableDialog::OnNotify(wParam, lParam, pResult); }
下面的截图向我们展示了DataGrid
的工作情况。
步骤2- 使用CDataComboBox
将DataCombo
控件添加到对话框中,在样式表中选择Drop List
类型。
将CDataGrid
变量添加到你的对话框头文件中
#include "DataComboBox.h" class CDataGrid_DemoDlg : public CResizableDialog { // Construction public: CDataComboBox m_cmbDep; CDataComboBox m_cmbBill;
在你的对话框的DoDataExchange
中将组合框与C++对象关联起来
DDX_Control(pDX, IDC_CMB_CAT, m_cmbCat); DDX_Control(pDX, IDC_CMB_SUP, m_cmbSup);
填充DataComboBox
: DataComboBox
有两种模式:BOUND
和UNBOUND
。
在第3步中,我将向你展示如何使用UNBOUND
模式。 但现在在OnInitDialog
中使用BOUND
模式填充DataComboBox
es。
m_pConnection.CreateInstance(__uuidof(Connection)); //Create connection try { //Open connection //I prefer to use udl //m_pConnection->Open // (L"File Name=C:\\Program Files\\Common Files" // "\\System\\Ole DB\\Data Links\\nwind.udl", L"", L"", -1); m_pConnection->Open (L"Provider=Microsoft.Jet.OLEDB.4.0;" "Data Source=D:\\DATA\\Nwind.mdb", L"", L"", -1); ...... m_cmbCat.Execute(m_pConnection,_ T("SELECT * FROM Categories ORDER BY CategoryName"), _T("CategoryName")); m_cmbSup.Execute(m_pConnection, _T("SELECT * FROM Suppliers ORDER BY CompanyName"), _T("CompanyName")); ...... ...... } catch(_com_error *e) { CString Error = e->ErrorMessage(); AfxMessageBox(e->ErrorMessage()); } catch(...) { } SetFields();
创建主从关系
重写ComboBoxes4
的CBN_SELCHANGE
消息并创建Requery()
函数。 将m_Grid.Execute
从SetFields()
移动到Requery()
。
void CDataGrid_DemoDlg::Requery() { CString strCat,strSup,strWhere; if (!m_cmbCat.IsAddPosition()) { m_strCatId=m_cmbCat.m_pSet->GetCollect(L"CategoryID"); strCat=_T(" CategoryID=")+m_strCatId; } if (!m_cmbSup.IsAddPosition()) { m_strSupId=m_cmbSup.m_pSet->GetCollect(L"SupplierID"); strSup=_T(" SupplierID=")+m_strSupId; } strWhere=strCat; if( ( strSup.GetLength()*strWhere.GetLength() ) ==0 ) strWhere+=strSup; else strWhere+=" AND "+strSup; m_Grid.Execute(m_pConnection,"ProductId"/*Primary key field */ ,"*"//fields in SELECT statment ,"Products" //from ,strWhere // where ,0); // order by N of the Grid column }
下面的截图向我们展示了这种关系是如何工作的。
步骤3- 在DataGrid中更改数据
创建对话框,将编辑框和组合框放入对话框模板中。 将必要的类和变量添加到头文件中。
#include "DataComboBox.h" #include "DDXFields.h" ///////////////////////////////////////////////////////////////////////////// // CDialEdit dialog class CDialEdit : public CDialog { // Construction public: bool m_catChange,m_supChange; _RecordsetPtr m_pSet; CDDXFields m_DDXFields; enum {EDIT, COPY, NEW}; int m_operation; CDataComboBox m_cmbCat; CDataComboBox m_cmbSup; . . . . . .
将控件关联到DoDataExchange
DDX_Control(pDX, IDC_CMB_CAT, m_cmbCat); DDX_Control(pDX, IDC_CMB_SUP, m_cmbSup); m_DDXFields.DDX(pDX);
添加到构造函数中
CDialEdit::CDialEdit(CWnd* pParent /*=NULL*/) : CDialog(CDialEdit::IDD, pParent) { //{{AFX_DATA_INIT(CDialEdit) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_operation=EDIT; m_catChange=m_supChange=false; m_DDXFields.SetSize(5); }
在OnInitDialog
中添加
BOOL CDialEdit::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here int i; m_DDXFields.m_pWnd=this; i=0; m_DDXFields.ElementAt(i).Set(_T( "ProductName" ),IDC_ED_PROD) ; m_DDXFields.ElementAt(i).m_description=_T("Product"); i=1; m_DDXFields.ElementAt(i).Set(_T( "QuantityPerUnit" ), IDC_ED_QTY, _T( "1" ),false,true) ; m_DDXFields.ElementAt(i).m_description=_T("Quantity Per Unit"); i=2; m_DDXFields.ElementAt(i).Set(_T( "UnitPrice" ), IDC_ED_PRICE, _T( "0" ),false,true) ; m_DDXFields.ElementAt(i).m_description=_T("Price") ; i=3; m_DDXFields.ElementAt(i).Set(_T( "UnitsInStock" ), IDC_ED_UNITS, _T( "0" ),false,true) ; m_DDXFields.ElementAt(i).m_description=_T("Units In Stock"); i=4; m_DDXFields.ElementAt(i).Set(_T( "Discontinued" ), IDC_ED_DISCONT,_T( "0" ),false,true) ; switch (m_operation) { case NEW: break; default: m_DDXFields.ReadData(m_pSet); break; } UpdateData(FALSE); m_cmbSup.Fill(); m_cmbCat.Fill(); . . . . . .
在对话框中创建“保存”按钮和函数。
void CDialEdit::OnBtnSave() { // TODO: Add your control notification handler code here CExString strField; UpdateData(); try { switch (m_operation) { case EDIT: break; default: m_pSet->AddNew(); strField=_T("CategoryID"); m_pSet->Fields->GetItem (strField.Variant())->Value = m_catId.Variant(); strField=_T("SupplierID"); m_pSet->Fields->GetItem (strField.Variant())->Value = m_supId.Variant(); break; } try { if( m_DDXFields.WriteData(m_pSet)==-1) return; } catch(...) { ; } CExString strCatId,strSupId; strCatId=m_cmbCat.GetCurId(); strSupId=m_cmbSup.GetCurId();; if(strCatId!=m_catId) { m_catChange=true; strField=_T("CategoryID"); m_pSet->Fields->GetItem (strField.Variant())->Value=strCatId.Variant(); } if(strSupId!=m_supId) { m_supChange=true; strField=_T("SupplierID"); m_pSet->Fields->GetItem (strField.Variant())->Value=strSupId.Variant(); } m_pSet->Update(); CDialog::OnOK(); }//try catch( _com_error &e ) { CString mes1,mes2,mes3,mes4; mes1.Format(_T("Error:%08lx.\n"), e.Error()); mes2.Format(_T("ErrorMessage:%s.\n"), e.ErrorMessage()); mes3.Format(_T("Source:%s.\n"), (LPCTSTR) _bstr_t(e.Source())); mes4.Format(_T("Description:%s.\n"), (LPCTSTR) _bstr_t(e.Description())); MessageBox(mes1+mes2+mes3+mes4, _T("Invalid field "),MB_ICONERROR); return; } catch(...) { MessageBox(_T("Unhandled Exception"), _T("Invalid field ")+strField,MB_ICONERROR); return; } }
在主对话框类的定义中插入CArrayStringBox
变量,因为我们在UNBOUND
模式下使用m_cmbSup
和m_cmbCat
。
class CDataGrid_DemoDlg : public CResizableDialog { // Construction public: CArrayStringBox m_SupArray; CArrayStringBox m_CatArray;
在主对话框的OnInitDialog
中填充它。
try { //Open connection //I prefer to use udl //m_pConnection->Open // (L"File Name=C:\\Program Files\\" // "Common Files\\System\\Ole DB\\Data Links\\nwind.udl", // L"", L"", -1); m_pConnection->Open(L"Provider=Microsoft.Jet.OLEDB.4.0;" "Data Source=D:\\DATA\\Nwind.mdb", L"", L"", -1); . . . . . . m_CatArray.Fill(m_pConnection, _T("SELECT * FROM Categories ORDER BY CategoryName"), _T("CategoryName"),_T("CategoryID")); m_SupArray.Fill(m_pConnection, _T("SELECT * FROM Suppliers ORDER BY CompanyName"), _T("CompanyName"),_T("SupplierID")); } catch(_com_error *e) { CString Error = e->ErrorMessage(); AfxMessageBox(e->ErrorMessage()); } catch(...) { }
在主对话框中创建“编辑”、“添加”、“复制”和“删除”按钮和函数
#include "DialEdit.h" void CDataGrid_DemoDlg::OnBtnEdit() { // TODO: Add your control notification handler code here int nRow=m_Grid.IsSelectRow(); if(nRow==-1) return; CDialEdit dlg; dlg.m_pSet=m_Grid.m_pSet; dlg.m_catId=m_Grid.m_pSet->GetCollect(L"CategoryID") ; dlg.m_supId=m_Grid.m_pSet->GetCollect(L"SupplierID") ; dlg.m_cmbCat.Attach(&m_CatArray,dlg.m_catId); dlg.m_cmbSup.Attach(&m_SupArray,dlg.m_supId); dlg.m_operation=CDialEdit::EDIT; if (dlg.DoModal() == IDOK) { if( ((dlg.m_catChange)&&(!m_cmbCat.IsAddPosition())) || ( (dlg.m_supChange)&&(!m_cmbSup.IsAddPosition()) ) ) { if(nRow==1) { if(1!=m_Grid.GetRowCount()) m_Grid.SetRowFocus(nRow); else m_Grid.SetRowFocus(0); } else { m_Grid.SetRowFocus(nRow-1); } m_Grid.RequerySource(); } else m_Grid.Invalidate(); } } void CDataGrid_DemoDlg::OnBtnAd() { // TODO: Add your control notification handler code here CDialEdit dlg; dlg.m_pSet=m_Grid.m_pSet; dlg.m_catId=m_Grid.m_pSet->GetCollect(L"CategoryID") ; dlg.m_supId=m_Grid.m_pSet->GetCollect(L"SupplierID") ; dlg.m_cmbCat.Attach(&m_CatArray,dlg.m_catId); dlg.m_cmbSup.Attach(&m_SupArray,dlg.m_supId); dlg.m_operation=CDialEdit::NEW; if (dlg.DoModal() == IDOK) { m_Grid.AddNew(); } } void CDataGrid_DemoDlg::OnBtnCopy() { // TODO: Add your control notification handler code here if(m_Grid.IsSelectRow()==-1) return; CDialEdit dlg; dlg.m_pSet=m_Grid.m_pSet; dlg.m_operation=CDialEdit::COPY; dlg.m_catId=m_Grid.m_pSet->GetCollect(L"CategoryID") ; dlg.m_supId=m_Grid.m_pSet->GetCollect(L"SupplierID") ; dlg.m_cmbCat.Attach(&m_CatArray,dlg.m_catId); dlg.m_cmbSup.Attach(&m_SupArray,dlg.m_supId); if (dlg.DoModal() == IDOK) { m_Grid.AddNew(); } } void CDataGrid_DemoDlg::OnBtnDel() { // TODO: Add your control notification handler code here m_Grid.Delete(); }
添加菜单,查找对话框,你的应用程序就准备好了。