Use CMFCPropertyGridCtrl, appear: OnDestroy or PostNcDestroy in derived class will not be called - mfc

The dialog box will pop up in static mode, as follows:
CTestDlg dlg;
dlg.DoModal ();
Ctestdlg contains cmfcpropertygridctrl control
When the ctestdlg dialog box pops up, you will see:
AppMsg - Warning: calling DestroyWindow in CWnd::~CWnd; OnDestroy or
PostNcDestroy in derived class will not be called.
If I remove the cmfcpropertygridctrl control, this warning will not appear.
But it has to be used, so what should we do to make the warning disappear?

Related

How to bring dialog to top when child control on it is clicked

Working with C++ app, using MFC.
I have an aux dialog that is created as a secondary dialog to the main application dialog. This aux dialog has several buttons etc. as child controls. If I click on the aux dialog background or in its nonclient area, it comes to the top as expected. But if I click on one of the child buttons, the button functions correctly but the dialog doesn't come to the top.
Is there some event I should handle in the dialog to bring it to the top when any child control is clicked? Or perhaps set some property in the dialog that will ensure that happens?
I'm suspicious I need to handle some activate or focus event that I'm not. Or maybe once the children handle the click, it needs to be propagated up? Or the other way around?
EDIT: Additional details answering question in comment:
Main dialog class CMyDlg and aux dialog class CAuxDlg are both derived from CDialog.
A blank dialog resource exists for each; all child controls etc are created programmatically.
class CMyDlg : public CDialog
{
public:
CAuxDlg *aux;
...
protected:
virtual BOOL OnInitDialog()
...
DECLARE_MESSAGE_MAP()
}
class CAuxDlg : public CDialog
{
...
protected:
...
DECLARE_MESSAGE_MAP()
}
Aux dialog is created in main dialog's OnInitDialog() method:
BOOL CMyDlg::OnInitDialog()
{
...
aux = new CAuxDlg(this);
aux->Create(IDD_AUX_DIALOG, GetDesktopWindow());
...
}
In the aux dialog resource, all properties are FALSE except for:
border: resizing
style: popup
title bar: true
tool window: true
use system font: true
All of my custom controls are derived from a custom base class CMyBase. I added a handler to this base class:
ON_WM_LBUTTONDOWN()
...
void CMyBase::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd::OnLButtonDown(nFlags, point);
GetParent()->SetActiveWindow();
}
and ensured that classes derived from CMyBase that handle WM_LBUTTONDOWN also call the base class's handler:
class CMyCtrl : public CMyBase
...
void CMyCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// do stuff here
CMyBase::OnLButtonDown(nFlags, point);
}
and that seems to have done the trick.
Note 1: As mentioned in the comments on the question, if I add a standard CButton or CStatic or even CWnd to the aux dialog, clicking on that standard control does bring the aux dialog to the top. I don't know what the standard controls are doing that mine is not (other than elaborate mouse handling), but it must be something like this.
Note 2: It isn't enough to just call CWnd::OnLButtonDown(). Activating the containing aux dialog seems to be necessary.

Where to initialize a rich edit control on another dialog?

I have an MFC dialog based application that has 2 Dialogs: Main Dialog CMyDlgand Second dialog CMyDlg2.
On the main Dialog I add a Button "Go dialog 2". So I added a handler for the button so that when clicked it pops up the second dialog. Everything works fine But on the second Dialog I have added a Rich Edit Control from toolbox. I Added for it a variable. I also added a class for the second dialog.
Now If I run the Application I get the dialog one and if I pressed "Go to dialog 2" I got what I want. But I need at some point to change the font of the rich edit control but my program crashes.
So I overrided OnInitDialog and inside it do some changes to the control but program crashes. After debugging I found that the handle of rich edit is null?!
So how and where can I change the color or do some initializations to the control?
(I called AfxInitRichEdit2() in OnInitInstance())
BOOL CMyDlg2::OnInitDialog() {
m_richEdit.SetWindowText("Hello there!"); // program crashes because the handle m_richEdit is null.
return TRUE;
}
And this is the handler of button that creates the Dialog2 and that contains the rich edit control:
void CMyDlg::OnBnClickedButton1(){
CMyDlg2 theDlg;
theDlg.DoModal();
// TODO: Add your control notification handler code here
}
If I create the rich edit control programmatically then everything works fine because I create it at OnInitDialog and then it works fine but I need the one that is I added using the wizard toolbox.
*** The thing is that if I write:
m_richEdit.SetWindowText(""); // program crashes but if I wirte:
GetDlgItem(IDC_RICHEDIT221).SetWindowText(""); it works fine?
You probably have the following code inserted by wizard:
void DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_RICHEDIT22, m_richEdit);
}
This tells the dialog to associate m_richEdit with the dialog control IDC_RICHEDIT22. But this association is not performed until the base class method CDialog::OnInitDialog(); is called.
BOOL CMyDlg2::OnInitDialog()
{
//this line should work:
GetDlgItem(IDC_RICHEDIT22)->SetWindowText("Hello");
//this line won't work:
//m_richEdit.SetWindowText("Hello there!"); <- richedit's handle is NULL
//this line will subclass m_richEdit
//plus run other initialization
CDialog::OnInitDialog();
//m_richEdit is ready
m_richEdit.SetWindowText("Hello there!");
return TRUE;
}
It's recommended to put CDialog::OnInitDialog() int the first line, to make sure the initialization is done.
GetDlgItem works because the control IDC_RICHEDIT22 exists in the dialog template and you have a valid dialog handle. You are basically making a simple call based on WinAPI's GetDlgItem:
HWND hedit = ::GetDlgItem(m_hWnd, IDC_RICHEDIT22);
::SetWindowText(hedit, "Hello world");
There is no additional initialization needed.
But m_richEdit is just a C++ object, declared as CRichEditCtrl m_richEdit; The constructor for this C++ class doesn't do much besides setting m_hWnd to NULL.
Once it's associated with a valid window handle, we can begin using its windows methods such as CRichEdit::SetWindowText

