I couldn't find anywhere in MSDN an example of handling ON_LBN_SELCHANGE. So, how does the afx_msg function look like, and what parameters does ON_LBN_SELCHANGE need in the message map?
The notification handler for LBN_SELCHANGE has no parameters.
All listbox notification handlers have a common syntax (link)
Each message-map entry takes the following form:
ON_Notification( id, memberFxn )
where id specifies the child window ID of the list-box control sending the notification
and memberFxn is the name of the parent
member function you have written to handle the notification.
The parent's function prototype is as follows:
afx_msg void memberFxn( );
Related
According to this article, to allow Drop Only on the Target, we have to
Use SubclassDlgItem() to re-route that one message to the dialog object so that all of the handling can be done there.
Mr. DanRollins (the author of the article) also provides an example
class CEditDropNotif : public CEdit
{
virtual BOOL PreTranslateMessage(MSG* pMsg) {
if ( pMsg->message == WM_DROPFILES ) {
GetParent()->SendMessage(WM_DROPFILES, pMsg->wParam, pMsg->lParam);
return TRUE; // eat it
}
return FALSE; // allow default processing
}
};
BOOL CMyDlg::OnInitDialog()
{
...
static CEditDropNotif cEd; // must persist (usually a dlg member)
cEd.SubclassDlgItem( IDC_EDIT1, this );
::DragAcceptFiles( cEd.m_hWnd, true ); // the editbox, not the dialog
...
But I don't understand why Edit control (CEdit) has the Accept Files in the properties window (Visual Studio Resource view), but can't register the message WM_DROPFILES for itself without having to create an inherited class (or it can but I haven't known yet).
I see that we can register the click message for button by the following code
BEGIN_MESSAGE_MAP(CSimpleDlg, CDialogEx)
...
ON_BN_CLICKED(IDC_BTN_01, &CSimpleDlg::OnBnClickedBtn01)
END_MESSAGE_MAP()
Is there a way I can do similar for drag drop event, like
ON_DRAW_DROP(IDC_TXT_01, &CSimpleDlg::OnDragDrop01)//Is exist?
The answer is: Nope.
ON_BN_CLICKED macro maps a member function that handles BN_CLICKED notification sent via WM_COMMAND message. The notifications are sent to control's parent (although MFC has also a "reflection" mechanism that forwards the notifications to controls).
WM_DROPFILES is a general Windows message, not a notification so that's it: if you want to handle it then you have to derive from CEdit.
See also:
Message Categories
Message Reflection for Windows Controls
Is there anybody could tech me how to use the interface "AddButton" of the MFC control? "CVSListBox"? I wrote the below code, and the new buttons have showed on the control successful, but I can't respond its ON_BN_CLICKED event. Could you tell me why? thanks.
ON_BN_CLICKED(IDC_BTN_AWSPORTIMPORT, &CPgTestAwsPortfolio::OnBnClickedBtnAwsportimport)
void CPgTestAwsPortfolio::OnBnClickedBtnAwsportimport()
{
int xx = 100;
}
CPortCaseListBox m_lbAwsPortCases;
m_pgTestAwsPort.m_lbAwsPortCases.AddButton(IDB_AFXBARRES_NEW, _T("Import"), 0, 0, IDC_BTN_AWSPORTIMPORT);
The idea is different here.
All Buttons are handled internally in the CVSListBox class.
See CVSListBoxBaseBase::OnCommand override.
When a button sends a WM_COMMAND it is intercepted by CVSListBoxBaseBase::OnCommand
When the id is member of the internal button list of the ist Control the virtual function OnClickButton is executed.
GetButtonID might help you to convert the Position into the ID.
Note OnClickButton receives the number of the button, not the id.
So the parent never receives any notification of this Buttons. It is all handled in the virtual functions of CVSListBox.
The documentation is incomplete because the Base class isn't described and document.
I've got some control like CtrlTree on CMyDialog.
I want to handle messages like ON_WM_LBUTTONDOWN() from CTreeCtrl in the CMyDialog class.
Is there any way in MFC to redirect message stream to parent?
The simplest way to redirect your messages is just sending a custom (WM_USER + xxx) message from your control's ON_WM_LBUTTONDOWN handler to the parent class.
Place parent's WM_LBUTTONDOWN handler code in a separate method and call this method directly.
Something like that (pseudo code), presuming that your existing code sits in HandleTreeCtrlLBDown()
CMyTreeCtrl::OnLButtonDown(..)
{
pParent ->SendMessage(WM_TREECTRLLBDOWN, 0, (LPARAM)this);
}
CControlParentDialog::OnTreeCtrlLBDown(wParam, lParam)
{
HandleTreeCtrlLBDown();
}
I'm coding an MFC application in which i have a dialog box with multiple CListCtrls in report view. I want one of them to be sortable.
So i handled the HDM_ITEMCLICK event, and everything works just fine .. Except that if i click on the headers of another CListCtrl, it does sort the OTHER CListCtrl, which does look kind of dumb.
This is apparently due to the fact that headers have an ID of 0, which make the entry in the message map look like this :
ON_NOTIFY(HDN_ITEMCLICK, 0, &Ccreationprogramme::OnHdnItemclickList5)
But since all the headers have an id of zero, apparently every header of my dialog sends the message.
Is there an easy way around this problem ?
EDIT: Maybe i wasn't clear, but i did check the values inside the NMHDR structure. The HwndFrom pointer is different depending on which header is clicked, which doesn't help me a lot since it's value is obviously different at each runtime. The idFrom value is 0, for the very reasons i explained above, because that's the id of every header. Thanks
EDIT2: The hwnd pointer values do also not correspond to the CListCtrl, probably because it's coming from a different object entirely.
Check the values of the NMHDR structure.
http://msdn.microsoft.com/en-us/library/bb775514%28VS.85%29.aspx
Ok i found a solution, though i find it a bit dirty but it works, so i'll post it for future reference.
You can get the Header through the GetHeaderCtrl member function of CListCtrl. You can then get it's handler thru m_hWnd. So all you got to do is to test if that handler is the same as the one in the NMHDR structure, so the code looks like this :
void Ccreationprogramme::OnHdnItemclickList5(NMHDR *pNMHDR, LRESULT *pResult)
{
if (pNMHDR->hwndFrom == LC_gen_schedules.GetHeaderCtrl()->mhWnd)
{
// Code goes here
}
*pResult = 0;
}
Thanks all for the help
The LPARAM passed to your message handler is actually a pointer to an NMHEADER structure, which contains an NMHDR structure, which in turn contains the HWND and control ID of the control which sent the message. You may be able to compare that to your list controls' HWNDs to determine which window's header control was clicked.
Alternatively, you could derive a class from CListCtrl and reflect the HDN_ITEMCLICK messages back to the list control. That way, each list control object handles its own header's notifications.
I was just wondering what (if any) the difference was between the following two message traps in MFC for the function, OnSize(..).
1 - Via Message map:
BEGIN_MESSAGE_MAP(CClassWnd, CBaseClassWnd)
...
ON_WM_SIZE()
..
END_MESSAGE_MAP()
2 - Via afx_message:
afx_msg type OnSize(...);
They seem to be used interchangeably, which one should be used or does it depend on other factors?
Both parts are necessary to add a message handler to a class. The message map should be declared inside your class, together with declarations for any message handler functions (e.g, OnSize).
class CClassWnd : public CBaseClassWnd {
...
afx_msg void OnSize(UINT nType, int cx, int cy);
DECLARE_MESSAGE_MAP
};
afx_msg is just an empty placeholder macro - it doesn't actually do anything, but is always included by convention.
The message map is then defined in the class's .cpp file:
BEGIN_MESSAGE_MAP(CClassWnd, CBaseClassWnd)
ON_WM_SIZE()
END_MESSAGE_MAP()
These macros generate a lookup table for the class which allows messages received by the window to be dispatched to the corresponding handler functions. The ON_WM_SIZE macro allows the wParam and lParam message parameters in the WM_SIZE message to be decoded into more meaningful values for the message handler function (nType, cx, and cy in this case). MFC provides macros for most window messages (WM_LBUTTONDOWN, WM_DESTROY, etc).
You can find more information on how message maps work in MFC here on MSDN.
afx_msg is just an empty macro, it's basically just there to denote that the method is an MFC message handler for readability purposes. Even with afx_msg there you still need to have an entry in the message map.
Some of the Windows message are already handled by MFC, so in these cases you can get away with adding just the method to your derived class.
For example the CWnd class (as do many other MFC classes) already maps a few Windows messages into it's message map (i.e. ON_WM_DRAWITEM, ON_WM_MEASUREITEM, ON_WM_ENTERIDLE etc, etc).
But any other message not already mapped by MFC will need to have both a class method and an entry in the message map for it to work.