I have defined a new dialog and its controls in an already existing resource file. I have also created a new file which will handle the events being generated from this dialog. But I am not sure how to connect these two.
Is the statement enum { IDD=IDD_NEW_DIALOG }; all that is required to connect the two? Or should we add some other statement?
The way this is usually done in MFC is to define a dialog template in the resource editor (as you've done), then in C++ derive a class from CDialog and associate it with the dialog template (which it sounds like you've done - it's not entirely clear).
What actually associates the two is the constructor for your CDialog code. If you look at dialog related code auto-generated by the MFC class wizard, you'll see in the constructor implementation something like this:
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/) : CDialog(CMyDlg::IDD, pParent)
where CMyDlg::IDD is defined as an enumeration with a value of your new dialog template's identifier. It's this that makes it all happen, not the declaration of the enum. You could modify it to
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/) : CDialog(IDD_NEW_DIALOG, pParent)
and it will still work (assuming IDD_NEW_DIALOG is the template id of your dialog in the resources), as all that's happening is the dialog id is being passed into the constructor.
In general, it's always worth remembering that, despite initial appearances, MFC does not bind to Windows through bits of compiler magic - it's all done with C++ and a few macros.
EDIT: DIALOGEX and DIALOG declare slightly difference dialog resource formats that Windows understands: the former is newer than the latter. However both have been around since at least Windows 95, so it's not a very significant distinction.
That's all that is needed when you create the dialog through the dialog class (DoModal(), or Create for a non-modal dialog), which is the normal way to go.
You of course need to inherit from CDialog, and add a message map to route the messages to your ewvent handler functions.
Use class wizard to create a class for newly created dialog. ctrl+w is the shortcut key from UI resource view.
Related
I'm using raw Win32 and C++ for a project. As I understand it, I am able to superclass Windows controls by retrieving the class information, replacing the procedure, then registering this as a new class and using it when creating a new window. Subclassing is done by replacing the window's procedure after the window is created. The advantage of superclassing is that you are able to process messages before CreateWindow() returns.
I'm looking to see if it's possible to superclass a dialog box created with CreateDialog() because I'd like to use a resource file for the dialog layout. The problem is that I don't know how I would provide my superclass when I create a dialog box. Is it even possible? Any idea how MFC handles this?
If you use an extended dialog box template to create your dialog, you can specify a custom window class as part of the DLGTEMPLATEEX definition.
The dialog manager will create and layout your dialog as normal, and call your window procedure for any dialog messages. You can use the DefDlgProc function to obtain default processing for any dialog messages you don't want to handle yourself.
I am more use to Qt than MFC, but I have the following concern:
I was creating a panel with 4 buttons, all these buttons have the same purpose, if you click on them it opens another dialog.
This dialog has the exact same layout for the 4 buttons.
However since a dialog is associated to a class via the enum { IDD = ...} I was wondering if it was actually possible to use the same template of dialog for more than one object or if I had to actually create 4 dialogs doing basically the same thing with a different id??
The resource ID in the statement enum { IDD = <resource ID> }; defines a compile-time constant, that is passed to the CDialog-c'tor (by default1)) to construct the native controls from a dialog template resource. This is then passed to one of the dialog creation functions (CreateDialog, etc.) to do the heavy lifting.
There are no restrictions to prevent using a single dialog template for multiple CDialog-derived classes.
1) You can pass the dialog template resource ID directly to the CDialog-c'tor in your custom class implementation, and do not need to use the standard enumerated value IDD.
Background
I am woefully inexperienced with MFC and C++.
I have a set of dialogs that all have a small section with the same set of controls and extremely similar code.
I would like to separate that small section of controls from all dialogs move the code from all the dialog classes into a single class.
Problem
I'm not sure how to go about it. All my ideas all seem to have their own problems because I am so inexperienced.
Could I make a super class these dialogs inherit from that creates the controls dynamically given an (x, y) and that hooks up all the connections and communicates the few specifics through virtual methods?
The problem is I don't know the specifics:
Where would the super class inherit from? (CWnd? CDialog?)
Where would I create the controls in the super class? (OnInit? Constructor?)
Where would I initialize the super class in its subclasses? (OnInit? Constructor?)
Would I just have two message maps? One for the super class and one for the sub class?
Are there any other pitfalls I should watch out for?
The small section that you want to reuse can be an ordinary modeless dialog, derived from CDialog. You can create its controls with the resource editor - just like any other dialog - so they won't have to be created dynamically. The trick is to turn off the dialog's titlebar style (in the resource editor) so it will not be visually apparent that this section is a separate dialog. It will blend right in with the parent dialog.
For each place you want to reuse this dialog just create it and place it on the parent dialog with (x, y) coordinates using SetWindowPos.
I have a custom MFC control, subclassing CWnd. Other than providing OnPaint and PreSubclassWindow implementations, it overrides no default functionality and does nothing weird in construction except registering a window class in the constructor.
The control is added to the dialog using the dialog editor to add a custom control.
The dialog worked when it was a simple modal dialog deriving from CDialog, but we have code which calls CWnd::CreateDlgIndirect to instance dialogs and this fails with the custom control... but works if the custom control is removed from the resource template.
Found it!
I had the custom control register its window class in its own constructor. I had member in the dialog of this custom control type, so the ctor was being called when the dialog was created, as intended.
But, it turns out the base class I changed the dialog to derive from, instead of CDialog, was calling CreateDlgIndirect in its own ctor, before my new class' own initialisation was reached - so it was trying to create custom control before the window class was registered.
My (slightly messy solution) is to ensure the window class registration happens at application startup in the InitInstance method, before any dialog stuff happens.
We layout dialogs using the resource editor. So say I have a RichEditCtrl called IDC_RICH. And I want to link it to an instance of a custom class CMyRichEditCtrl : CRichEditCtrl, without losing the ability to set properties on it in resource editor.
What's the right way? You can certainly get some functionality by creating a DDX-linked variable, and changing the type to CMyRichEditCtrl. But in some cases I see people calling code like:
m_Rich.SubclassDlgItem(IDC_RICH, this));
What's the difference?
EDIT: One problem I'm seeing is that when I override Create(Ex) methods, they don't get called. It's kind of like the control is already created by the time my object gets linked to the resource identifier, pehaps?
DDX_Control() does SubclassWindow() under the hood. SubclassDlgItem is a shortcut for SubclassWindow(GetDlgITem()). Usually (broad generalisation here) the people using SubclassWindow are the ones who picked up that habit before DDX_Control existed (pre-1995 or so?) and never really got into MFC-mode, or people who copy and paste their programs together from blog snippets left and right.
So, use DDX_Control() for clarity, although it will technically not make a difference if you use SubclassDlgItem().
The windows you put on a dialog with the resource editor are created using CreateWindow(Ex) with the first argument set to the class name that is specified in the .rc file. The DDX_ mechanism then associates this instantiated window with the dialog class member in DoDataExchange().
MFC is a layer over Win32 but MFC development doesn't completely shield you from Win32. It's more like a bunch of classes and methods that take away some of the drudgery of MFC and provide some form of object-orientedness. The methods of MFC object aren't the ones that are doing the real work, and much of the framework does things under the hood and doesn't notify the 'upper layer' (i.e., MFC objects) unless that is explicitly hooked up. Create() is such a method that is only there if you want to manually create a control, it's not called by MFC when the object is created. (this is a generalization because sometimes it is, but that's outside of the scope of this discussion).
1> For controls that you put on a dialog with the resource editor, used DDX_Control:
class CMyDlg : public CDialogEx
{
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
public:
CRichEditCtrl m_Rich;
};
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_RICHEDIT1, m_Rich);
}
2> For controls that create manually:
CRichEditCtrl m_Rich;
m_Rich.Create(...);
m_Rich.SubclassDlgItem(IDC_RICH, this));