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.
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.
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.
While you are initializing you data controls in a form, following things may be done.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:
The four numeric data types (
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.
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.
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.
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( const CNT_Control &ctl);
CNT_Control& operator= ( const CNT_Control& ctl);
void WriteParamDict(CXMLResult & res);
void ReadFromResult ( int i ,CXMLResult &rst);
void WriteToResult (CXMLResult &rst);
We can initialize the information of control by hand (hard coded) or by program. We support both ways.
void InitFromFile( const CString & path,BOOL ini =TRUE);
void AddDate(UINT nID, UINT lab, const CString &name,
const CString &def, int chkmask,
const CString &min1, const CString &max1);
void AddComboBox(UINT nID, UINT lab, int dt,
int ct, const CString &name,
const CString &def, const CString &dict);
void AddLabel(UINT nID, COLORREF cr=RGB(0,0,0), BOOL trans= TRUE);
void AddEdit ( UINT nID,UINT lab, int dt,
int ct, const CString &name,const CString & def,
int chkmask, const CString& min1, const CString &max1);
void AddButtons(UINT nID);
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);
To validate the data, you can call:
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.
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
CXMLCmd. Data control initialization is using
CXMLResult. It has the following format:
In "…………" part , you can write any tags with values.
The format for
CXMLCmd is as following:
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
- Step 2. Declare a dictionary used by this system or just in dialog.
- Step 3: Add a function as an entry to initialize the control group.
- Step 4: Add initialize control group and Dictionary in constructor of the form.
CChldInfantLang::CChldInfantLang(CWnd* pParent )
: CBitmapInnerDlg(CChldInfantLang::IDD, pParent)
m_pDict = NULL;
- Step 5: Add
DoDataExchage function in
DoDataExchange function of dialog
void CChldInfantLang::DoDataExchange(CDataExchange* pDX)
- Step 6: Call
InitControl of control group to complete initialization of control groups.
m_cntGroup.InitCotrols (this, m_pDict);
- Step 7: Set initialization data to control in
PreInit function using a configuration file using
CString strPath = theApp.m_Path +_T("\\chldInfantLang.xml");
- Step 8: Call update to controls and get XML data in a string format for further usage.
m_cntGroup .AddToXML (cmd);
More to be complete
- To support more controls, include
- 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.
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.
HMXNumEdit - Massimo Colurcio - firstname.lastname@example.org
CXShadebutton - email@example.com
CLabel - I forgot, sorry.
CcoobBtn - I forgot, sorry.