65.9K
CodeProject 正在变化。 阅读更多。
Home

自动收集信息控件组

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.60/5 (4投票s)

2002年12月27日

6分钟阅读

viewsIcon

127130

downloadIcon

682

一套用于批量输入、验证和打包用户数据的类。

引言

我写了一个界面上有数千个参数的程序。我发现编写这种对话框并检查数据来完成任务很麻烦。收集所有参数并提交到数据库是很简单的,但这是一个耗时的工作。经过几个月的头疼,我发现这个任务具有普遍性。我编写了这个控件组来自动收集和检查数据。

使用场景

每个程序都需要用户通过用户界面输入大量数据。特别是对于MIS系统,人们必须填写一个大表单,通过代码编写所有数据控件的初始化、获取数据和检查数据是非常麻烦的。

要求

分析整个过程,我发现数据输入操作有四个部分:数据控件初始化、控件状态改变时的活动、数据检查和根据设计规范将数据打包成数据包。

初始化

当您初始化表单中的数据控件时,可能会完成以下事项:

  • A - 建立变量及其控件的映射。
  • B - 将变量的默认值设置给控件。
  • C - 根据字典填充选择控件的选项。
  • D - 用从数据库或其他来源检索到的数据填充控件。

      在使用MFC时,条件A将通过DoDataExchange完成。条件B必须由用户从其工作中获得才能完成。条件C和D是所有需要根据其控件类型进行编码的程序的通用要求。

      控件的活动

      当控件状态被用户更改时,用户界面会根据用户的数据或选择发生一些变化。这被称为控件状态改变的活动。在Microsoft® Windows®中,这些操作将使用控件的通知。我们将在MFC应用程序中通过重写OnMsg来完成它。

      检查数据(验证)

      用户完成数据输入后,应用程序必须根据其业务检查数据的有效性。一般来说,业务数据是以下数据类型中的一种或组合:int, long, double, float, date/time, string 等。

      四种数值数据类型(intlongdoublefloat)将在指定的业务模型中拥有其域。这些域由程序员根据其业务给出。字符串更复杂,它包括空字符串和字符串的长度。有时,可能必须遵守字符串的格式。我写了一篇文章一套通用数据检查函数来解决这个问题(有些人可能认为它微不足道)。在那篇文章中,我分析了我们在输入数据时可能遇到的所有可能条件。

      在Windows中使用组合框时有一个特殊的检查。通常,组合框将由用户定义的字典填充。有时,字典只是数据集的提示,有时我们必须从选项列表中的数据集中选择。至少有两种方法可以实现此功能,使编辑框只读或检查用户输入的数据是否在字典中。在此版本中,我们选择第二种方法。

      数据交换

      当我们使用MFC时,将数据设置到控件和从控件获取数据都是使用DoDataExchange。我们为我们的控件组做同样的事情。有几点我们需要处理。没有直接的方法可以从字典中获取项目代码。为了解决这个问题,我写了一篇文章一个使用XML作为字典的组合框。创建了一组单选按钮。在MFC标准方式中,每个单选按钮的值从0开始,并根据它们在表单上的创建顺序递增。实际上,每个单选按钮可能关联有其他值。与组合框的项目不同,您不能将lParam附加到单选按钮,您必须自己处理这种情况。

      数据包

      如果数据正常,我们可以提交到数据库。您需要将用户输入的所有数据打包成SQL格式来完成命令。在此控件中,输出将是一个XML文件。使用MSXML和XSL样式表中的接口,您可以非常容易地将XML转换为其他形式。

      实现

      通用控件

      根据对优点的分析,我发现我们可以抽象出一个通用控件。在这个通用控件中,我们可以根据通用控件中的成员值生成各种实际使用的控件。通用控件的信息由控件本身的描述、关联变量名、检查信息、提示等组成。它为控件组提供了从初始化、数据交换、检查和打包完成任务所需的所有信息。

      class CNT_Control
      {
      public:
          // data type
          int        m_iDataType;
          // control type
          int        m_iCntType;
          // id of control
          UINT    m_uiID;
          // xml name of variable
          CString    m_strName;
          // the max value
          CString m_strMax;
          // the min_value
          CString m_strMin;
          // prompt name of variable
          CString m_strPrompt;
          // the data check information flag
          int        m_iCheckFlag;
          // The default value
          CString m_strDefault;
          // The value
          CString m_strValue;
          // The color
          COLORREF m_Cr;
          // The Transparent
          BOOL    m_bTransparent;
          // The dictioary
          CString m_strDict;
          // The label can be used
          UINT    m_uiLabel;
          
          CNT_Control(int dt,int ct,UINT nid,UINT nLab, const CString &name ,
              const CString &max, const CString &min,int chk,
              const CString &def=_T(""),COLORREF cr=RGB(0,0,0),BOOL t=TRUE);
          CNT_Control();
          CNT_Control( const CNT_Control &ctl);
          CNT_Control& operator= ( const CNT_Control& ctl);
      public:
          void WriteParamDict(CXMLResult & res);
          void ReadFromResult ( int i  ,CXMLResult &rst);
          void WriteToResult (CXMLResult &rst);
      };

      初始化

      我们可以手动(硬编码)或通过程序初始化控件信息。我们支持这两种方式。

          // Initialize control group using specific file 
          // If ini = TRUE means to construct control using give data in the file.
          // Otherwise , just initialize data in control group,
          // but no construct the actual control
          void InitFromFile( const CString & path,BOOL ini =TRUE);
      
          // Add a data control. to control group 
          // All parameter's meaning is same as the
          // functions with this kind result before.
          void AddDate(UINT nID, UINT lab, const CString &name, 
             const CString &def, int chkmask, 
             const CString &min1, const CString &max1);
          // Add a comboxBox to control group
          // parameters meaning is same as above.
          void AddComboBox(UINT nID, UINT lab, int dt, 
             int ct, const CString &name, 
             const CString &def, const CString &dict);
          // Add a label to control group.
          // cr : the color of lable.
          // tran: set to TRUE is transparent background
          void AddLabel(UINT nID, COLORREF cr=RGB(0,0,0), BOOL trans= TRUE);
          // Add a edit control to control group.
          // all meanings of parameter is same as above.
          // dt : data type , see definitions
          // ct: control type, see definitioins.
          void AddEdit ( UINT nID,UINT lab, int dt, 
             int ct, const CString &name,const CString & def, 
             int chkmask, const CString& min1, const CString &max1);
          // Add a button to control group.
          void AddButtons(UINT nID);
          // Clear the all inputted data to default condition.

      这些函数获取每个控件的信息,但根据MFC请求,控件并不存在。我们通过以下函数进行初始化,调用后,控件的状态就准备好了。

      void InitCotrols(CWnd *pParent,CXMLDict *dict);

      控件与变量之间的数据交换

      一项重要的事情是在控件和变量之间交换数据。我们使用MFC的标准方法——DoDataExchange函数来交换数据。因此,控件中的所有值都会与变量进行交换,反之亦然。

      void DoDataExchange(CDataExchange *pDX);

      验证

      要验证数据,您可以调用

      // Check all data in the window,
      // if somebody does not satisfied , prompt user.
      BOOL CheckData(CWnd *wnd );

      如果系统中发生错误,CheckData将返回FALSE。同时,它将根据初始化时设置的条件提示用户发现了一个错误。

      XML 表示

      这些控件组中的所有数据文件都使用XML。关于如何操作XML,请参阅我的Windows SDK DOM 接口的包装类文档。我已经将CXMLFile类扩展到CXMLResultCXMLCmd。数据控件初始化使用CXMLResult。它具有以下格式:

      <answer>
          <recordset>
              <record>
              </record>
              …………
              <record>
              </record>
          <recordset>
      </answer>

      在“…………”部分,您可以编写任何带有值的标签。

      CXMLCmd的格式如下:

      <__command>
          <__parameter/>
          <__group/>
      <__order/>
      </__command>

      如何使用

      使用控件组非常简单。您可以按照以下步骤操作:

      • 步骤1。在表单声明中声明一个控件组
        class CChldInfantLang : public CBitmapInnerDlg
        {
        CControlGroup m_cntGroup;
      • 步骤2。声明本系统或对话框中使用的字典。
                CXMLDict* m_pDict;
      • 步骤3:添加一个函数作为初始化控件组的入口。
            void PreInit();
      • 步骤4:在表单的构造函数中添加初始化控件组和字典。
        CChldInfantLang::CChldInfantLang(CWnd* pParent /*=NULL*/)
            : CBitmapInnerDlg(CChldInfantLang::IDD, pParent)
        {
            m_pDict = NULL;
            PreInit();
        }
      • 步骤5:在对话框的DoDataExchange函数中添加DoDataExchage函数
        void CChldInfantLang::DoDataExchange(CDataExchange* pDX)
        {
            CBitmapInnerDlg::DoDataExchange(pDX);
            m_cntGroup.DoDataExchange (pDX);
        ………………………………….
        }
      • 步骤6:调用控件组的InitControl完成控件组的初始化。
        BOOL CChldInfantLang::OnInitDialog() 
        {
            CBitmapInnerDlg::OnInitDialog();
            
            SetBitmap(IDB_BITMAP_PAPER);
            m_cntGroup.InitCotrols (this, m_pDict);
            
            return TRUE;  // return TRUE unless you set the focus to a control
                          // EXCEPTION: OCX Property Pages should return FALSE
        }
      • 步骤7:使用CXMLResult格式的配置文件在PreInit函数中将初始化数据设置到控件。
        void CChldInfantLang::PreInit()
        {
            CString strPath = theApp.m_Path +_T("\\chldInfantLang.xml");
            m_cntGroup.InitFromFile (strPath);
        
        }
      • 步骤8:调用更新控件并以字符串格式获取XML数据以供进一步使用。
                CString xml;
            CXMLCmd m_Cmd;
            UpdateData();
            if(!CheckData ())
                return;
            m_Cmd.InitCmd ();
                m_cntGroup .AddToXML (cmd);
                 m_Cmd.GetXML (xml);

      有待完善

      • 支持更多控件,包括ListBoxTreeViewListView控件。
      • 处理诸如组禁用或组启用等操作。
      • 处理如果控件中的某些内容发生变化,控件组将自动执行程序想要的操作并将控件设置为相应的状态。
      • 支持Visual C++ .NET中的CdhtmlDialog。它与MFC的通用对话框有很大不同。

      致谢

      我采用了网络上许多现有的代码。我将列出我收集的所有内容,如果有人未被提及,请通知我。谢谢各位专家。

      • HMXCheckBox, HMXEdit, HMXNumEdit - Massimo Colurcio - m.colurcio@softhor.com
      • CXShadebutton - ing.davide.pizzolato@libero.it
      • CLabel - 抱歉,我忘记了。
      • CcoobBtn - 抱歉,我忘记了。

      就是这样。

    • © . All rights reserved.