Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

An auto-collection information control group

0.00/5 (No votes)
26 Dec 2002 1  
A set of classes for batch inputting, validating, and packing user's data.

Introduction

I wrote a program with thousands of parameters on an interface. I found it is ugly to write such kinds of dialogs and check data to complete the task. It is trivial to collect all parameters and commit to database. It is a time consuming task. After months of headache, I found that this task has universal properties. I wrote this control group to collect and check data automatically.

Where to use

Every program needs people to input a lot of data through the user interface. Especially for a MIS system people must fill a big form, it is an ugly thing to write all data control initialization, get data and check data by code.

Requirements

Analyzing the whole process, I found that a data input action has four parts: data control initialization, activity on control changed, data check and pack data into a data package according to design specification.

Initialization

While you are initializing you data controls in a form, following things may be done.

  • A - Make a map of variables and their control.
  • B - Set the default value of variables to control.
  • C - Fill the selection control with options according to dictionary.
  • D - Fill the control with data retrieved from the database or other sources.

      Condition A will complete by DoDataExchange while you are using MFC. Condition B must be got from the user from there jobs to complete. Condition C and D are general requirements for all programs which need to code according to there control type.

      Activities of control

      When the control status has been changed by user, there will be some change on user interface according to the users� data or selection. This is called activity of control changed. In Microsoft� Windows�, these actions will use notification of control. We shall complete it via overriding OnMsg in a MFC application.

      Check data (validation)

      After user completes their data input, the application must check the validation of data according to the business they are doing. In general, the business data is one or a composite of the following data types: int, long, double, float, date/time, string etc.

      The four numeric data types (int, long, double, float) will have their domain in specified business modal. These domains are given by the programmer according to their business. The string is more complicated, it includes empty string and the length of string. Sometimes, may be a format of string must be obeyed. I wrote an article A set of universal data check functions to solve this question (somebody may think it nothing or a trivial). In that article, I analyzed all possible conditions we may encounter while we input data.

      There is a special check while you are using combo box in windows. Usually, a combo box will be filled by a dictionary defined by the user. Sometimes, the dictionary is just a hint of dataset, sometimes we must select from dataset in the option list. There are at least two methods to implement this function, make edit read only or check if user input data is in the dictionary. In this version, we select the second method.

      Data exchange

      While we are using MFC, set data to control and get data from control is using DoDataExchange. We do the same things for our control group. There are several points needed for us to process. There are no direct methods to get the item code from a dictionary. To solve the problem, I have written an article A ComboBox using XML as dictionary. A group of radio button is created. In the MFC standard way, the value of each radio button is started from 0 and incremented one in sequence according to their creation on form. Actually, there may be other values associated with each radio button. Unlike the item of combo box, you can not append a lParam to a radio button, you must process the condition by yourself.

      Package of data

      If the data is OK, we can commit to database. You need to pack all the data input by user into a SQL form to complete the command. In this control, the output will be an XML file. It is very easy for you to translate the XML into other forms using interfaces in MSXML and XSL stylesheet.

      Implementation

      A universal control

      According to the analysis of pros, I found that we can abstract a universal control. In this universal control, we can generate all kinds of actually used controls according to the member values in the universal control. The information of universal control is composed of the description of the control its self, associated variable name, check information, prompts etc. It provides all information for control group to complete the task from initialization, data exchange, checking and packaging.

      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);
      };

      Initialization

      We can initialize the information of control by hand (hard coded) or by program. We support both ways.

          // 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.

      These functions get information to each control, but the control does not exist as per MFC request. We do initialize via the following function, after it is being called, the status of control is ready.

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

      Exchange data between control and variables

      One important thing is to exchange data between controls and variables. We exchange data using the standard method of MFC, DoDataExchange function. As a result, all values in the controls are exchanged to controls or vise versa.

      void DoDataExchange(CDataExchange *pDX);

      Validation

      To validate the data, you can call:

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

      If an error occurred in the system, the CheckData will return FALSE. At the same time, it will prompt the user that an error is found according to the condition set at initialization.

      XML representations

      All data files in these control group are using XML. On how to operate XML, see my document Wrapper class for DOM interface of Windows SDK. I have extended the class CXMLFile to CXMLResult and CXMLCmd. Data control initialization is using CXMLResult. It has the following format:

      <answer>
          <recordset>
              <record>
              </record>
              ����
              <record>
              </record>
          <recordset>
      </answer>

      In "����" part , you can write any tags with values.

      The format for CXMLCmd is as following:

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

      How to use

      To use the control group is very easy. You can follow the following steps:

      • Step 1. Declare a control group in the declaration of the form
        class CChldInfantLang : public CBitmapInnerDlg
        {
        CControlGroup m_cntGroup;
      • Step 2. Declare a dictionary used by this system or just in dialog.
                CXMLDict* m_pDict;
      • Step 3: Add a function as an entry to initialize the control group.
            void PreInit();
      • Step 4: Add initialize control group and Dictionary in constructor of the form.
        CChldInfantLang::CChldInfantLang(CWnd* pParent /*=NULL*/)
            : CBitmapInnerDlg(CChldInfantLang::IDD, pParent)
        {
            m_pDict = NULL;
            PreInit();
        }
      • Step 5: Add DoDataExchage function in DoDataExchange function of dialog
        void CChldInfantLang::DoDataExchange(CDataExchange* pDX)
        {
            CBitmapInnerDlg::DoDataExchange(pDX);
            m_cntGroup.DoDataExchange (pDX);
        �������������.
        }
      • Step 6: Call InitControl of control group to complete initialization of control groups.
        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
        
        }
      • Step 7: Set initialization data to control in PreInit function using a configuration file using CXMLResult format.
        void CChldInfantLang::PreInit()
        {
            CString strPath = theApp.m_Path +_T("\\chldInfantLang.xml");
            m_cntGroup.InitFromFile (strPath);
        
        }
      • Step 8: Call update to controls and get XML data in a string format for further usage.
                CString xml;
            CXMLCmd m_Cmd;
            UpdateData();
            if(!CheckData ())
                return;
            m_Cmd.InitCmd ();
                m_cntGroup .AddToXML (cmd);
                 m_Cmd.GetXML (xml);

      More to be complete

      • To support more controls, include ListBox and TreeView and ListView controls.
      • To deal with the action, such as group disable or group enable etc.
      • To deal with the action if some content change in the control occurred, the control group will automatically do what a program wants and sets the control to do.
      • To support CdhtmlDialog in Visual C++ .NET. It is a lot different in the common dialog of MFC.

      Acknowledgement

      I adopted many existing code in the Web. I am listing all what I collected, if somebody is not mentioned, please notify me. Thank you all gurus.

      • HMXCheckBox, HMXEdit, HMXNumEdit - Massimo Colurcio - m.colurcio@softhor.com
      • CXShadebutton - ing.davide.pizzolato@libero.it
      • CLabel - I forgot, sorry.
      • CcoobBtn - I forgot, sorry.

      That's all.

    • License

      This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

      A list of licenses authors might use can be found here