When i programatically create a non-modal dialog from a dialog resource ID i use the following code:
CDialogEx myDialog(IDD_DIALOG1, this);
...
myDialog.Create(IDD_DIALOG1, this);
One can see that this isn't very practical as one needs to pass the dialog ID twice.
Did i understand something wrong about the creation of a dialog?
Is there a way to avoid that repetition?
What is the reason that the MFC class CDialogEx provides a constructor
CDialogEx(UINT nIDTemplate, CWnd* pParent=NULL);
but also an inherited method
virtual BOOL CDialog::Create(UINT nIDTemplate, CWnd* pParentWnd = NULL);
which forces me to repeat the dialog ID?
The reason behind is that i want to derive an own class myDialogClass from CDialogEx but do not want to assign an ID at this point. Would it be possibly ok to pass a dummy ID to the CDialogEx constructor?
I want to assign the ID when i create the dialog window, not before.
class MyDialogClass: public CDialogEx{
...
public:
MyDialogClass(CWnd* pParent=NULL):CDialogEx(DUMMY_ID, pParent){}
}
Furthermore i want to extract my dialog class into an own library (MFC extension library) and use it in some other code.
My dialog class provides an additional memory DC to the normal DC, but this could just be any other functionality.
I want to use this additional functionality in several contexts.
“Did i understand something wrong about the creation of a dialog?” There are two scenarios a dialog box may be used: modal & modeless. You mixed them:
CDialog & CDialogEx provides a parameterless constructor which may be used with the modeless scenario. Your code becomes:
CDialogEx myDialog();
// ...
myDialog.Create(IDD_DIALOG1, this);
For more information on how to correctly implement a modeless dialog, see this.
Related
I'm new to MFC. I chose to create an office style MFC app through the wizard in VS2017. I now want to extend CMFCShellTreeCtrl so I created another class with that as the base class. The basics are fine. My issue is that I want to do something like:
whatever MyClass::FuncitonCalledAfterControlCreated(...)
{
SetFlags(GetFlags() | SHCONTF_NONFOLDERS);
ModifyStyle(0x0, TVS_CHECKBOXES);
}
But I'm having trouble figuring out what virtual function to override or am I supposed to do one of those message mapping things? I would guess that whatever it is, it would be common to all controls? Anyway, what would be the appropriate function?
TIA!!
If control is derived from CWnd a WM_CREATE is issued which can be directed to the control via a message map of:
ON_WM_CREATE()
And member function:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
If on a dialog resource the WM_CREATE won't occur. Some say you can use PreSubClassWindow but on a case of testing Create(), that call comes BEFORE the CreateWindowEx call so won't work for setting the TVS_CHECKBOX style. I didn't try a CDialog with a tree control and check the call stack.
I read few basics about MFC and I am trying to implement simple editor using CEditView. Please correct if my current understanding is wrong.
CEditView is just a view, physically there won't be any control placed in it.
CEditView is just the area, where user can see and enter the text.
Explicitly no need to place any CEdit control on to the view (like
we put CEdit control on the CDialogView).
CEdit control is just a member of CEditView.(GetEditCtrl()).
Currently CEdit provides so many edit related features. If I want to extend that CEdit member class, is it possible to do it? It's something like:
Class CMyEdit : public CEdit
From MSDN:
You construct a CEdit object in two steps. First, call the CEdit
constructor and then call Create, which creates the Windows edit
control and attaches it to the CEdit object.
I create dummy constructor:
CMyEdit::CMyEdit
{
}
After that I called Create:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID);
//Here I have given dummy CRect and dummy Control ID that is 1;
myEdit->Create(ES_MULTILINE | WS_CHILD |
WS_VISIBLE | WS_TABSTOP |
WS_BORDER,CRect(10, 10, 100, 100), this, 1);
If I create and when I run the program, CEdit control is coming onto the CEditView. But I don't want that physical control onto the CEditView.
Do we need to create method here? Not sure how to extend this CEdit class behaviour without creating the control.
CEditView is a CEdit as a view, In fact In a CEdit and in a CEditView there is a normal Windows API Edit control inside. It is a little trick, that the MFC is using. It creates a simple Edit control, (so there is one window handle), but you can treat this handle via a CView pointer AND a CEdit pointer. When you look into the code, you see that GetEditCtrl just casts the this pointer.
When you create a View with a CEditView you have always a CEdit/Edit control inside... you can't change that.
Sure that you get a new edit control over a CEditView if you create an additional control inside of it.
If you can't create a CMyEditView derived from CView with a CMyEdit inside of it (using the full view).
The easiest way would just be to extend a CEditView to a CMyEditView...
It is not very clear what behavior you are trying to modify but looks like you are aware that in MFC you can create your own custom control. You can override the methods of your CEdit in the custom control class CMyEdit like OnPaint() etc. and achieve the same. You should go through with the tutorial which mentioned in details about the custom controls and then you will get to know what all methods you need to override in your custom controls.
I have a CDialog created by wizard named CDialogParent, then create a child dialog template has IDD= IDD_CHILD_DLG1, in this child dialog I put one button IDC_BTN1 (I don't create class handler for this child).
BOOL CDialogParent::OnInitDialog()
{
....
CDialog *pChild = new CDialog();
pChild->Create(IDD_CHILD_DLG1, this);
pChild->ShowWindow(SW_NORMAL);
}
Normally, I need to create new class handler CDialogChild for child and add message map like:
BEGIN_MESSAGE_MAP(CDialogChild, CDialog)
ON_BN_CLICKED(IDC_BTN1, &CDialogChild::OnBnClickedBtn1)
END_MESSAGE_MAP()
Problem that I want to catch control's message IDC_BTN1 of child dialog BUT by declare message map in CDialogParent like:
BEGIN_MESSAGE_MAP(CDialogParent, CDialog)
ON_BN_CLICKED(IDC_BTN1, &CDialogParent::OnBnClickedBtn1)
END_MESSAGE_MAP()
How to do this without create new class handler?
Thanks for help!
In short: You cannot.
There are 2 reasons why this is not possible:
Control IDs are unique among siblings (i.e. controls sharing the same parent window) only. Different dialogs can use the same ID for different controls.
I'll assume you mean Owned dialog when you say Child dialog (those are different concepts, but the following rationale is the same). When setting up an owner-owned window relationship, that relationship is based on window handles (HWND). There is no additional C++ type information available. Both the type and object pointer are required to call the appropriate class member in a message map.
If you want to be informed about an event raised in an owned dialog, implement a message handler in the owned dialog's class and post a message to the owning dialog.
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.
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.