An auto-collection information control group






3.60/5 (4 votes)
Dec 27, 2002
6 min read

126493

682
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.
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 inDoDataExchange
function of dialogvoid 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 usingCXMLResult
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
andTreeView
andListView
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.comCXShadebutton
- ing.davide.pizzolato@libero.itCLabel
- I forgot, sorry.CcoobBtn
- I forgot, sorry.
That's all.