|
How to use DDX with WTL? Author: Girish Bharadwaj This has been asked a few times in the ATL newsgroups. (For the uninitiated, WTL is Window Template Library). There is an excellent article by Dr. Richard Grimes about how to use WTL. So, I will not go there. Adding DDX support to your WTL application WTL comes with a neat class called CWinDataExchange which allows you to do data exchange between member variables and dialog items. In order to use that, you have to do the following things: Assuming that you have already generated a WTL application from the wizard, 1) Add #include <atlddx.h> to stdafx.h (or any other convenient place). If you want to use CString available from WTL in the data exchange code, you have to #include <atlmisc.h> before including atlddx.h.
#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
//Add following lines
#include <atlmisc.h>
#include <atlddx.h>
2) If you want to use float arguments to be exchanged, you have to define a compile time directive _ATL_USE_DDX_FLOAT. Note that if you use this, you cannot use _ATL_MIN_CRT since floats are exchanged using the CRT functions. In particular, it uses <float.h> to do that. 3) Derive the class which requires the data exchange from CWinDataExchange.
class CMainDlg : public CDialogImpl<CMainDlg>,
public CWinDataExchange<CMainDlg> //Add this
{
public:
enum { IDD = IDD_MAINDLG };
4) Add DDX map to the class
BEGIN_DDX_MAP(CMainDlg)
DDX_TEXT(IDC_STRING,m_edit1)
DDX_INT(IDC_INT,m_int)
DDX_INT_RANGE(IDC_INT_RANGE,m_int_range,-10,100)
DDX_TEXT_LEN(IDC_STRING_RANGE,m_string_range, 8)
DDX_FLOAT(IDC_FLOAT, m_float)
DDX_FLOAT_RANGE(IDC_FLOAT_RANGE,m_float_range,-1.00,2500.24)
DDX_CHECK(IDC_CHECK_BOX,m_check)
DDX_RADIO(IDC_RADIO1, m_radio)
//DDX_CONTROL() is just a simple wrapper to do subclassing of a given window.
END_DDX_MAP()
Explanations on each macro and the functions are provided later. 5) Provide default implementation for OnDataValidateError() and OnDataExchangeError() functions. Those functions are called by the framework (CWinDataExchange) when it encounters an error either during validation or while exchanging. If you do not provide any implementation, the default implementation will give a Beep() and sets the focus on the offending control. OnDataValidateError() occurs only when you have set the limits for the corresponding control, i.e., length of the string, min or max value for an int etc
void OnDataValidateError(UINT id, BOOL bSave,_XData& data)
{
CString str;
switch (data.nDataType)
{
case ddxDataNull:
str = "Data is NULL.";
break;
case ddxDataText:
str.Format("Type text, length of data :%i, allowed; %i\n",
data.textData.nLength, data.textData.nMaxLength);
break;
case ddxDataInt:
str.Format("Type int, value:%i, allowed min:%i, max:%i\n",
data.intData.nVal,data.intData.nMin,
data.intData.nMax);
break;
#ifdef _ATL_USE_DDX_FLOAT
case ddxDataFloat:
case ddxDataDouble:
{
char buf[1024];
sprintf(buf,"Type float: value:%f, min:%f, max:%f",
data.floatData.nVal,data.floatData.nMin,
data.floatData.nMax);
str = buf;
}
break;
#endif
}
MessageBox (str);
}
void OnDataExchangeError(UINT id, BOOL bSave)
{
MessageBox ("DataExchange Error");
}
6) Call DoDataExchange() with TRUE to save and FALSE to load. You can use the second argument of DoDataExchange normally –1, to do the data exchange only on a particular control. DoDataExchange returns TRUE if it successfully exchanged the data else will return FALSE.
void SetupDlg()
{
m_edit1 = "Hello there";
m_string_range = "abcdefgh";
m_int = 1;
m_int_range = 12;
#ifdef _ATL_USE_DDX_FLOAT
m_float = -23.45;
m_float_range =1212.23232;
#endif
m_check = 1;
m_radio = 0;
DoDataExchange(FALSE);
}
void ShowSels()
{
if (DoDataExchange(TRUE))
{
char buf[1024];
#ifdef _ATL_USE_DDX_FLOAT
sprintf(buf,"%s\n%i\n%f\n%s\n%i\n%f\n%i\n%i\n",
m_edit1,m_int,m_float, m_string_range,
m_int_range,m_float_range,
m_check,m_radio);
#else
sprintf(buf,"%s\n%i\n%s\n%i\n%i\n%i\n",
m_edit1,m_int,m_string_range,m_int_range,
m_check,m_radio);
#endif
MessageBox(buf);
}
}
Structures used by CWinDataExchange
// Helpers for validation error reporting
enum _XDataType
{
ddxDataNull = 0,
ddxDataText = 1,
ddxDataInt = 2,
ddxDataFloat = 3,
ddxDataDouble = 4
};
struct _XTextData
{
int nLength;
int nMaxLength;
};
struct _XIntData
{
long nVal;
long nMin;
long nMax;
};
struct _XFloatData
{
double nVal;
double nMin;
double nMax;
};
struct _XData
{
_XDataType nDataType;
union
{
_XTextData textData;
_XIntData intData;
_XFloatData floatData;
};
};
All these are used only during error reporting and otherwise, not used. Since, these are self-explanatory, I won't get into explaining each of them. You can use this in validation error handler as:
void OnDataValidateError(UINT id, BOOL bSave,_XData& data)
{
CString str;
switch (data.nDataType)
{
case ddxDataNull:
str = "Data is NULL.";
break;
case ddxDataText:
str.Format("Type text, length of data :%i,
allowed; %i\n", data.textData.nLength,
data.textData.nMaxLength);
break;
case ddxDataInt:
str.Format("Type int, value:%i,
allowed min:%i, max:%i\n",data.intData.nVal,
data.intData.nMin,data.intData.nMax);
break;
#ifdef _ATL_USE_DDX_FLOAT
case ddxDataFloat:
case ddxDataDouble:
{
char buf[1024];
sprintf(buf,"Type float: value:%f,
min:%f, max:%f",data.floatData.nVal,
data.floatData.nMin,data.floatData.nMax);
str = buf;
}
break;
#endif
}
MessageBox (str);
}
MACROS in CWinDataExchange CWinDataExchange has several macro helpers to do the data exchange. Following is the listing of those macros that you can use in BEGIN_DDX_MAP()/END_DDX_MAP().
DDX_TEXT(<Id of the control> , <variable name>)
DDX_TEXT_LEN(<id of the control>, <variable name>,
<length allowed>)
DDX_INT(<id of the control>, <variable name>)
DDX_INT_RANGE(<id of the control>, <variable name>,
<minimum value>, <maximum>)
DDX_UINT(<id of the control>,<variable name>)
DDX_UINT_RANGE(<id of the control>, <variable name>,
<min>, <max>)
DDX_FLOAT(<id of the control>, <variable name>)
DDX_FLOAT_RANGE(<id of the control>, <variable name>,
<min>, <max>)
DDX_CONTROL(<id of the control>, <variable name>)
DDX_CHECK (<id of the control>, <variable name>)
DDX_RADIO(<id of the control>, <variable name>)
DDX_TEXT and DDX_TEXT_LEN can take LPSTR, BSTR, CComBSTR or WTL::CString as arguments. For DDX_UINT , DDX_UINT_RANGE, DDX_INT and DDX_INT_RANGE argument type is an int. For DDX_FLOAT and DDX_FLOAT_RANGE, the variable type is to be a double. Note that this is wrapped with _ATL_USE_DDX_FLOAT directive. So, if you don’t want to use CRT you have to avoid floats. (or is it the otherway around?) The difference between DDX_UINT and DDX_INT is that the former does does exchange with unsigned integers and the latter takes the signs into consideration. DDX_CONTROL is just a simple wrapper to do SubclassWindow() on a given dialog item. Note that it needs the second argument to be a CContainedWindow or CCindow.
template <class TControl>
DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
{
T* pT = static_cast<T*>(this);
if(!bSave && ctrl.m_hWnd == NULL)
ctrl.SubclassWindow(pT->GetDlgItem(nID));
}
Both DDX_RADIO and DDX_CHECK take int as the variable. To Setup the radio buttons, you need to create a group of radio buttons with the first in the zorder with WS_GROUP style. The rest of them should not have that. Note that DDX_CHECK gives 0, 1 or 2 based on the selection (0 – unselected, 1- selected and 2 – indeterminate). Mail a question to the author!! As part of the IDevResource commitment to Open Publishing, all of our authors are available to answer all of your trickiest questions at Author Central. For information about the authors, or to mail a question, visit them at Author Central. Did you like this article? If you liked this article, tell us about it. You can email your remarks to us at [email protected] Have your say about the article. You can make your point about the article by mailing [email protected] (If you haven't allready joined, you can join by going to onelist.com/community/dev-com). More ByteSize articles: 'ILoveYou' By Richard Grimes, 200500 COM+ 2.0 - First Announcement of Microsoft's New Technology By Richard Grimes, 100500 How to use DDX with WTL? By Girish Bharadwaj, 270300 ATL Server By Richard Grimes, 220200 COM Threading Models By Gopalan Suresh Raj, 070200 ActiveX & COM By Gopalan Suresh Raj, 270100 Type Library Info, XML and a bit of XSL for fun! by Richard Anderson 121199 COM and Apartments By Richard Grimes, 070100 What is WTL? By Richard Grimes, 070100 An Introduction to Interface Programming By Richard Grimes, 070100 Contribute to IDR: To contribute an article to IDR, a click here.
|
|