Drag CMDIChildWnd using client area - mfc

I'm trying to create a CMDIChildWnd without title bar draggable using the mouse on the client area.
into the message map I've added
ON_WM_LBUTTONDOWN()
and
void CChildFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
SendMessage(WM_SYSCOMMAND, SC_MOVE | 0x0002);
}
the result is a child windows that moves using the mouse as required but only inside its area.
Any idea on how I can proceed?

I did it using a little trick. The class to implement the behaviour is the derived class of the CFormView and I'm able to move the window as expected sending the htcaption message to the parent
void derived_CFormView::OnLButtonDown(UINT nFlags, CPoint point)
{
CFormView::OnLButtonDown(nFlags, point);
GetParentFrame()->PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));
}
void derived_CFormView::OnLButtonUp(UINT nFlags, CPoint point)
{
CFormView::OnLButtonUp(nFlags, point);
GetParentFrame()->PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));
}

Related

MFC ribbon home button closes app with double click

I've faced with strange behaviour of a home ribbon button.
I've created standard MFC application in Visual Studio 2010 with Office template that has a ribbon control. But if I double click on the Home ribbon button at the upper position the application is closed.
Could you please tell me if it is standard MFC application handlers behaviour and how I can change it?
I've looked at Prevent double click on MFC-Dialog button but couldn't apply it to my case (more clearly - I don't know how to add double click handler to a ribbon home button).
CMFCRibbonApplicationButton is not derived from CWnd so cannot handle WM_LBUTTONDBLCLK message.
One solution is to derive from CMFCRibbonBar.
class CCustomRibbonBar : public CMFCRibbonBar
{
// ...
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
};
BEGIN_MESSAGE_MAP(CCustomRibbonBar, CMFCRibbonBar)
ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()
void CCustomRibbonBar::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CMFCRibbonBaseElement* pHit = HitTest(point);
if (pHit->IsKindOf(RUNTIME_CLASS(CMFCRibbonApplicationButton)))
{
// the user double-clicked in the application button
// do what you want here but do not call CMFCRibbonBar::OnLButtonDblClk
return;
}
CMFCRibbonBar::OnLButtonDblClk(nFlags, point);
}
Another solution: override PreTranslateMessage in CMainFrame class;
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if ((WM_LBUTTONDBLCLK == pMsg->message) && (pMsg->hwnd == m_wndRibbonBar))
{
CPoint point(pMsg->pt);
m_wndRibbonBar.ScreenToClient(&point);
CMFCRibbonBaseElement* pHit = m_wndRibbonBar.HitTest(point);
if (pHit && pHit->IsKindOf(RUNTIME_CLASS(CMFCRibbonApplicationButton)))
{
// do what you want but do not call CMDIFrameWndEx::PreTranslateMessage
return TRUE; // no further dispatch
}
}
return CMDIFrameWndEx::PreTranslateMessage(pMsg);
}
Derive your own derived class of CMFCRibbonApplicationButton.
Create a message handler for CMFCRibbonApplicationButton::OnLButtonDblClk
Provide your own implementation of what you want to do on the double click. If nothing should happen, just leave the body empty.
In your CMainFrame you find a definition of CMFCRibbonApplicationButton m_MainButton. Replace the class name with your implementation.

MFC click and move/drag dialog window

I am currently working on finishing some code handed off to me. It was written in MFC in Visual Studio 2005 years ago, was put on hold, and now is brought to me.
While I know C++, I have spent the last ~2 months studying the code and learning MFC and it's starting to come together.
The GUI for the code is an SWF flash file embedded in an invisible dialog window. I do not have the source code for the SWF file so will probably, in the future, redo it in WPF or something. I have the WMMode set to "Window" because in Transparent/Opaque mode it doesn't display properly, where it flashes/blinks everytime a mouse event is captured.
Anyhow, in Win XP/Vista, clicking and dragging the flash control works. In windows 7/8.1, it won't move.
Happy to provide any and all info needed. I'm still a little overwhelmed by MFC dialogs so unsure what you'd all like to see.
I found this question: Moving window by click-drag on a control
Which looks like it solves a lot of the issue. However, I don't want the whole control to be clickable like this, only the top part. Unfortunately, in the MS Resource view, the ActiveX control is blank as the SWF is only loaded at runtime; I've tried to find resources for this kind of thing but it's very difficult as I am unsure of the technical terms to use.
EDIT
I have attempted this by creating a very simple MFC app that has a Static Text control and nothing else. I am trying to get it to work by clicking on the static text (though I may be painting myself into a corner as it does not have a built-in lButtonDown event).
Here is the relevant code:
class MyDialog : public CDialog
{
public:
MyDialog(CWnd* pParent = NULL) : CDialog(MyDialog::IDD, pParent)
{ }
// Dialog Data, name of dialog form
enum{ IDD = INTERFACE1 };
protected:
virtual void DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); }
//Called right after constructor. Initialize things here.
virtual BOOL OnInitDialog()
{
CDialog::OnInitDialog();
pText = (CStatic *)GetDlgItem(ID_TEXT);
pText->SetWindowTextW(_T("Hello World!"));
return true;
}
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
private:
CStatic * pText;
public:
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
Overridden Method:
afx_msg void MyDialog::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd::OnNcLButtonDown(HTCAPTION, point);
}
I have also tried setting nFlags to 0x2, calling OnLButtonDown (as opposed to onNcLButtonDown), various other things. The message fires but the window does not move (it does move from the title bar, as normal). What am I missing?
Actually lets try this code instead with ON_WM_NCHITTEST(). This will drag the dialog if you click the mouse anywhere in client area (client area acts as caption). There is a line rc.bottom = rc.top + 100 if you uncomment it then it will only drag if you click the top section (I picked the number 100 at random).
//declare:
afx_msg LRESULT OnNcHitTest(CPoint point);
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
ON_WM_NCHITTEST()
END_MESSAGE_MAP()
LRESULT MyDialog::OnNcHitTest(CPoint point)
{
ScreenToClient(&point);
CRect rc;
GetClientRect(&rc);
//rc.bottom = rc.top + 100;
if (rc.PtInRect(point))
return HTCAPTION;
return CDialog::OnNcHitTest(point);
}
Second option:
If we want to move the dialog by clicking on a child control, and if that control captures the mouse, then try this method instead. ***Note, test to make sure the control works properly after it is moved.
BOOL MyDialog::PreTranslateMessage(MSG *msg)
{
if (msg->message == WM_MOUSEMOVE && (msg->wParam & MK_LBUTTON))
{
CPoint p;
GetCursorPos(&p);
CRect r;
ActiveX->GetWindowRect(&r);
if (r.PtInRect(p))
{
ReleaseCapture();
SendMessage(WM_NCLBUTTONDOWN, HTCAPTION, 0);
SendMessage(WM_NCLBUTTONUP, HTCAPTION, 0);
return 1;
}
}
return CDialogEx::PreTranslateMessage(msg);
}

