Display context menu over MFC application mainframe menubar - mfc

I have VC++ MFC app and I need to display a context menu over CMainFrame menubar. I added a handler for WM_CONTEXTMENU in CMainFrame and I am able to display my context menu over the toolbar (also the window title) but the handle does not get invoked when I right click in the menubar

Using the Spy++ utility and right clicking on the client, toolbar or caption regions of a typical application results in the following message trace information:
<02620> 005503AE P WM_RBUTTONDOWN fwKeys:MK_RBUTTON xPos:1048 yPos:7
<02621> 005503AE P WM_RBUTTONUP fwKeys:0000 xPos:1048 yPos:7
<02622> 005503AE S WM_CONTEXTMENU hwnd:005503AE xPos:1174 yPos:63
But right clicking on the menu produces no corresponding trace information in the Spy++ message window. So it looks to me like this is standard Windows behaviour.
I suspect Windows is generating the WM_CONTEXTMENU message in response to the WM_RBUTTONDOWN and WM_RBUTTONUP messages and since these are not generated when you right click on the menu, no popup context menu is displayed.
But if you really want this behaviour, what you could do is trap the WM_NCRBUTTONDOWN client mouse message and inside this message handler post your own WM_CONTEXTMENU message to the frame window.

Thanks for pointing me in the right direction. I was able to do it by handling WM_NCRBUTTONUP message and inside the handler check whether the point is on the menu bar.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CONTEXTMENU()
ON_WM_NCRBUTTONUP()
END_MESSAGE_MAP()
void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point) {
// do not display our popup menu for title bar, etc
CRect rcClient;
GetClientRect(rcClient);
ClientToScreen(rcClient);
if (rcClient.PtInRect(point))
PopupMenu(point);
else
__super::OnContextMenu(pWnd, point);
}
void CMainFrame::OnNcRButtonUp(UINT nHitTest, CPoint point) {
if (nHitTest == HTMENU)
PopupMenu(point);
CFrameWnd::OnNcRButtonUp(nHitTest, point);
}
int CMainFrame::PopupMenu(CPoint &point) {
// display popup menu
....
}

Related

focus lost after double click in tree view

We use in several place a CTreeCtrl (TreeView) and accept a double click to open dialogs related to the double clicked node.
The opened dialog looses the focus after being opened, since the tree view seems to force to be focussed at the end of the double click handling.
Our scenario:
the user double clicks onto a node
the tree view gets focused and selects an item in its tree
the tree view containing window receives the NM_DBLCLK notification for the tree view and reacts on the double click by opening a dialog or a MDI child window in our MDI environment
the opened dialog/MDI child window gets focused after being opened
the tree view gets focused again
Even if we use in (3) (the notification handler) the result field returning a non zero value to prevent the rest of the default handling, (5) happens and the tree view gets focused again, the item selected again.
I'd really appreciate any hint about a way to resolve this issue, since it is really annoying, that a just opened dialog or window looses its focus right after opening.
Thanks in advance!
This behavior won't occur if you create a modal dialog box, because parent window is immediately disabled and dialog gains focus. But with mode-less dialog, flicker may occur, and dialog loses focus.
For mode-less dialog, use PostMessage or SetTimer so that the mode-less dialog is opened after TreeView message is processed. Example:
#define WM_USER_MSG1 WM_USER + 1
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_MESSAGE(WM_USER_MSG1, create_dialog)
...
END_MESSAGE_MAP()
void CMyWnd::OnDblClick(NMHDR*, LRESULT* pResult)
{
PostMessage(WM_USER_MSG1, 0, 0);
*pResult = 0;
}
LRESULT CMyWnd::create_dialog(WPARAM, LPARAM)
{
if(!m_dlg.GetSafeHwnd())
m_dlg.Create(IDD_DIALOG_X, this);
m_dlg.ShowWindow(SW_SHOW);
return 0;
}

C++ Win32API WM_KEYDOWN and buttons

