从数据库表读入数据显示在对话框
一、前情回顾
1、新建一个工程,如下图所示。
2、建立菜单,并添加消息响应函数,如下图所示。
3、接下来在对话框中进行相应操作,具体步骤如下图所示。
①插入Dialog,并对其相关属性做修改,如下图所示。
②添加一些控件,如下图所示。
③对添加的控件属性做相关的修改,如下图所示。
4、建立类向导,取类名“CDlgStuInfo”,如下图所示。
5、接下来,我们通过编程添加一些数据。首先在CdlgStuInfo中右击添加消息响应句柄“WM_INITDIALOG”,如下图所示。
6、在OnInitDialog() 中添加代码,如下。
BOOL CDlgStuInfo::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
DWORD dwStyle;
dwStyle = m_listCtrl.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_ONECLICKACTIVATE;
m_listCtrl.SetExtendedStyle(dwStyle);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
(记得要把头文件:#include "DlgStuInfo.h"对话框类嵌入进去!)
7、在OnMStuInfo()中添加代码,如下。
void CChapterView::OnMStuInfo()
{
// TODO: Add your command handler code here
CDlgStuInfo dlg_stuInfo;
dlg_stuInfo.DoModal();
}
8、此时,运行结果如下图所示。
9、新建一个“添加学生信息”对话框,建立类向导,并添加成员变量,具体如下图所示。
10、双击“添加信息”按钮,把“添加学生信息”这个对话框给调出来,如下图所示。
11、把“添加学生信息”对话框的头文件:#include "Dlg_StuInfoAppe.h"嵌入进来。然后在OnBTNAppe()中编程。
void CDlgStuInfo::OnBTNAppe()
{ //添加学生信息按钮
// TODO: Add your control notification handler code here
CDlg_StuInfoAppe dlg_stuInfoAppe;
dlg_stuInfoAppe.DoModal();
}
12、新建一个“修改学生信息”对话框(可将步骤9中的控件全选复制粘贴进来),建立类向导,并添加成员变量,具体如下图所示。
13、双击“修改信息”按钮,把“修改学生信息”这个对话框给调出来,如下图所示。
14、把“修改学生信息”对话框的头文件:#include "Dlg_StuInfoModi.h"嵌入进来。然后在OnBTNModi()中编程。
void CDlgStuInfo::OnBTNModi()
{ //修改学生信息按钮
// TODO: Add your control notification handler code here
CDlg_StuInfoModi dlg_stuInfoModi;
dlg_stuInfoModi.DoModal();
}
15、新建一个“删除学生信息”对话框(可将步骤9中的控件全选复制粘贴进来),建立类向导,并添加成员变量,具体如下图所示。
16、双击“删除信息”按钮,把“删除学生信息”这个对话框给调出来,如下图所示。
17、把“删除学生信息”对话框的头文件:#include "Dlg_StuInfoDele.h"嵌入进来。然后在OnBTNDele()中编程。
void CDlgStuInfo::OnBTNDele()
{ //删除学生信息按钮
// TODO: Add your control notification handler code here
CDlg_StuInfoDele dlg_stuInfoDele;
dlg_stuInfoDele.DoModal();
}
18、如何分别把 “添加学生信息”、“修改学生信息”和“删除学生信息”对话框中要添加、修改和删除的记录更新到上一个 “学生档案信息”对话框的列表中去,是我们的目的。
19、我们回到IDD_DlgStuInfo对话框,选中对话框,右击选择“事件…”,在弹出的事件句柄中选择“NM_CLICK”,如下图所示。(为接下来的工作做准备)
20、先来编译运行看看效果吧。
二、导入外部资源
1、新建Ado.h和Ado.cpp这样两个类,并添加代码,如下图所示。
代码如下:
①Ado.h中的代码:
#ifndef _ADO_H_
#define _ADO_H_
#import "C:\Program Files\Common Files\System\ado\msado60_Backcompat_i386.tlb" no_namespace rename("EOF","adoEOF")\
rename("LockTypeEnum","adoLockTypeEnum")\
rename("FieldAttributeEnum","adoFieldAtttributeEnum")\
rename("EditModeEnum","adoEditModeEnum")\
rename("RecordStatusEnum","adoRecordStatusEnum")\
rename("ParameterDirectionEnum","adoParameterDirectionEnum")\
rename("DataTypeEnum","adoDataTypeEnum")
//#import ".\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
class CAdo//:public CSingleton<CAdo>
{
public:
static CAdo& getSingleton()
{
static CAdo mInstance;
return mInstance;
}
public:
_RecordsetPtr m_pRecordset;
_ConnectionPtr m_pConnection;
public:
//构造函数
CAdo();
//析构函数
virtual ~CAdo();
//access数据库引擎打开
void OnInitADOConn();
void OnInitADOConn(CString sourcePath);
//SqlServer 数据库引擎打开
void OnInitADOConnSQLServer();
public:
//查询语句获取记录集
_RecordsetPtr& GetRecordSet(_bstr_t bstrSQL);
_RecordsetPtr& GetRecordSet(CString strSQL);
//执行sql语句
BOOL ExecuteSQL(_bstr_t bstrSQL);
BOOL ExecuteSQL(CString strSQL);
//从某一个字段读取数据
CString GetCollect(CString strField);
CString GetCollect(CString strField,_RecordsetPtr& recordSet);
//释放连接
void ExitConnect();
//显示错误信息
void ExpressErrInfo(_com_error e);
};
#endif //_ADO_H_
②Ado.cpp中的代码:
#include "stdafx.h"
#include "Ado.h"
#include <string>
CAdo::CAdo()
{
}
CAdo::~CAdo()
{
}
void CAdo::OnInitADOConn()
{
/// 以单线程的方式创建com对象
::CoInitialize(NULL);
try
{
m_pConnection.CreateInstance("ADODB.Connection"); // 创建Connection对象
char pBuf[MAX_PATH]; // 存放路径的变量
CString DBpath,strConnect;
//DBpath = "./db.mdb";
DBpath = "./DB_CSMT.mdb";
strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Persist Security Info=False;Mode=Share Deny None"),DBpath);
m_pConnection->Open((_bstr_t)strConnect,"","",adModeUnknown); // 连接数据库
}
catch(_com_error e)
{
//AfxMessageBox(_T("OnInitADOConn()"));
ExpressErrInfo(e);
}
}
void CAdo::OnInitADOConn(CString sourcePath)
{
/// 以单线程的方式创建com对象
::CoInitialize(NULL);
try
{
m_pConnection.CreateInstance("ADODB.Connection"); // 创建Connection对象
char pBuf[MAX_PATH]; // 存放路径的变量
CString strConnect;
strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Persist Security Info=False;Mode=Share Deny None"),sourcePath);
m_pConnection->Open((_bstr_t)strConnect,"","",adModeUnknown); // 连接数据库
}
catch(_com_error e)
{
ExpressErrInfo(e);
}
}
void CAdo::OnInitADOConnSQLServer()
{
::CoInitialize(NULL);
try
{
m_pConnection.CreateInstance("ADODB.Connection");
CString strConnect;
strConnect.Format(_T("Provider=SQLOLEDB;Data Sourse=Sql Server;Initial Catalog=master;User ID=sa;Password=sa"));
m_pConnection->Open((_bstr_t)strConnect,"","",adModeUnknown);
}
catch(_com_error e)
{
ExpressErrInfo(e);
}
}
_RecordsetPtr& CAdo::GetRecordSet(_bstr_t bstrSQL)
{
try
{
if (NULL == m_pConnection)
{
OnInitADOConn();
}
m_pRecordset.CreateInstance(__uuidof(Recordset));
if (adStateOpen == m_pRecordset->State)
{
AfxMessageBox(_T("记录集打开"));
m_pRecordset->Close();
}
m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenStatic,adLockOptimistic,adCmdText);
}
catch(_com_error e)
{
ExpressErrInfo(e);
}
return m_pRecordset;
}
_RecordsetPtr& CAdo::GetRecordSet(CString strSQL)
{
_bstr_t bstrSQL = (_bstr_t)strSQL;
try
{
if(m_pConnection == NULL)
OnInitADOConn();
m_pRecordset.CreateInstance(__uuidof(Recordset));
//adStateClosed != m_recordset->GetState()
if(m_pRecordset->State == adStateOpen)
{
//AfxMessageBox(L"记录集打开");
m_pRecordset->Close();
//m_pRecordset=NULL;
}
m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenStatic,adLockOptimistic,adCmdText);
//m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
variant_t m_dirno;
}
catch(_com_error e)
{
ExpressErrInfo(e);
}
return m_pRecordset;
}
BOOL CAdo::ExecuteSQL(_bstr_t bstrSQL)
{
_variant_t RecordsAffected;
try
{
if (NULL == m_pConnection)
{
OnInitADOConn();
}
m_pConnection->Execute(bstrSQL,NULL,adCmdText);
return TRUE;
}
catch(_com_error e)
{
ExpressErrInfo(e);
}
return FALSE;
}
BOOL CAdo::ExecuteSQL(CString strSQL)
{
_bstr_t bstrSQL;
_variant_t RecordsAffected;
bstrSQL = (_bstr_t)strSQL;
try
{
if(m_pConnection==NULL)
OnInitADOConn();
m_pConnection->Execute(bstrSQL,NULL,adCmdText);
return true;
}
catch(_com_error e)
{
ExpressErrInfo(e);
return false;
}
}
CString CAdo::GetCollect(CString strField)
{
CString strValue;
_variant_t variValue,variField;
variField = (_variant_t)strField;
variValue = m_pRecordset->GetCollect(variField);
if( variValue.vt != VT_NULL)
{
strValue = (char *) _bstr_t (variValue);
}
return strValue;
}
CString CAdo::GetCollect(CString strField,_RecordsetPtr& recordSet)
{
CString strValue;
_variant_t variValue,variField;
variField = (_variant_t)strField;
variValue = recordSet->GetCollect(variField);
if( variValue.vt != VT_NULL)
{
strValue = (char *) _bstr_t(variValue);
}
return strValue;
}
//释放连接
void CAdo::ExitConnect()
{
try
{
if(m_pRecordset!=NULL && m_pRecordset->State != NULL)
{
m_pRecordset->Close();
m_pRecordset = NULL;
}
if( m_pConnection->State == adStateOpen)
{
m_pConnection->Close();
m_pConnection = NULL;
}
::CoUninitialize();
}
catch(_com_error e)
{
ExpressErrInfo(e);
}
}
//显示数据库错误信息
void CAdo::ExpressErrInfo(_com_error e)
{
CString ErrorStr;
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
ErrorStr.Format( "ADO Error Code meaning = %s Source = %s Description = %s",
e.ErrorMessage(), (LPCTSTR)bstrSource, (LPCTSTR)bstrDescription );
//在调试窗口中打印错误信息,在Release版中可用DBGView查看错误信息
AfxMessageBox(ErrorStr, MB_OK | MB_ICONERROR);
}
2、将我们事先写好的student.mdb文件导入对应的工程目录下,如下图所示。
3、通过数据库记录的表,把数据库中记录读出来,这个“读”的代码,我们通过重载对话框OnInitDialog()来实现,如下图所示。
代码如下:
BOOL CDlgStuInfo::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CString strSql,strSNo,strSName,strSSex,strSDept,strSClass;
//strSql是查询语句的变量,后面的几个是数据库表中记录的字段名
DWORD dwStyle; //定义列表框风格
int i = 0;
strSql = "select * from student"; //查询语句,提取数据库中所有记录
m_ado.OnInitADOConn(".\\student.mdb"); //打开当前工程文件夹下的mdb,一个“.”代表当前目录
m_ado.GetRecordSet(strSql); //执行语句
dwStyle = m_listCtrl.GetExtendedStyle(); //获取列表控件的风格
dwStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_ONECLICKACTIVATE; //加入你所需要的风格
m_listCtrl.SetExtendedStyle(dwStyle); //设置显示风格
m_listCtrl.InsertColumn(i++,"学号",LVCFMT_CENTER,100);
m_listCtrl.InsertColumn(i++,"姓名",LVCFMT_CENTER,100);
m_listCtrl.InsertColumn(i++,"性别",LVCFMT_CENTER,100);
m_listCtrl.InsertColumn(i++,"专业",LVCFMT_CENTER,100);
m_listCtrl.InsertColumn(i++,"班级",LVCFMT_CENTER,100); //设置字段名
i = 0;
while (!m_ado.m_pRecordset->adoEOF) //通过内置的记录集调用,判断当前记录是否已经到了记录集的最后一个
{ //若没有到记录集,我们进行循环
strSNo = m_ado.GetCollect("SNo");
//通过m_ado对象获取当前记录的字段值
strSName = m_ado.GetCollect("SName");
strSSex = m_ado.GetCollect("SSex");
strSDept = m_ado.GetCollect("SDept");
strSClass = m_ado.GetCollect("SClass");
m_listCtrl.InsertItem(i,strSNo); //插入到列表控件中去
m_listCtrl.SetItemText(i,1,strSName);
m_listCtrl.SetItemText(i,2,strSSex);
m_listCtrl.SetItemText(i,3,strSDept);
m_listCtrl.SetItemText(i,4,strSClass);
m_ado.m_pRecordset->MoveNext(); //记录指针向下移动一个单位
i++; //为下一次插入列表控件做准备
}
//i--;
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
4、此时我们来编译运行看看效果吧。
5、很明显,我们已经成功将提前写入数据库表中的数据通过对话框“读”出来了。那么下面,我们做添加、修改、删除这样一些操作。
三、添加、修改、删除的实现
Ⅰ 添加
思路:首先把数据库中的记录全部删掉,然后再把当前控件列表中的数据重新写入到数据库中。
1、代码如下。
void CDlgStuInfo::OnBTNAppe() //添加学生信息按钮
{
// TODO: Add your control notification handler code here
int i;
CDlg_StuInfoAppe dlg_stuInfoAppe;
if(IDOK == dlg_stuInfoAppe.DoModal())
{
m_strSno = dlg_stuInfoAppe.m_sNo;
m_strSname = dlg_stuInfoAppe.m_sName;
m_strSex = dlg_stuInfoAppe.m_sSex;
m_strDept = dlg_stuInfoAppe.m_sDept;
m_strClass = dlg_stuInfoAppe.m_sClass; //把“添加学生信息”对话框中的数据传过来,保存到学生档案信息对话框中
//i = m_listCtrl.GetItemCount() - 3; //获取当前记录的数
i = 10; //刚开始我们有10条记录
//int pos; //添加的位置
//pos = m_listCtrl.GetItemCount();
m_listCtrl.InsertItem(i,m_strSno);
m_listCtrl.SetItemText(i,1,m_strSname);
m_listCtrl.SetItemText(i,2,m_strSex);
m_listCtrl.SetItemText(i,3,m_strDept);
m_listCtrl.SetItemText(i,4,m_strClass); //把获取进来的数据插进去
CString strSql = "delete from student"; //清除数据库中的数据
m_ado.ExecuteSQL(strSql);
int recCount = m_listCtrl.GetItemCount(); //控件列表里面新增加的一条记录以后,它的记录总数
for(i = 0; i < recCount; i++)
{
m_strSno = m_listCtrl.GetItemText(i, 0);
m_strSname = m_listCtrl.GetItemText(i, 1);
m_strSex = m_listCtrl.GetItemText(i, 2);
m_strDept = m_listCtrl.GetItemText(i, 3);
m_strClass = m_listCtrl.GetItemText(i, 4); //获取当前控件列表里的信息
strSql.Format("insert into student (SNo,SName,SSex,SDept,SClass) values('%s','%s','%s',\
'%s','%s')",m_strSno,m_strSname,m_strSex,m_strDept,m_strClass); //在VC和C语言里面,续航符用“\”
m_ado.ExecuteSQL(strSql);
//把控件列表中的数据更新到数据库里面去。更新思路是:首先把数据库中的记录全部删掉,然后再把当前控件列表中的数据重新写入到数据库中
}
UpdateData(FALSE);
}
}
2、编译运行结果如下图所示。
Ⅱ 修改
思路:刚开始的时候选中记录,再点击“修改信息”按钮。选中记录是通过鼠标点击,是对列表控件的点击,通过点击事件把我们的编号记录下来,记录下来后,通过被选中记录的学号,把相应的数据载进去(要求学号是不允许修改的),所以我们要将“修改学生信息”对话框里的学号编辑框>>属性>>样式前的“只读”勾选上,此时运行后的学号里的内容就修改不了了。如下图所示。
1、代码如下。
点击事件的代码:
void CDlgStuInfo::OnClickListStuInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int pos;
pos = m_listCtrl.GetSelectionMark(); //获取当前被鼠标选中的行
m_strSno = m_listCtrl.GetItemText(pos,0); //把我们被选中的这条记录的相关信息读到显示对话框的成员变量中去
m_strSname = m_listCtrl.GetItemText(pos,1);
m_strSex = m_listCtrl.GetItemText(pos,2);
m_strDept = m_listCtrl.GetItemText(pos,3);
m_strClass = m_listCtrl.GetItemText(pos,4);
//UpdateData(TRUE);
selPos = pos;
*pResult = 0;
}
修改的代码:
void CDlgStuInfo::OnBTNModi() //修改学生信息按钮
{
// TODO: Add your control notification handler code here
CDlg_StuInfoModi dlg_stuInfoModi;
dlg_stuInfoModi.m_sNo = m_strSno;
dlg_stuInfoModi.m_sName = m_strSname;
dlg_stuInfoModi.m_sSex = m_strSex;
dlg_stuInfoModi.m_sDept = m_strDept;
dlg_stuInfoModi.m_sClass = m_strClass;
if (dlg_stuInfoModi.DoModal() == IDOK) //把修改后的数据写回到当前显示窗口
{
m_strSno = dlg_stuInfoModi.m_sNo;
m_strSname = dlg_stuInfoModi.m_sName;
m_strSex = dlg_stuInfoModi.m_sSex;
m_strDept = dlg_stuInfoModi.m_sDept;
m_strClass = dlg_stuInfoModi.m_sClass;
m_listCtrl.SetItemText(selPos,0,m_strSno);
m_listCtrl.SetItemText(selPos,1,m_strSname);
m_listCtrl.SetItemText(selPos,2,m_strSex);
m_listCtrl.SetItemText(selPos,3,m_strDept);
m_listCtrl.SetItemText(selPos,4,m_strClass);
CString strSql;
strSql.Format("update student set SName = '%s',SSex = '%s',SDept = '%s',SClass = '%s'\
where SNo = '%s'",m_strSname,m_strSex,m_strDept,m_strClass,m_strSno);
//根据当前“修改学生信息”对话框里的学号进行修改,通过学号定位到数据库表中相同的记录,对它进行更新
m_ado.ExecuteSQL(strSql);
}
}
2、编译运行结果如下图所示。
Ⅲ 删除
思路:首先在列表控件上把它删除掉,再通过delete语句到数据库表中把对应的记录删除掉,这个删除同样也是根据学号来的。
1、代码如下。
void CDlgStuInfo::OnBTNDele() //删除学生信息按钮
{
// TODO: Add your control notification handler code here
int pos;
pos = m_listCtrl.GetSelectionMark(); //获取当前被鼠标选中的行
m_listCtrl.DeleteItem(pos);
CString strSql;
strSql.Format("delete from student where SNo = '%s'",m_strSno);
m_ado.ExecuteSQL(strSql);
}
2、编译运行结果如下图所示。
四、全剧终
没有小结,强加练习才是王道!
加油!