4.5.3 职工添加的实现(2)
通过类向导为对话框添加WM_LBUTTONDOWN消息响应函数。该函数主要通过判断鼠标左键单击是否在Picture控件上,调用打开文件对话框。相关代码如下:
代码位置:见光盘中本章源代码的CEmpAddDlg类。
- 1 void CEmpAddDlg::OnLButtonDown(UINT nFlags, CPoint point)
- 2 {
- 3 CRect Rect; //定义一个区域
- 4 GetDlgItem(IDC_PHOTO)->GetWindowRect(&Rect); //获取区域
- 5 ScreenToClient(&Rect); //转换客户坐标
- 6 if(Rect.PtInRect(point)) //如果在这个区域内
- 7 {
- 8 CFileDialog FileDlg(TRUE, "BMP", NULL, //定义文件对话框
- 9 OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "位图文件(*.BMP)|*.BMP||");
- 10 if(FileDlg.DoModal() != IDOK) //打开文件对话框
- 11 return ;
- 12 CString pathname = FileDlg.GetPathName(); //获取选中文件的路径
- 13 CFile file; //定义一个文件变量
- 14 if(!file.Open(pathname, CFile::modeRead) ) //只读方式打开文件
- 15 return ;
- 16 m_nFileLen = file.GetLength(); //获取文件的长度
- 17 m_pBMPBuffer = new char[m_nFileLen + 1]; //开辟符数组
- 18 if(!m_pBMPBuffer) //如果空间不够大
- 19 return ;
- 20 if(file.ReadHuge(m_pBMPBuffer,m_nFileLen) != m_nFileLen) //读取文件
- 21 return ;
- 22 LPSTR hDIB,lpBuffer = m_pBMPBuffer;
- 23 LPVOID lpDIBBits;
- 24 BITMAPFILEHEADER bmfHeader; //保存bmp文件头
- 25 DWORD bmfHeaderLen; //保存文件头的长度
- 26 bmfHeaderLen = sizeof(bmfHeader); //读取文件头的长度
- 27 strncpy((LPSTR)&bmfHeader,(LPSTR)lpBuffer,bmfHeaderLen); //文件的赋值
- 28 if (bmfHeader.bfType != (*(WORD*)"BM")) //如果文件类型不对
- 29 return ;
- 30 hDIB = lpBuffer + bmfHeaderLen; //指针移动文件头后
- 31 BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
- 32 BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
- 33 lpDIBBits=(lpBuffer)+((BITMAPFILEHEADER *)lpBuffer)->bfOffBits;
- 34 CClientDC dc(this);
- 35 m_hPhotoBitmap = CreateDIBitmap(dc.m_hDC,&bmiHeader, //创建位图
- 36 CBM_INIT,lpDIBBits,&bmInfo,DIB_RGB_COLORS);
- 37 Invalidate(); //刷新
- 38 }
- 39 CDialog::OnLButtonDown(nFlags, point);
- 40 }
第4~5行代码实现了控件区域的获取。
第8~12行代码通过CFileDialog类实现了照片文件路径的获取。
第14~21行代码实现了将照片文件转换为二进制数据。
第22~36行代码实现了照片文件的处理。
上述代码主要完成图片文件的读取。GetWindowRect()函数获取控件区域的大小,通过ScreenToClient()函数转换成客户区域,函数PtInRect()实现判断当前鼠标的位置是否在控件的区域中。借助CFile类ReadHuge()实现读取照片数据,将照片文件转换成二进制代码。
双击【添加】按钮添加消息响应函数,该函数把职工信息添加到数据库中。OnBtnAdd()代码参考如下:
代码位置:见光盘中本章源代码的CEmpAddDlg类。
- 1 void CEmpAddDlg::OnBtnAdd()
- 2 {
- 3 UpdateData(); //更新数据
- 4 if(m_strName == "") //条件判断
- 5 {
- 6 MessageBox("姓名不能为空!");
- 7 return ;
- 8 }
- 9 if(m_nAge == 0)
- 10 {
- 11 MessageBox("请设置年龄!");
- 12 return ;
- 13 }
- 14 CString strSex, strDepart, strBirth, strAge; //定义字符串变量
- 15 strBirth.Format("%d-%d-%d",m_Birth.GetYear(),m_Birth.GetMonth(),m_Birth.GetDay());
//获取时间 - 16 int nIndex = m_SexCtrl.GetCurSel(); //获取列表框选中索引
- 17 m_SexCtrl.GetLBText(nIndex, strSex); //获取列表框的文本
- 18 nIndex = m_DepartCtrl.GetCurSel();
- 19 m_DepartCtrl.GetLBText(nIndex, strDepart);
- 20 strAge.Format("%d", m_nAge); //年龄数据类型转换
- 21 m_pRecordset->AddNew; //添加记录
- 22 m_pRecordset->PutCollect("name",_variant_t(m_strName)); //添加姓名
- 23 m_pRecordset->PutCollect("age",_variant_t((long)m_nAge)); //添加年龄
- 24 m_pRecordset->PutCollect("sex",_variant_t(strSex)); //添加性别
- 25 m_pRecordset->PutCollect("addr",_variant_t(m_strAddr)); //添加住址
- 26 m_pRecordset->PutCollect("depart",_variant_t(strDepart)); //添加院系
- 27 m_pRecordset->PutCollect("birth",_variant_t(strBirth)); //添加生日
- 28 m_pRecordset->PutCollect("phone",_variant_t(m_strPhone)); //添加电话
- 29 m_pRecordset->PutCollect("more",_variant_t(m_strMore)); //添加备注
- 30 char *pBuf = m_pBMPBuffer;
- 31 VARIANT varBLOB;
- 32 SAFEARRAY *psa;
- 33 SAFEARRAYBOUND rgsabound[1];
- 34 if(pBuf)
- 35 {
- 36 rgsabound[0].lLbound = 0;
- 37 rgsabound[0].cElements = m_nFileLen;
- 38 psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
- 39 for (long i = 0; i < (long)m_nFileLen; i++)
- 40 SafeArrayPutElement (psa, &i, pBuf++);
- 41 varBLOB.vt = VT_ARRAY | VT_UI1;
- 42 varBLOB.parray = psa;
- 43 m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);
//保存图片数据 - 44 }
- 45 m_pRecordset->Update(); //更新记录集
- 46 MessageBox("保存成功!");
- 47 }
第4~13行代码判断数据是否存在。
第21~29行代码实现了职工信息的添加。
第30~46行代码实现了职工照片的添加,保存数据到数据库中。
上述代码借助Format()函数将年月日的信息格式化到字符串中,通过AddNew()添加一条新的记录,函数PutCollect()将数据添加到对应的字段中。下面将详细介绍如何把图片保存到数据库中。
本系统实现把jpg图片以二进制数据形式存储在SQL Server 2005数据库 image字段中,并实现了可以读取数据库中字段数据显示在picture控件上。实现过程如下。
(1)image字段的设定。在SQL Server 2005中建立一个可以存储二进制数据的字段photo,对应数据类型应该选image。
(2)BLOB数据的保存。BLOB类型的数据无法用普通的方式进行存储,需要使用AppendChunk()函数。AppendChunk()包含在Field对象中,原型为HRESULT AppendChunk (const _variant_t & Data )。从函数原型中可以看到,关键的问题是需把二进制数据赋值给VARIANT类型的变量。关键代码如下:
- m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);
//BLOB数据的保存
(3)BLOB数据的读取。对应于保存数据时所使用的AppendChunk()函数,读取数据应该使用GetChunk()函数,GetChunk()的原型为_variant_t GetChunk(long Length )。给出数据的长度后GetChunk()将返回包含数据的VARIANT类型变量,然后可以利用SafeArrayAccessData()函数得到VARIANT变量中指向数据的char*类型的指针,以方便处理。关键代码如下:
- long lDataSize = m_pRecordset->GetFields()->GetItem("photo")->ActualSize;
//数据大小获取 - varBLOB = m_pRecordset->GetFields()->GetItem("photo")->GetChunk(lDataSize);
//BLOB数据的读取
【责任编辑:
云霞 TEL:(010)68476606】