加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
MFC中最简单的数据库应用
acmilan2015/05/19软件综合 IP:四川
在计算机编程中,最实用的技术莫过于数据库应用了,特别是访问本地数据库的方法。可以说访问数据库是计算机编程的必备技能。在MFC中访问数据库其实很容易的。
首先,你需要一个*.mdb的数据库(不能是*.accdb),可以使用Microsoft Access来生成:
捕获.png

然后在里边新建一个表,添加一些字段,关闭
然后按照常规方法新建一个MFC工程(单文档、多文档、对话框均可,在这里我建立一个对话框程序):
捕获2.png

然后需要在stdafx.h里加入这一句,添加数据库支持:
C++
// 添加数据库支持 #include <afxdb.h></afxdb.h>
由于使用的是基于对话框的程序,因此需要手动添加数据库支持。随后打开资源视图找到主对话框,设计如下的界面:
捕获4.png

注意ComboBox组合框需要添加一个变量,这里设为m_combobox。然后分别双击四个按钮添加单击代码。

------- 我是讲解的分割线 -------

在MFC中,数据库有两个常用类:CDatabase和CRecordset。CDatabase用于打开数据库和执行SQL命令,而CRecordset则提供了一种直观的方法访问数据库记录。在这里我不准备给大家详细解读这两个类的用法,只教给大家比较简单的用法:如何打开数据库,执行SQL语句,遍历数据记录,关闭数据库。

