开发平台:win7 64bit
开发工具:VS2012,Oracle11g
前言
前几天学习了数据库的一些基础知识,并且使用ADO连接了数据库。为了熟悉数据库在项目中的使用,所以就选择了一个类似课程设计的题目练练手。题目中做的事情包括:
* 对ADO进行了初步的封装
* 使用了一些素材对界面进行美化
* 四个模块,包括售卖,添加入库,在库查询和人员管理
其中最重要的还是在于对ADO的封装和使用。
一、ADO的封装
ADO类的封装主要封装了对数据库的连接,SQL语句的执行这两个部分。封装的过程中出现过些一问题,后面一一列出。特别是对于抛出异常的一些问题要尤为注意。
ADO.H文件
//导入msado15.dll动态链接库
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF", "adoEOF")
//_MSC_VER 编译器版本
#if _MSC_VER > 1000
#pragma once
#endif
class Cado
{
public:
Cado();
virtual ~Cado();
public:
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecord;
//Ado连接操作
BOOL AdoConnect(CString sHost= "192.168.0.33",CString sPort = "1521",\
CString sUid="pa",CString sPwd="pa",CString sSid="pa");
//执行SQL语句
BOOL ExecuteSQL(_bstr_t bstrSQL);
//执行SQL语句,并且返回_RecordsetPtr
_RecordsetPtr& GetRecordset(_bstr_t bstrSQL);
//退出连接
void ExitConnect();
};
#endif
ADO.Cpp文件
#include "stdafx.h"
#include "ado.h"
Cado::Cado()
{
//初始化Com库
//不在这里面初始化库,因为AfxOleInit只能执行一次,所以放在App类初试中
//AfxEnableControlContainer();
//AfxOleInit();
}
Cado::~Cado()
{
}
//默认参数为连接Oracle数据库的连接字串
BOOL Cado::AdoConnect(CString sHost,CString sPort,CString sUid,CString sPwd,CString sSid)
{
CString strConnect;
strConnect.Format("Provider=OraOLEDB.Oracle.1;Password=%s;Persist Security Info=True;User ID=%s;\
Data Source=\"(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = %s)\
(PORT = %s)) )(CONNECT_DATA = (SID = %s)))\"",sPwd, sUid, sHost, sPort, sSid);
try
{
::CoInitialize(NULL); //初始化com环境(必须,否则提示异常)
m_pConnection.CreateInstance(__uuidof(Connection));
m_pConnection->ConnectionTimeout = 5; // 设置连接超时为5s
m_pConnection->Open(_bstr_t(LPCTSTR(strConnect)),"","",adModeUnknown);
m_pConnection->CursorLocation = adUseClient; //设置使用客户端连接
}
catch (_com_error e)
{
AfxMessageBox(e.Description());
return FALSE;
}
catch (...)
{
AfxMessageBox("数据库连接失败!");
return FALSE;
}
return TRUE;
}
void Cado::ExitConnect()
{
if (m_pRecord != NULL)
m_pRecord -> Close();
m_pConnection->Close();
}
BOOL Cado::ExecuteSQL(_bstr_t bstrSQL)
{
try
{
if (m_pConnection == NULL)
AdoConnect();
m_pConnection->Execute(bstrSQL,NULL,adCmdText);
return TRUE;
}
catch (_com_error e)
{
AfxMessageBox("执行SQL异常\n\t原因:" + e.Description());
return FALSE;
}
}
_RecordsetPtr& Cado::GetRecordset(_bstr_t bstrSQL)
{
try
{
if (m_pConnection == NULL)
AdoConnect();
m_pRecord.CreateInstance(__uuidof(Recordset));
m_pRecord->Open(bstrSQL,m_pConnection.GetInterfacePtr(),
adOpenDynamic,adLockOptimistic,adCmdText);
}
catch (_com_error e)
{
AfxMessageBox("异常原因:"+e.Description());
}
return m_pRecord;
}
二、登录界面设计
登录界面素材可以从各种网站或者应用的登录界面上截取。下面图片就是我在网上随面挑选下来,然后用Photoshop工具对图片进行了一些细微的修改,其中加入了“Robin旗舰店”做为商铺logo。并且在登录账号和登录密码后面截取一块矩形区域作为登录时填入信息的部分。
将上述处理好的图片(bmp格式)加载到资源管理器中。插入一个Dialog资源并且将其Border风格修改为:None。这样的对话框就是没有边框的风格,那么显示出来的就是只有图片,不会多一圈丑陋的边框。
在登录的Dialog对话框中添加一个picture控件,设置为BITMAP风格,加载图片进控件。调整对话框大小和图片大小相同。这样结果就是:
上图中用红色矩形框标示的是对话框的大小边框。接下来添加两个Edit控件,使控件的大小正好和登录账号和登录密码后面的框重合。
然后再添加两个Button控件,让他们和登录和重填重合。将他们的风格设置成“不可见”(Visible FALSE)。因为这里并不是要真的去用着两个Button,使用它们的目的仅仅是获取这两个区域的坐标点。接着就是编码的过程了。
在登录对话框对应的类中添加WM_LBUTTONDOWN(鼠标左键按下)消息的响应函数,并且重写虚函数OnOK()。在WM_LBUTTONDOWN消息响应下实现如下过程:
CRect rc1,rc2;
m_cancle.GetWindowRect(&rc1);
ScreenToClient(&rc1); //将屏幕坐标系转化为客户区坐标系
m_ok.GetWindowRect(&rc2);
ScreenToClient(&rc2);
if (rc2.PtInRect(point)) //在登录区域内
OnOK();
if ( rc1.PtInRect(point) ) //在取消区域内
OnCancel();
在OnOK函数中添加:
UpdateData(TRUE);//将界面输入值刷新到关联变量
Cado ado; //定义一个ADO对象
ado.AdoConnect("192.168.0.33");//连接数据库
CString sql;
sql.Format("select * from robin_users where NAME='%s' and PWD='%s'",
m_sUser,m_sPass);
//执行SQL语句
ado.m_pRecord = ado.GetRecordset((_bstr_t)sql);
//查询结果非空则登录成功
if(!ado.m_pRecord->adoEOF)
{
CDialog::OnOK();
strUser = ado.m_pRecord->GetCollect("PRIORTY");
ado.ExitConnect();
return;
}
MessageBox("密码不正确","提示",MB_OK); //查询为空提示
m_sUser = ""; //清空填入信息
m_sPass = "";
UpdateData(FALSE); //将变量值刷新到界面
ado.ExitConnect(); //退出数据库连接
小结:
这里的界面美化,使用的方法是将图片作为背景,利用图片中的一些区域作为响应某些操作的” Button”,这种做法相对比较简单,程序结构也不会有太大的调整,Button的响应消息任然可以是一个个独立的部分。
三、 管理界面
管理界面和上面登录界面如出一辙,分为设计素材,添加,显示几个部分。界面实现的结果如下:
左上角的几个图标是在Photoshop中添加上去的,作为几个“Button”,这里还有一个细节就是在鼠标滑过这些图标的时候变成“小手”的形状。这个事在WM_MOUSEMOVE消息中做的,判断鼠标点的操作和登录界面是一样的。
CRect reSale, reCheck, reAdd, reKey;
m_tSale.GetWindowRect(&reSale);
m_tCheck.GetWindowRect(&reCheck);
m_tAdd.GetWindowRect(&reAdd);
m_tKey.GetWindowRect(&reKey);
//转换坐标系
ScreenToClient(reSale);
ScreenToClient(reCheck);
ScreenToClient(reAdd);
ScreenToClient(reKey);
if (reSale.PtInRect(point) || reCheck.PtInRect(point) ||
reAdd.PtInRect(point) || reKey.PtInRect(point) )
{
SetCursor(LoadCursor(NULL,IDC_HAND));
return;
}
CDialogEx::OnMouseMove(nFlags, point);
四、 用户管理模块
首先要做的是建立数据库。这里,用户管理信息作为一个单独的“表”存在。创建如下表:
表名:robin_users
NAME | PWD | PRIORITY |
admin | 123456 | 管理员 |
权限判断部分:
if (reKey.PtInRect(point))
{
if ("管理员" != strUser)
{
MessageBox("您的用户权限过低!","提示",MB_OK);
return;
}
OnKey();//点击管理员图标
return;
}
账户管理在另外一个对话框下完成:
在该对话框的InitDialog中就查询数据库中的robin_users表,将用户列到ListCtrl中。实现过程:
CDialog::OnInitDialog();
m_list.InsertColumn(1, "用户名", LVCFMT_CENTER, 100);
m_list.InsertColumn(2, "密码", LVCFMT_CENTER, 100);
m_list.InsertColumn(3, "权限", LVCFMT_CENTER, 100);
m_combPrio.InsertString(0,"管理员");
m_combPrio.InsertString(1,"前台");
m_list.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
AddList();
return TRUE;
其中AddList()实现过程:
Cado ado;
ado.AdoConnect("192.168.0.33");
ado.m_pRecord = ado.GetRecordset("SELECT * FROM robin_users");
int i = 0;
while(!ado.m_pRecord->adoEOF)
{
m_list.InsertItem(i,(char*)(_bstr_t)ado.m_pRecord->GetCollect("NAME"));
m_list.SetItemText(i,1,(char*)(_bstr_t)ado.m_pRecord->GetCollect("PWD"));
m_list.SetItemText(i,2,(char*)(_bstr_t)ado.m_pRecord->GetCollect("PRIORTY"));
ado.m_pRecord->MoveNext();
i++;
}
ado.ExitConnect();
后面就是添加和删除的实现,其原理和实现方式都差不多。过程都是先连接数据库,然后从信息框中获取信息(添加)或者从列表中获取鼠标选中的位置(删除),然后指向相应的SQL语句对数据进行操作,操作完后退出连接数据库。然后将列表的数据刷新(删除所有条目,然后使用AddList()加载全部用户即可)。
实现代码如下:
删除用户部分:
void CKeyDlg::OnBnClickedDeletuser()
{
POSITION pos = m_list.GetFirstSelectedItemPosition();
if (NULL == pos)return;
int nIndex = m_list.GetNextSelectedItem(pos);
CString str = m_list.GetItemText(nIndex,0);
if("admin" == str)
{
MessageBox("不允许删除原始管理员账户","警告",MB_OK);
return;
}
Cado ado;
ado.AdoConnect("192.168.0.33");
CString sql;
sql.Format("DELETE FROM robin_users WHERE NAME = '%s'",str);
ado.ExecuteSQL((_bstr_t)sql);
ado.ExitConnect();
m_list.DeleteAllItems();
AddToList();
}
添加用户部分:
void CKeyDlg::OnBnClickedAdduser()
{
UpdateData(TRUE);
if (m_strUser == "" || m_strPwd == "" || m_strPrio =="")
{
MessageBox("账户,密码,权限均不能为空,请检查后重新输入!","提示",MB_OK);
return;
}
Cado ado;
ado.AdoConnect("192.168.0.33");
CString sql;
sql.Format("INSERT INTO robin_users(NAME,PWD,PRIORTY) VALUES('%s','%s','%s')",
m_strUser,m_strPwd,m_strPrio);
ado.ExecuteSQL((_bstr_t)sql);
ado.ExitConnect();
m_list.DeleteAllItems();
AddToList();
}