I'm having a problem receiving message in WM_KEYDOWN. WM_KEYDOWN works just fine until I click any button in my app. From that point it no longer receives my input from the keyboard. How to fix it?
If you are using Win32 controls such as CreateWindowEx(NULL, L"BUTTON", ... this is expected Each control is actually a child window and is capturing all of the window messages after it has focus.
Once the button is clicked you can capture the WM_COMMAND - BM_CLICK message to then call SetFocus(hwnd) to refocus on your window (as Giswin mentioned).
Probably your window has no focus before you click any button on your app. you can add code somewhere in your app to set focus programmatically:
yourwindow->SetFocus();
or use winapi:
::SetFocus(hWnd);
Just in case anyone is wondering, I (unsurprisingly) noticed the same behavior for handling WM_CHAR responses in my WindowProcedure callback as well. As soon as you click a button, the focus changes from the main window to the button control (which is a child window) and keyboard presses no longer have any effect.
As suggested by #NTSCCobalt, adding a simple SetFocus(main window handler) in your WM_COMMAND cases will solve the problem, e.g.
case DEL__BUTTON:{
<Button specific code>
SetFocus(hwnd);
return 0;
}

CDialog DoModal (dialog opens with keyboard focus, but not mouse focus)

I have a CDialog window (CDrafter) which contains a CRichEditCtrl control.
I overrided CDrafter::PreTranslateMessage and CDrafter::OnNotify to allow me to click on special words in the RichTextEdit with the mouse, which in turn opens another dialog (MyDialog).
*NOTE: I did this as I didn't like the limitations of the EN_LINK styling.*
So within the CDrafter::PreTranslateMessage i have:
It just determines where and which word was clicked (nothing more) (waits for OnNotify to do something with it).
So within the CDrafter::OnNotify I have:
BOOL CSTANAGMessageDrafterDlg::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
BOOL r = CDialog::OnNotify(wParam, lParam, pResult);
//if (::PreTranslateMessage found a word clicked on ) {
MyDialog dialog;
dialog.DoModal();
//}
//Awesome my dialog opened and I can start editing the form (via the keyboard) no problems.
//BUG: There is a problem as the mouse curser is still showing the
// move carpet position icon as if it is still focused on the RichTextEdit control.
// If I click the mouse anywhere (in the MyDialog, or within the parent dialog)
// the mouse icon, and focus correctly changes to MyDialog, then I can click OK or CANCEL.
return r;
}
I have tried the calling "CDialog::OnNotify(wParam, lParam, pResult)" after the MyDialog::DoModal - still see same issue.
The MyDialog::DoModal is called within the same thread as the parent dialog.
I would expect to be able to do the following:
click on word, and MyDialog opens, click on MyDialog::Cancel button and the dialog closes.
But there is a problem as this is my sequence:
click on word, and MyDialog opens, click on MyDialog::Cancel button (it doesn't work - only the mouse icon changes), click on MyDialog::Cancel button and the dialog closes
I need to (initially click) the mouse in order to get any mouse control within the newly opened dialog. i.e. the mouseover event on buttons, etc. does nothing until I (click).

Help please: No BN_CLICKED for custom radio button (MFC, VC++6)

I have derived a CButton class and created my own radion button control. Its all working nicely with the exception that I can't get the parent dialog to detect when the radio button it clicked.
The parent dialog will detect the radio button click if I call CButton::OnLButtonUp() but the problem in doing that is that the framework also draws the radio button as well. I don't want to do that as I am drawing the radio button myself.
Can somebody please tell me how to stop Windows/MFC framework from drawing the control in this case? If I don't call CButton::OnLButtonUp() then yeah, Windows/MFC won't draw the control but my parent dialog won't get a BN_CLICKED notification either.
I know I could send a custom message back to my dialog but I don't want that - I want compatability with the BN_CLICKED message.
As you will see below, I have also tried posting a message back to the owning dialog and this doesn't work either.
void CNCCheckBox::OnLButtonUp(UINT nFlags, CPoint point)
{
if( m_Owner )
m_Owner->PostMessage( BN_CLICKED, (WPARAM) IDC_RAD_1/*GetDlgCtrlID()*/, (LPARAM) this->m_hWnd );
//CButton::OnLButtonUp(nFlags,point); // Can't use this!!
}
I've solved it. I got rid of OnDrawItem() (AFX_MSG), and added DrawItem (AFX_VIRTUAL) instead. Also, in PreSubClassWindow() I modify the style to the button is treated as a BS_PUSHBUTTON and BN_CLICKED events are now being sent to my parent dialog.
So in short:
- Don't use OnPaint()
- Don't use OnDrawItem()
- Use:
//{{AFX_VIRTUAL(CNCCheckBox)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL

Dialog not close on Windows Mobile

I made a very simple MFC application that call a Dialog when I click in a button, and send a MessageBox after 5 seconds.
The problem is, when I was in the second dialog and I dismiss the MessageBox from the parent (not click OK button of MessageBox. I click in a blank part of the second dialog) I cannot close this dialog (The second dialog) when I click OK or CANCEL button.
Why?
Part of Code:
Main Dlg:
BOOL Cmult_rc_testDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
SetTimer(1, 5000, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void Cmult_rc_testDlg::OnBnClickedButton1()
{
CDlg1 a;
a.DoModal();
}
void Cmult_rc_testDlg::OnTimer(UINT_PTR nIDEvent)
{
KillTimer(nIDEvent);
MessageBox(L"oi");
CDialog::OnTimer(nIDEvent);
}
The second Dialog is default code generated by MFC wizard.
Not sure I understand your question entirely . . . it sounds like you're trying to close the parent window when the message box is still shown?
If that's the case, the parent window owns the message box, and is not allowed to acquire focus until the message box is closed. You could try using
::MessageBox(NULL, L"oi", L"MessageBox", MB_OK);
instead of MessageBox, which will create a message box that allows you to focus back on the original window still (The :: means to use the global namespace version of MessageBox, which is the Windows native call as opposed to MFC).