MFC Statusbar - Making text a link with button behavior

Im trying to use a status bar in an MFC application as described here
I managed to add items to my status bar as described in the link.
There's nothing that I could post here as code reference as its currently 1:1 as in the link.
What I want is to make the text a link, so that when clicked, I'll catch this callback and do something.
I couldn't find how to do it, yet I've seen it in apps before.
I use something similar, but you need to derive your own class from CStatusBar.
a) place the following code at the top of your derived StatusBar.cpp
BEGIN_MESSAGE_MAP(CMyStatusBar, CStatusBar)
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
b) add the following declaration for CMyStatusBar in your derived StatusBar.h
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
c) place the following code later on in your derived StatusBar.cpp
void CMyStatusBar::OnLButtonUp(UINT nFlags, CPoint point)
{ CRect rc;
int nPaneIndex = CommandToIndex(ID_INDICATOR_TIME);
GetStatusBarCtrl().GetRect(nPaneIndex, &rc);
if (rc.PtInRect(point))
{ // do something
}
}

CRichEditCtrl::SetRedraw() in OnMouseMove handler causes infinite loop

Oversimplifying, I have the next WM_MOUSEMOVE message handler in my CRichEditCtrlEx class, which is derived from the CRichEditCtrl:
void CRichEditCtrlEx::OnMouseMove(UINT nFlags, CPoint Point)
{
SetRedraw(FALSE);
// some actions, which should not cause rich edit redrawing
SetRedraw(TRUE);
}
The problem is that SetRedraw(TRUE), preceded by the SetRedraw(FALSE), somehow places a new WM_MOUSEMOVE message in the message queue, so OnMouseMove handler will be called infinitely, even if the mouse doesn't move.
Trying to locate the trouble, I've experimented with the following simple handlers:
void CRichEditCtrlEx::OnMouseMove(UINT nFlags, CPoint Point)
{
RedrawWindow();
}
or
void CRichEditCtrlEx::OnMouseMove(UINT nFlags, CPoint Point)
{
Invalidate();
},
but they don't cause infinite loops.
I've also tried to validate the client area, but it didn't help:
void CRichEditCtrlEx::OnMouseMove(UINT nFlags, CPoint Point)
{
SetRedraw(FALSE);
// some actions, which should not cause rich edit redrawing
CRect rc;
GetClientRect(&rc);
ValidateRect(&rc);
SetRedraw(TRUE);
}
What is wrong with the SetRedraw()?
Any idea would be appreciated.
UPD: I see that WM_MOUSEMOVE message may be caused not only by a mouse movement, but sometimes also by a window drawing. An infinite loop can be avoided by storing the last mouse position and checking whether the mouse was really moved, but it seems for me like a workaround.

How to disable the default behaviour of a MFC link control?

I am using a MFC link control in my dialog based application,and I add an event handler of BN_CLICKED for it, hoping that it could do something for me, however, when i click on it, it just does nothing at all(when i don't set the url of it, when i set the url, it will jump to that url), my event handler is not triggered. So, how to disable its default "jump" behaviour and trigger my handler?
Subclassing CMFCLinkCtrl and adding an ON_WM_LBUTTONDOWN event handler seems to work.
You can then choose whether or not to call CMFCLinkCtrl::OnLButtonDown.
class CMyLinkCtrl : public CMFCLinkCtrl {
DECLARE_DYNAMIC(CMyLinkCtrl)
public:
CMyLinkCtrl();
virtual ~CMyLinkCtrl();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
protected:
DECLARE_MESSAGE_MAP()
};
IMPLEMENT_DYNAMIC(CMyLinkCtrl, CMFCLinkCtrl)
CMyLinkCtrl::CMyLinkCtrl() {
}
CMyLinkCtrl::~CMyLinkCtrl() {
}
BEGIN_MESSAGE_MAP(CMyLinkCtrl, CMFCLinkCtrl)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
void CMyLinkCtrl::OnLButtonDown(UINT nFlags, CPoint point) {
static bool bDisabled = false;
if(bDisabled) {
MessageBox(_T("Link is disabled"));
} else {
CMFCLinkCtrl::OnLButtonDown(nFlags, point);
}
bDisabled = !bDisabled;
}