[返回]
中国计算机报2000年第92期DDX访问数据库Date字段的方法
唐一均
在用MFC的ODBC编程方法编写数据库应用程序时,常会需要处理数据库中的日期字段,通常在以CRecordView为基类的FormView类中,虽然CTime类的内存变量已经和数据库指定记录绑定了,但在使用DDX的时候就有了问题。
普通的Edit Box不能和CTime类的内存变量建立关联,通常只能用一个叫Date Time Picker contorl的控件建立关联,如果用ClassWiard为新的Date Time Picker加上CTime类的内存变量的话,编译时会提示:"'DDX_FieldDateTimeCtrl' : undeclared identifier",你只有修改DDX_FieldDateTimeCtrl为:DDX_DateTimeCtrl(pDX, IDC_DATETIMEPICKER1, m_pSet-〉My_Date_Variable);方可。
但是,VC5.0控件列表中并没提供Date Time Picker控件,而且在使用时感到很有约束,我们是否有其他选择呢?
下面笔者提供一个可把Date字段绑定于一个普通的Edit Box的DDX实现方法,步骤如下:
1.在你项目中添加date.h和date.cpp(下文将提供)。
2.假设你的FormView的cpp文件叫AbcFormView.cpp,在头上加入#include "date.h"。
3.如下修改AbcFormView.cpp在//{{AFX_DATA_MAP(CAbcFormView)语句下增加DDX_FieldDate(pDX,IDC_EDIT1,m_pSet-〉m_REGISTERDATE,m_pSet);
假设你数据库Date字段名叫REGISTERDATE ,IDC_EDIT1是Form上要显示Date的Edit box的ID,DDX_FieldDate由date.cpp提供解释。
4.保证你的CMyRecordSet类的.h文件中m_REGISTERDATE是CTime类的。
5.在你theApp所在的cpp中找到...App::InitInstance()并添加setlocale( LC_ALL, "C" );并在cpp头上加#include"locale.h",这用来设定你的Edit box中所显示的日期类型格式的。
date.h源程序如下:
// date.h: 声明DDX_FieldDate的各种接口
void AFXAPI DDX_FieldDate(CDataExchange pDX, int nIDC, CTime&& ts, CRecordset pSet);
BOOL GetDate(CWnd pWnd, CTime&& ts);
BOOL GetDate(HWND hWnd, CTime&& ts);
void SetDate(CWnd pWnd, CTime ts);
void SetDate(HWND hWnd, CTime ts);
//date.h文件结束
date.cpp源程序如下:
// date.cpp : DDX_FieldDate的执行代码
#include "stdafx.h"
#include "date.h"
void AFXAPI DDX_FieldDate(CDataExchange pDX, int nIDC, CTime&& ts, CRecordset pSet )
{ //下面Edit控件的HWND是为DDX 或DDV作准备的
HWND hWndCtrl = pDX-〉PrepareEditCtrl(nIDC);
if (pDX-〉m_bSaveAndValidate)
{
if (!GetDate(hWndCtrl, ts))
{
// 不能得到日期;
AfxMessageBox("无效的日期");
pDX-〉Fail(); }
}
else
{ SetDate(hWndCtrl, ts);}
}
BOOL GetDate(CWnd pWnd, CTime&& ts)
{
ASSERT(pWnd != NULL);
return GetDate(pWnd-〉m_hWnd, ts);
}
BOOL GetDate(HWND hWnd, CTime&& ts)
//这个GetDate从Edit box中取得日期值
{const int DATE_SIZE = 64;
char sBuffer[DATE_SIZE+1];
CString strBuffer;
COleDateTime date;
::GetWindowText(hWnd, sBuffer, DATE_SIZE);
//从Edit box取值
strBuffer = sBuffer;
if (strBuffer.IsEmpty()) {
ts.GetCurrentTime();
return TRUE;
}
// 注意ParseDateTime是帮助你测试日期完整性的
date.ParseDateTime(strBuffer, VAR_DATEVALUEONLY, LANG_USER_DEFAULT );
if( date.GetStatus() == COleDateTime::valid ) {
CTime tyj2( date.GetYear(),date.GetMonth(), date.GetDay(), 0, 0, 0 );
//再传回来
ts=tyj2;
return TRUE;
} else
return FALSE;
}
void SetDate(CWnd pWnd, CTime ts)
{ ASSERT(pWnd != NULL);
SetDate(pWnd-〉m_hWnd, ts);
}
void SetDate(HWND hWnd, CTime ts)
//SetDate用于显示日期值到Edit box
{ COleDateTime date( ts.GetYear(), ts.GetMonth(), ts.GetDay(), 0, 0, 0);
CString sBuffer;
sBuffer = date.Format("%x");
// 不要忘记setlocale( LC_ALL, "C" );
//如果日期值无效的话为空字符
if( date.GetStatus() == COleDateTime::invalid )
sBuffer = "";
::SetWindowText(hWnd, sBuffer.GetBufferSetLength(sBuffer.GetLength()));
}
以上程序中GetDate是用于从你的控件上获取数据到内存变量,SetDate是用你想要的方式显示数据到你的控件上,效果如图1。上述代码均在IBM DB2数据库、VC 6.0、ODBC32环境下编译通过。
掌握这个方法,你可以为你数据库中各种特殊的字段编写各自的DDX方法,让它们绑定到一些控件上去,你也获得了更大的自由,如可以完全控制数据的显示方式等。