my environment is C++, MFC, compact-framework for WM 6.0+ devices.
In many places, I am showing pop-up messages using 'MessageBox()' to give a simple warning or get Yes/No repsonse from user. What I want to do is that whenever any message is closed, call some common function before I perform specific codes.
I tried WM_SHOWWINDOW in parent window but it doesn't seem to occur.
Any suggestion will be appreciated.
[Added] my screen has many buttons and I have to make sure only one button is focused all the time. When I show message box, button seems to loose its focus so I want to focus it back when message is closed. Of course, I can do it in every place where message is used but looking for a better way to handle this situation.
The MessageBox function returns specific return codes when it is closed, you can wrap the MessageBox function and check the return values and run some code based on that.
Here are the return codes from MSDN :
IDABORT 3 The Abort button was selected.
IDCANCEL 2 The Cancel button was selected.
IDCONTINUE 11 The Continue button was selected.
IDIGNORE 5 The Ignore button was selected.
IDNO 7 The No button was selected.
IDOK 1 The OK button was selected.
IDRETRY 4 The Retry button was selected.
IDTRYAGAIN 10 The Try Again button was selected.
IDYES 6 The Yes button was selected.
So the following code can be used to run different functions based on the return code.
void MyMessageBox(wstring title,wstring message)
{
int msgboxID = MessageBox(
NULL,
(LPCWSTR)message.c_str(),
(LPCWSTR)title.c_str(),
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2
);
switch (msgboxID)
{
case IDCANCEL:
// TODO: add code
break;
case IDTRYAGAIN:
// TODO: add code
break;
case IDCONTINUE:
// TODO: add code
break;
//so on
}
}
More info here :
http://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx
You might try intercepting the WM_ACTIVATE message in the parent window.
Related
I was hoping someone out there would help me with my predicament I ran into. Essentially I have a Checkbox and a RichEditControl next to each other. I want to be able to know when a user has clicked on my RichEditControl so i can send a message to my checkbox to flag it on and off.
At first i tried to overlay my checkbox with empty text to act as a "blank" background for my RichEditControl so i wouldn't have to worry about sending messages left and right. No matter what i tried the "blank" background would overlap the RichEditControl text and leave it completely blank.
I searched on here for some help and i found this which is exactly what I ran into. I understand what he is saying but don't have the knowledge to implement what they said.
Right now I'm playing around with EN_LINK to attempt to capture a message so i can tell my checkbox to flag itself.
BEGIN_MESSAGE_MAP(TempInit, CDialog)
ON_NOTIFY(EN_LINK, IDC_TempInitMsg, &TempInit::OnEnLinkTempinitmsg)
END_MESSAGE_MAP()
void TempInit::OnEnLinkTempinitmsg(NMHDR *pNMHDR, LRESULT *pResult)
{
ENLINK *pEnLink = reinterpret_cast<ENLINK *>(pNMHDR);
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
radioClicked = !radioClicked;
if (radioClicked == true)
{
GetParent()->SendMessage(WM_MYRADIOCLICKED, CHECKENABLED, 0);
}
else
{
GetParent()->SendMessage(WM_MYRADIOCLICKED, CHECKDISABLED, 0);
}
}
*pResult = 0;
}
I'm sorry in advance if this is totally the wrong way to go about this. I've been googling for a few hours and have come empty handed. If anyone has any other method please help me if possible. I can post more code if what i have above isn't enough.
Steven,
One way to go about this would be to handle the EN_MSGFILTER notification from the rich edit control. I can't provide you any code to show you how to do this off hand but here's the documentation for the Notification messages from that the Rich edit control generates. Simply handle it the same way your doing with your radio button.
This will check the check box when the Rich Edit Ctrl has the focus and untick
it when it losses the focus.
BEGIN_MESSAGE_MAP(TempInit, CDialogEx)
ON_EN_SETFOCUS(IDC_RICHEDIT21, &TempInit::OnEnSetfocusRichedit21)
ON_EN_KILLFOCUS(IDC_RICHEDIT21, &TempInit::OnEnKillfocusRichedit21)
END_MESSAGE_MAP()
void CMFCApplication1Dlg::OnEnSetfocusRichedit21()
{
CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK1);
pCheckBox->SetCheck(1);
}
void CMFCApplication1Dlg::OnEnKillfocusRichedit21()
{
CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK1);
pCheckBox->SetCheck(0);
}
My project is simple WIN32 dialog box with a tab control.
Under some condition, I want to prevent the user from changing tab. MS documentation is quite straightforward -
Returns TRUE to prevent the selection from changing, or FALSE to allow the selection to change.
However, this just does not work!
The code:
case WM_NOTIFY:
if (((LPNMHDR)lParam)->idFrom == IDC_DEVTABS)
{
if (((LPNMHDR)lParam)->code == TCN_SELCHANGING)
return (INT_PTR)TRUE;
//return (INT_PTR)OnSelChanging(hDlgTab);
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
OnSelChanged(hDlgTab);
return (INT_PTR)TRUE;
}
I can see that my parent dialog box receives the message, but the tab is changing anyhow. Any idea how I can prevent the tab from changing?
If your control is in a dialog, as I assume it is, you need to return the value through the DWLP_MSGRESULT window data.
SetWindowLongPtr(hWndDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
The return value from the dialog procedure indicates to the dialog manager whether or not the message was handled. The actual return value for the message is provided via DWLP_MSGRESULT.
As always, see Raymond's blog for a good discussion of this.
I have a Modeless dialog which shows a bunch of buttons; some of these are customized to draw stuff with GDI.
Now, when the user clicks on a customized one under certain conditions, a message box appears to alert user of the error and this is fine.
The problem is that after accepting the Message Box (showed as MB_ICON_ERROR), everywhere I click in the dialog, I always get the error message as if the whole dialog send the message to the customized button and the only way to get rid this is to press tab and give the focus to another control.
This is a strange behaviour and knowing why happens wouldn't be bad, but a simple workaround for now should do the job.
Since the moment that is probably a matter of focus, I've tried to set it on another control (in the owner dialog) by doing:GetDlgItem( IDC_BTN_ANOTHER_BUTTON )->SetFocus();
and then, inside the customized control by adding:KillFocus( NULL );but had no results.
How should I use these functions?
Thanks in advance.
PS: if I comment the AfxMessageBox, the control does not show this bizarre behaviour.
EDITI'll show some code as requested.
// This is where Message Box is popping out. It is effectively inside the dialog code.
void CProfiloSuolaDlg::ProcessLBtnDownGraphProfilo(PNT_2D &p2dPunto)
{
// m_lboxProfiles is a customized CListBox
if(m_lboxProfiles.GetCurSel() == 0)
{
// This profile cannot be modified.
/*
CString strMessage;
strMessage.Format( _T("Default Profile cannot be edited.") );
AfxMessageBox( strMessaggio, MB_ICONERROR );
*/
return;
}
// Selecting a node from sole perimeter.
SelectNodo(p2dPoint);
}
Actually, the message is commented to keep the dialog working.
// This is inside the customization of CButton
void CMyGraphicButton::OnLButtonDown(UINT nFlags, CPoint point)
{
PNT_2D p2dPunto;
CProfiloSuolaDlg* pDlg = (CProfiloSuolaDlg*)GetParent();
m_pVD->MapToViewport(point,p2dPunto);
switch(m_uType)
{
case GRF_SEZIONE:
pDlg->ProcessLBtnDownGraphProfilo(p2dPunto);
break;
case GRF_PERIMETRO:
pDlg->ProcessLBtnDownGraphPerimetro(p2dPunto);
break;
}
CButton::OnLButtonDown(nFlags, point);
}
Since you are handling the button down event in the button handler for the custom control, you don't need to call the base class. Just comment out CButton::OnLButtonDown(nFlags, point).
I'm coding in C++/MFC on a Windows platform (using MS VS2008.) I have this Edit control (which is basically a text box) that is set to be read-only. The control displays some basic information. I want to add an "Easter Egg" to my app, i.e. when a user Ctrl+Shift clicks on this edit control it must display some additional info. The question is how to trap such a click event using MFC/native WinAPIs?
The most straight forward way is to subclass the edit control using SetWindowLong and catch WM_LBUTTONDOWN event. You'd then want to call GetAsyncKeyState or equivalent to check whether the specific key is being pressed or not, and show the message.
There is no need to do subclassing. Just catch WM_PARENTNOTIFY
case WM_PARENTNOTIFY: {
if (LOWORD(wParam) == WM_LBUTTONDOWN)
printf("x: %i, y: %i\n", LOWORD(lParam), HIWORD(lParam));
}
break;
By default, child windows in a dialog box have the WS_EX_NOPARENTNOTIFY style and so doesn't notify the parent window. You should remove this style.
case WM_INITDIALOG: {
HWND hChildWnd = GetDlgItem(hWnd, IDC_CHILD);
LONG style = GetWindowLong(hChildWnd, GWL_EXSTYLE);
style &= ~WS_EX_NOPARENTNOTIFY;
SetWindowLong(hChildWnd, GWL_EXSTYLE, style);
...
P.S. I hope it's not too late :D
Language: C++
Development Environment: Microsoft Visual C++
Libraries Used: MFC
Pretty new to MFC, so bear with me. I have a dialog that is launched via DoModal(). I'm attempting to add buttons to this dialog that will replace the default "OK" and "Cancel" buttons. Right now, I can't quite figure out how to do this. I deleted the OK and Cancel buttons and added new ones with new IDs, added event handlers, and just some simple code for them to execute upon being pressed, but I couldn't get it to work.
I suspect it has something to do with the fact that DoModal() expects responses from OK or Cancel, but nothing else. I'm not really sure though. Any help would be greatly appreciated!
EDIT: Stripped down code added for reference.
void CPrefsDlg::Launch() {
[ ... ]
CSAPrefsDialog dlg;
INT_PTR nRet = -1;
nRet = dlg.DoModal();
// Handle the return value from DoModal
switch ( nRet )
{
case -1:
AfxMessageBox("Dialog box could not be created!");
break;
case IDABORT:
// Do something
break;
case IDOK: // This works just fine.
exit(0);
break;
case IDSAVEONE: // This does not work.
MessageBox("Save One");
break;
default:
break;
};
}
void CPrefsDlg::SaveOne()
{
// I tried adding in my own handler for 'Save One'...this does not work.
MessageBox("Save one");
}
To wire up your dialog to terminate and return IDSAVEONE, you need to add a click handler to the Save One button and have it call EndDialog:
void CSAPrefsDialog::OnBnClickedSaveone()
{
EndDialog(IDSAVEONE);
}
If you add the click handler through the dialog editor (e.g. by double-clicking on your button) then the necessary framework code will be generated for you to wire this up; otherwise you'll need to add the following line into your BEGIN_MESSAGE_MAP section in your dialog class:
ON_BN_CLICKED(IDSAVEONE, &CSAPrefsDialog::OnBnClickedSaveone)
but (as AJG85's just beaten me to posting) depending on what the operation is, how fast it is and whether you want to report errors in the preferences dialog or not, you may want to just carry out the extra function in your on-clicked handler instead.
MFC has built in ids for the ok and cancel buttons. Those being IDOK and IDCANCEL. You can either handle these in a switch via the return of DoModal() or probably better would be to override OnOK() and OnCancel() methods in your dialog class to do what you want.
You can do this by adding a line to the message map to call your handler:
Edit: The same thing works for buttons you add to the dialog which I added to my example code below:
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
ON_BN_CLICKED(IDOK, &OnBnClickedOk)
ON_BN_CLICKED(IDSAVEONE, &OnBnClickedSave)
END_MESSAGE_MAP()
void MyDialog::OnBnClickedOk()
{
// do extra stuff when they click OK
CDialog::OnOK(); // call base class version to complete normal behavior
}
void MyDialog::OnBnClickedSave()
{
// this would be called for your save button with custom id IDSAVEONE
// note: no base class call here as it's specific to your dialog
}