一、如何打开本地数据库
打开本地数据库不是很难,只是要记住一个ODBC连接地址格式,格式如下:
"ODBC;Engine={引擎名称};DSN='';DBQ=文件名"
这个格式是固定的,其中我们用到的引擎是"Microsoft Access Driver (*.mdb)",即访问Access本地数据库。
由于程序中经常需要数据库,因此需要将数据库对象定义为对话框类(DataBaseTest1Dlg.h)中的一个类变量:
Other
CDatabase m_dbfile;
代码如下:
Java
void CDataBaseTest1Dlg::OnBnClickedDbopen() {     CString sDriver = "Microsoft Access Driver (*.mdb)"; // 数据库引擎     CString sFile = "Database.mdb"; // 数据库路径     CString sConnect;                                                // 用CString::Format构造数据库的连接地址     sConnect.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,sFile);                                                // 构造后的地址:"ODBC;DRIVER={Microsoft Access Driver (*.mdb)};DSN='';DBQ=Database.mdb"                                                    // 建议在try块中进行数据库操作     try     {         // 打开数据库(简单用法)         m_dbfile.Open(NULL, false, false, sConnect);                                                    // TODO: 访问数据库     }     catch(CDBException &e) // 数据库失败时     {          AfxMessageBox("数据库连接失败,确认数据库Database.mdb是否在当前路径下!");          return;     }                                                }                      // CDatabase::Open()函数共有5个参数: // 参数1是DSN地址,这里留空 // 参数2是独占连接,默认为false // 参数3是只读连接,默认为false // 参数4是连接地址 // 参数5是是否使用游标库,默认为true,这里省略
访问数据库强烈建议在try catch块中进行,并捕捉CDBException,因为如果不捕捉很可能导致程序崩溃。

二、执行SQL语句
执行SQL语句很简单,直接使用ExecuteSQL("SQL语句")即可。如以下语句删除表datatable中的所有数据。
Other
m_dbfile.ExecuteSQL("DELETE FROM datatable");

三、遍历数据记录
遍历数据记录要用到CRecordset,它提供了方便的访问数据记录的途径,建立CRecordset的方法:
Other
CRecordset recset(&m_dbfile);
建立了记录集以后还要打开它,打开它需要一个SELECT查询:
Other
// 需要一个select查询语句以打开记录集 CString sqlstr =  "SELECT id, context FROM datatable ORDER BY id ASC";              recset.Open(CRecordset::forwardOnly, sqlstr, CRecordset::readOnly);                      // CRecordset::Open()函数共有3个参数: // 参数1是打开类型,有forwardOnly、snapshot、dynaset、dynamic,默认是snapshot // 参数2是SQL语句 // 参数3是打开选项,这里是readOnly,表示只读
这里我们只需要遍历,因此选择了forwardOnly和readOnly模式。
打开以后便可以遍历了。遍历最简单的方法就是使用GetFieldValue("字段名", str1);来获取数据,并使用MoveNext()移动到下一条记录,使用IsEOF()判断是否遍历完毕:
Other
while (!recset.IsEOF()) { // 判断是否读取完毕                                              // 通过 GetFieldValue("字段名", &str); 获取当前记录中各字段的数据     CString strID;     recset.GetFieldValue("id", strID);                                              CString strContext;     recset.GetFieldValue("context", strContext);                                                                      // TODO: 使用获得的数据                                              // 移向下一条记录     recset.MoveNext(); }
最后可以用Close()手动关闭记录集(一般不用手动关闭):
Other
recset.Close();

四、关闭数据库也很简单,直接Close()即可。为了避免重复Close(),可以先用IsOpen()判断一下:
Other
if (m_dbfile.IsOpen()) { // 如果数据库已打开     m_dbfile.Close(); // 关闭数据库 }
这个IsOpen()函数也可以用在其它的数据库操作上,以避免在未打开数据库的情况下访问数据库。

------- 我是源代码的分割线 -------

附上源代码和例程(无毒):
程序运行效果图:
捕获5.png
attachment icon DataBaseTest1.rar 331.87KB RAR 127次下载

[修改于 10年1个月前 - 2015/05/24 22:57:56]

来自:计算机科学 / 软件综合
3
 
新版本公告
~~空空如也
acmilan 作者
10年1个月前 IP:四川
769356
附上重要的程序源代码:
stdafx.h文件:
C++
// stdafx.h : 标准系统包含文件的包含文件, // 或是经常使用但不常更改的 // 特定于项目的包含文件    // ... 其它代码 ...    #include <afxdb.h></afxdb.h>
DataBaseTest1Dlg.h文件:
C++
// DataBaseTest1Dlg.h : 头文件 //    #pragma once #include "afxwin.h"    // CDataBaseTest1Dlg 对话框 class CDataBaseTest1Dlg : public CDialog {     // ... 其它代码 ... public:     CComboBox m_combobox;     CDatabase m_dbfile;        // ... 其它代码 ... };
DataBaseTest1Dlg.cpp文件:
PHP
// DataBaseTest1Dlg.cpp : 实现文件 //    // ... 其它代码 ...    void CDataBaseTest1Dlg::DoDataExchange(CDataExchange* pDX) {     CDialog::DoDataExchange(pDX);     DDX_Control(pDX, IDC_COMBO1, m_combobox); }      // ... 其它代码 ...      void CDataBaseTest1Dlg::OnBnClickedAdd() {     CString str1;     m_combobox.GetWindowText(str1);     if (str1 != "") {         m_combobox.AddString(str1);         m_combobox.SetWindowText("");         SuspendDataToDB(); // 更新数据库     } }      void CDataBaseTest1Dlg::OnBnClickedDel() {     int cur = m_combobox.GetCurSel();     if (cur >= 0) { // 返回-1则没有选择任何对象         m_combobox.DeleteString(cur);         SuspendDataToDB(); // 更新数据库     } }      void CDataBaseTest1Dlg::OnBnClickedDbopen() {     CString sDriver = "Microsoft Access Driver (*.mdb)"; // 数据库引擎     CString sFile = "Database.mdb"; // 数据库路径     CString sConnect;          // 构造数据库的连接地址     sConnect.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,sFile);          // 构造后的地址:"ODBC;DRIVER={Microsoft Access Driver (*.mdb)};DSN='';DBQ=Database.mdb"              // 建议在try块中进行数据库操作     try     {         // 打开数据库(简单用法)         // 参数1是DSN地址,这里留空         // 参数2是独占连接,默认为false         // 参数3是只读连接,默认为false         // 参数4是连接地址         // 参数5是是否使用游标库,默认为true         m_dbfile.Open(NULL, false, false, sConnect);              // 更改标题栏         SetWindowText("数据库测试:数据库已连接");              // 加载数据库内容到程序         LoadDataFromDB();     }     catch(CDBException &e) // 数据库失败时     {          AfxMessageBox("数据库连接失败,确认数据库Database.mdb是否在当前路径下!");          return;     }          }      void CDataBaseTest1Dlg::OnBnClickedDbclose() {     if (m_dbfile.IsOpen()) { // 如果数据库已打开         m_dbfile.Close(); // 关闭数据库         SetWindowText("数据库测试:数据库已断开");     } }      void CDataBaseTest1Dlg::OnClose() {     if (m_dbfile.IsOpen()) {         m_dbfile.Close();         SetWindowText("数据库测试:数据库已断开");     }          CDialog::OnClose(); }      void CDataBaseTest1Dlg::SuspendDataToDB(void) {     if (m_dbfile.IsOpen()) { // 数据库操作         try {             CString strSql;                  // 删除所有记录             m_dbfile.ExecuteSQL("DELETE FROM datatable");                  for (int i=0; i<m_combobox.getcount(); i++) {                                       依次取得组合框中的字符串                 cstring temp;                 m_combobox.getlbtext(i, temp); 依次插入                 strsql.format("insert into datatable (id, context) values (%d, '%s');", i,                 m_dbfile.executesql(strsql);             }         } catch (cdbexception &e)     } }      void cdatabasetest1dlg::loaddatafromdb(void)     if (m_dbfile.isopen()) 数据库操作                       记录集,可以方便地操作记录 crecordset的应用十分广泛,用法参见微软msdn         crecordset recset(&m_dbfile); 需要一个select查询语句以打开记录集         cstring sqlstr="  "SELECT" context from order by id asc"; 打开记录集: 参数1是打开类型,有forwardonly、snapshot、dynaset、dynamic,默认为snapshot 参数2是sql语句 参数3是打开选项,这里是readonly,表示只读         recset.open(crecordset::forwardonly, sqlstr, crecordset::readonly); 先清空组合框         m_combobox.resetcontent();         while (!recset.iseof()) 通过 getfieldvalue("字段名", &str); 获取当前记录中各字段的数据             cstring             recset.getfieldvalue("context", 向组合框添加所取得的值             m_combobox.addstring(temp); 移向下一条记录             recset.movenext(); }< code></m_combobox.getcount();>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
wzbhbb
9年4个月前 IP:北京
811012
怎么无法下载?
另外,数据表建立是如何操作的
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
9年4个月前 修改于 9年4个月前 IP:四川
811053
引用 wzbhbb:
怎么无法下载?
另外,数据表建立是如何操作的
个人不再建议玩C++/Comctl32、C++/MFC、C++/ATL这些落后的GUI开发方法。。。

它们实在是效率太低、难度太高、自由度太低、界面太丑了。。。

建议去学习C#/WPF这种更高效、低难度、自由度更高、更华丽的GUI编程方法,或者跨平台的C++/Qt也行。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,6年4个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的