Re: Dynamic Dialog : Edit Control Message Handling and DoDataExchange
Dear Joseph,
Thanks a lot for giving me some insight for the DDX DDV routines. I am
planning to shrugg it off.
I have read much of your MVP articles and really helped me lot. :)
I have redesigned my class now and use the GetWindowText and
SetWindowText with the control variables directly.
Take a look at this:
//Custom Edit Control class
class CEditControl: public CEdit
{
//Implement the Dynamic creation for accessing the class Information
at Run Time
DECLARE_DYNAMIC(CEditControl)
public:
//Currently empty
};
//Container class
class CControls: public CWnd
{
public:
//Constructor
CControls();
//Destructor
~CControls();
protected:
//Embedd the control class in the container
CEditControl m_EditControl;
CLabelControl m_LabelControl;
CComboControl m_ComboControl;
public:
//The method exposed to create the controls with just the control type
and Resource ID
BOOL Create(CWnd *pParent,CRect rect,int ControlType,int nID);
BOOL GetData(CString &Data,int Type);
};
Here I am exposing this container class in the main application and
creating the controls dynamically and attaching them to the parent
window with its handle passed as CWnd* to the create function.
I am creating the Resource ID dynamically incrementing them , starting
with 1111.
GetData will return me the information from the control.
I have some of the last questions for you ( Hope I am not asking much
:) )
I am facing following issues now.
1. How to align the controls properly. : There might be many controls
which needs alignement. Currently I am getting the dialog box
co-ordinates and putting the controls with the co-ordinates using the
CRect structure in create function.
I need to do lot of computation of the Pixels of the dialog in order to
align them properly.
SO , wondering if this is the right method or is there any other method
with different logic that could be used for alignment?
2. If the dialog box client area exceeds the numnber of controls it can
display, then I am planning to have a Scroll bar control to the dialog,
but have no idea How I will be scrolling down to show other controls.
I have tried to use the CScrollBar but it is not of much help.
Could you please throw some light on how to readjust the controls and
show other controls on the dialog box?
I did not get much help for this in MSDN.
This is the biggest issue thats nagging me, How to use the Scroll Bar
on a dialog in order to show the controls which were added at run time.
Hope your continuous support on this one as well.
Thanks.
--
Abhijit.
Joseph M. Newcomer wrote:
My own inclination is to avoid creating them dynamically. Instead, create them
statically, and mark them as invisible and disabled, and tuck them off in a corner of your
dialog. When you need them, make them visible and move them to where you want them.
Note that "move them to where you want them" must not involve any constants, with the
possible exception of 2 (as in /2 to get a control centered); all heights and widths must
be computed at runtime. One of the advantages of creating dummy controls is that they
always get the right height for the user-selected font. Even in those cases where I have
to create controls dynamically because I really, really need to create controls
dynamically (there are lots of good reasons to do this, but many more bad reasons), I
always have dummy controls tucked in a corner of my dialog, such as an edit control, a
check box control, a radio button control, a static label, a combo box, etc. just so that
the invisible controls get the right height, and I create my new controls using this
height as one of the parameters (and the width is always computed on-the-flly, either by
using GetTextExtent or as some ratio of the dialog size, such as half the width, or
something like that).
Putting invisible static controls in the places you want to create your controls is also a
good idea. If I have to stack controls, I'll create an invisible static rectangle of the
size of the gap I want to put between the controls, and derive its pixel size at runtime
to stack the controls.
If you ever hardwire a parameter to a CRect for creating the control, you are doomed,
because those values essentially only work on your machine with your monitor and the
current version of the display driver for the current video card you have, making it
nearly impossible to run the program effectively on any other machine in the Known
Universe.
If you need to create lots of controls, ON_..._RANGE Message Map entries are for you. For
example, all edit controls will be in the range 10000..10999, all combo boxes in the range
11000...11999, etc., which allows you to handle the decodes for the objects on your own.
For example, I'll do table lookup given the control ID to find the object it represents
(which is derived from a "controller description file" in my case, which is a
customer-supplied definition of what the GUI needs to have). But if the number of
controls is actually known, and essentially fixed, just do it all at design time and let
SW_SHOW and SW_HIDE handle the details (and SetWindowPos: don't plop all the controls down
one on top of the other; that way you end up with a maintenance nightmare!)
joe
*****
On 31 May 2006 06:11:36 -0700, abhijitcpawar@gmail.com wrote:
Hi All,
I am facing a problem related to the DoDataExchange for the Controls on
the Dialog Box in a MFC dialog based application.
I will explain my architecture first.
I have a MFC dialog with two static buttons on it. I want to create the
dynamic controls on the client area of the dialog box.
For this I am using the my subclasses derived from the default
controls, lets say Edit Control.
After creating my class, MyEdit from the CEdit class, I am using
another class as a container to hold all the objects of the different
controls.
I am exposing this class to the application's dialog.
In the main applications OnInitDialog() , I create the Edit control
with the help of the container class.
It creates the class successfully. But now, I have some variables in
the container class which I want to associate with this Edit control
using the DoDataExchange.
I have defined my own DoDataExcahange in the container class...
The control resource I am getting dynamically. So when I give this ID
in the DDX_Text function, it throws the exception saying teh Exchange
controls is not associated with this variable.
//This is my class.
class DynamicEdit: public CEdit
{
DECLARE_DYNAMIC(DynamicEdit)
protected:
//Subclassed this message
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
DECLARE_MESSAGE_MAP ()
public:
DynamicEdit();
CString m_strName;
//~DynamicEdit();
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
};
//Container class
class MyControls: public CWnd
{
public:
MyControls();
DynamicEdit *m_DynamicEdit;
*****
No need to make this a DynamicEdit *; it could just be a DynamicEdit!
*****
BOOL Create(CWnd *pParent,CRect rect, int nID, int Type);
//~MyControls();
protected:
afx_msg void OnChar (UINT nChar, UINT nRepCnt, UINT nFlags);
DECLARE_MESSAGE_MAP()
//The data exchange for all the controls
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
};
Implementation file::
//Message Map for the Edit Control
BEGIN_MESSAGE_MAP (DynamicEdit, CEdit)
ON_WM_CHAR ()
END_MESSAGE_MAP ()
void DynamicEdit::DoDataExchange(CDataExchange* pDX)
{
CWnd::DoDataExchange(pDX);
DDX_Text(pDX,1021,m_strName); <===== Error
*****
This suggests you are trying to use UpdateData. Most especially for dynamic cases, you
must AVOID UPDATEDATA! It does nothing you will find useful. SetWindowText and
GetWindowText are perfectly respectable, do what you need, and do not involve any need to
call UpdateData (see my essay on Avoiding UpdateData). And if you want to limit the
number of characters, CEdit::SetLimit [or some similar name] works perfectly fine; you
don't need any DDV to accomplish this!
*****
//DDV_MaxChars(pDX,m_strName,10);
}
Here the Edit control is displayed properly on the dialog but the Data
Exchange could not be done.
*****
So don't do it. Don't even bother with it. Pretend you never heard of UpdateData and
your life becomes simpler
*****
I am using the Main dialog's handle to create the controls on it. So I
want to delegate the message to my container class and use the
DoDataExchange of my custom control class.
How could this be done?
I am not getting any idea if we could attach a resource dynamically to
the variable as it always fails..
Also, If I am to create the Dynamic controls at run time , will this
approach work ( Container class)...
I desparately want to use the DDX and DDV routines instead of using the
GetDLGItem API's...
*****
Why in the world would you want to ever use GetDlgItem? If you're writing more than one
GetDlgItem per year, you're probably doing the wrong thing. See my essay on Avoiding
GetDlgItem on my MVP Tips site.
Also, I believe DDV is completely the wrong approach to validation; it happens far too
late in the process of data entry, and issues meaningless messages to the user. I took
one completely unusable customer program and made it not only user-friendly but downright
user-cuddly, and the first thing I did to make that happen was to rip out every possible
use of DDX on values and all uses of DDV.
****
Is there any way to solve this.
Any help in this regard is highly appreciable.
*****
Lots of ways, most of which involve ignoring DDX and DDV entirely.
joe
*****
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm