返回
 中国计算机报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方法,让它们绑定到一些控件上去,你也获得了更大的自由,如可以完全控制数据的显示方式等。