Getting a debug assertion error when calling GetDC() (MFC)

I'm making a MFC application using the Doc/View architecture with Visual Studio 2017, and for some reason I get that error whenever I call GetDC() inside this function:
void CDigitRecognizerView::ClearScreen(void)
{
CDC* dc;
dc = GetDC(); // debug assertion error here
CBrush brush;
brush.CreateSolidBrush(0xFFFFFF);
dc->SelectObject(&brush);
CRect rect;
GetWindowRect(&rect);
dc->FillRect(&rect, &brush);
CDigitRecognizerDoc* pDocument = GetDocument();
ReleaseDC(dc);
}
This is the message map macro defined in the app class:
BEGIN_MESSAGE_MAP(CDigitRecognizerApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, &CDigitRecognizerApp::OnAppAbout)
ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
ON_COMMAND(ID_EDIT_CLEARSCREEN, CDigitRecognizerView::ClearScreen)
END_MESSAGE_MAP()
So whenever I select the "Clear Screen" option from the menu of the app, ClearScreen() gets called but I can't get the DC of the View, it crashes.
I have looked at the variables in the debugger and the window handle seems OK so I don't know really.
I am also wondering what other way I could call a function of the View class from the App class whenever I select a menu option because this doesn't seem to work.
How did you get the CWinApp message-map pointing to a CDigitRecognizerView function? I think the "wizard" wouldn't do this. Did you add the handler manually?
As for accessing Doc/View instances from the CWinApp class, there are some functions available:
GetFirstDocTemplatePosition() / GetNextDocTemplate(), members of CWinApp class. Alternatively you can simply store the pDocTemplate instance created in the InitInstance() function. Then call:
GetFirstDocPosition() / GetNextDoc(), members of the CDocTemplate class, and finally:
GetFirstViewPosition() / GenNextView(), members of the CDocument class
But this is normally not needed (the events could be handled in the Doc/View classes), unless you want to perform some operation(s) on all (or some of the) DocTemplate/Doc/View instances (which rather implies that you are developing an MDI application).

Parent Window is NULL in CFormView (MFC)

I have a CFormView-derived class that has a button I am trying to call ShowWindow on. However, this call fails because the m_hWnd variable is null. Why is m_hWnd null? The dialog has the child style set in the properties window, and I'm associating the parent CFrameWnd with the form view. This view is intended to be modeless.
Code that creates view:
void CMainFrame::SwitchEditView(CRuntimeClass * pViewClass)
{
context.m_pNewViewClass=pViewClass;
context.m_pCurrentDoc=pDoc;
context.m_pNewDocTemplate=NULL;
context.m_pLastView=NULL;
context.m_pCurrentFrame=this;
m_subSplitter.CreateView(0,1,pViewClass,CSize(0,0), &context); // create new view and add it to the splitter window
}
The constructor for my CFormView-derived class:
CDFAManEditViewProject::CDFAManEditViewProject()
: CFormView(CDFAManEditViewProject::IDD)
{
// c_btnEdit is a CButton MFC control
c_btnEdit.ShowWindow(SW_SHOW); // this call fails on ASSERT(::IsWindow(m_hWnd) )
}
You are trying to access an edit control from the view constructor. But the view window has not been created yet when the constructor runs. That is why you have no m_hWnd and no edit control yet.
Move your initialization of controls into the view's OnInitialUpdate.

CMFCButton::SetToolTip(str) not work in OnInitDialog() and

I want my CMFCButton to show tooltip when mouse over.
It doesn't work if I use SetToolTip() method in OnInitDialog
CMFCButton* bt = ((CMFCButton*)GetDlgItem(IDC_MFCBUTTON1));
bt->SetTooltip(_T("tooltip"));
BUT it does work if I put this code in message handle function like another button's click handle.
What I want is that the CMFCButton could show tooltip when the dialog is created, where should I put these code?
========================
By the way, The tooltip text I set in the Property view does not work for most time.
I just derived a class
class CMyButton : public CMFCButton
{
public:
void SetDelayFullTextTooltipSet(bool DelayFullTextTooltipSet)
{
m_bDelayFullTextTooltipSet = DelayFullTextTooltipSet;
}
};
Instead of a CMFCButton variable on the Dialog class I use the button, I now have a CMyButton.
And in the OnInitDialog, after the SetTooltip call, I do
button.SetDelayFullTextTooltipSet(FALSE);
Have you called the base class' OnInitDialog()? The main point is that the control needs to be created before you call SetToolTip() on it. Step into OnInitDialog() with the debugger and see if m_hWnd of the control has a value at the moment you call SetToolTip().