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);
}
Related
I am trying to add a picture control in a mfc dialog. I want to get the x,y coordinates of the pixel when I click on the picture control. I am using this code as a reference code and following this discussion to detect the click on the picture control.
A separate class has been derived for the picture control and PreTranslateMessage has been implemented.
BOOL CPictureCtrl::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if (pMsg->message == WM_LBUTTONDOWN && GetDlgItem(IDC_STATIC_BITMAP)->GetSafeHwnd() == pMsg->hwnd)
{
CPoint point(pMsg->pt);
ScreenToClient(&point);
OnLButtonDown(pMsg->wParam, point); //passes the coordinates of the clicked Point in the dialog box
}
return CStatic::PreTranslateMessage(pMsg);
}
In the main Dialog class I am calling the OnLButtonDown as follows
void CCPictureCtrlDemoDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
m_picCtrl.GetWindowRect(&rect);
ScreenToClient(&rect);
if (rect.PtInRect(point))
{
// Do something
}
CDialog::OnLButtonDown(nFlags, point);
}
PreTranslateMessage is only triggered when i hover the mouse over the picture control, it does not trigger when i click on the picture. and the OnLButtonDown of the main dialog is does not trigger when
I click on the picture control, it only triggers when I click anywhere other than the picture control.
Thanks.
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.
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
}
}
I'm writing a WTL Aero wizard and I'd like to gray out the window's Close button (its first step will require no user interaction and can not be canceled, so disabling the button is perfectly appropriate).
Putting the following code:
CMenuHandle pMenu = GetSystemMenu(FALSE);
pMenu.EnableMenuItem(SC_CLOSE, FALSE);
in OnInitDialog does not work, as the procedure is called before the window itself is displayed on the screen (the ATLASSERT(::IsMenu(m_hMenu)); assertion in EnableMenuItem is tripped at runtime).
Is there an elegant way to disable the Close button? (I'm a WTL beginner, and I'd like the solution to be as clean as possible).
This is a minimal version of the wizard's page code:
#include "stdafx.h"
class MainPage : public CAeroWizardPageImpl<MainPage> {
public:
BEGIN_MSG_MAP(MainPage)
MESSAGE_HANDLER_EX(WM_INITDIALOG, OnInitDialog)
CHAIN_MSG_MAP(__super)
END_MSG_MAP()
enum {
IDD = IDR_MAINFRAME
};
MainPage() : CAeroWizardPageImpl<MainPage>(IDR_MAINFRAME) {
/* Set the wizard's title */
m_headerTitle.LoadString(IDS_INSTALLHEADER);
SetHeaderTitle(m_headerTitle);
}
private:
CString m_headerTitle;
LRESULT OnInitDialog(UINT message, WPARAM wParam, LPARAM lParam) {
UNREFERENCED_PARAMETER(message);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
/* Disable the wizard buttons and center the window */
ShowWizardButtons(0, 0);
EnableWizardButtons(PSWIZB_BACK, 0);
CenterWindow();
return TRUE;
}
};
The close [X] button is a part of Common Controls wizard property sheet class. You are not supposed to alter its presentation and behavior. What you can do is to handle PSN_QUERYCANCEL notification and prevent wizard from closing. With WTL it is easy, however you need to know that that there are two versions of notifications handlers available.
If _WTL_NEW_PAGE_NOTIFY_HANDLERS is defined, typically in stdafx.h, then you do it like this:
class MainPage :
public CAeroWizardPageImpl<MainPage>
{
// ...
INT OnQueryCancel()
{
return 1; // Zero to Allow Wizard Close
}
};
Otherwise, older syntax is in use:
class MainPage :
public CAeroWizardPageImpl<MainPage>
{
// ...
BOOL OnQueryCancel()
{
return FALSE; // Allow Wizard Close?
}
};
Along with preventing cancellation/close you are free to indicate this by showing a message box suggesting use to wait until the pending operation is completed, or otherwise display a notification (e.g. flash a static control etc.)
I'm building a project with MFC Feature Pack. Is this project I have a window which includes a CView, which includes a CListCtrl-derived object. The object includes the LVS_EDITLABELS flag.
Somehow I cannot edit the CListCtrl icon labels by two-time clicking (not double-clicking) on the icon label. After I select the item with a single click, a second click just flashes the item (button down turns text background to white, button up turns it back to blue) and the edit control never appears.
I reduced this problem to the simplest form, and even with a plain CListCtrl object I cannot edit the labels.
I also found that:
This problem occurs in VS2008. It doesn't occur in a similar project built in VS2003.
I am able to edit the labels if I build a CListView instead of a CView+CListCtrl.
I am also able to edit the labels if I build a CFormView and put the CListCtrl inside the resource dialog.
Here's some code in the simplest form: the .h file:
// vwTerminaisTeste.h
//
#pragma once
// vwTerminaisTeste view
class vwTerminaisTeste : public CView
{
DECLARE_DYNCREATE(vwTerminaisTeste)
protected:
vwTerminaisTeste(); // protected constructor used by dynamic creation
virtual ~vwTerminaisTeste();
CListCtrl m_lstTerminais;
protected:
DECLARE_MESSAGE_MAP()
virtual void OnDraw(CDC* /*pDC*/);
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
};
and the .cpp file:
// vwTerminaisTeste.cpp : implementation file
//
#include "stdafx.h"
#include "vwTerminaisTeste.h"
// vwTerminaisTeste
IMPLEMENT_DYNCREATE(vwTerminaisTeste, CView)
vwTerminaisTeste::vwTerminaisTeste()
{
}
vwTerminaisTeste::~vwTerminaisTeste()
{
}
BEGIN_MESSAGE_MAP(vwTerminaisTeste, CView)
ON_WM_CREATE()
ON_WM_SIZE()
END_MESSAGE_MAP()
// vwTerminaisTeste message handlers
void vwTerminaisTeste::OnDraw(CDC* /*pDC*/)
{
CDocument* pDoc = GetDocument();
}
int vwTerminaisTeste::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
m_lstTerminais.Create(WS_CHILD | WS_VISIBLE | LVS_EDITLABELS, CRect(0,0,1,1), this, 0);
m_lstTerminais.InsertItem(0, "Teste", 0);
return 0;
}
void vwTerminaisTeste::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if (IsWindow(m_lstTerminais.GetSafeHwnd()))
m_lstTerminais.MoveWindow(0, 0, cx, cy);
}
This way I cannot edit labels.
To change it to a CListView I simply replaced CView by CListView and m_lstTerminais by GetListCtrl(), and removed the OnCreate and OnSize implementations. That way it worked.
Note: the vwTerminaisTeste is created from a CSplitterWndEx within a CMDIChildWndEx-derived class.
Well nobody solved this problem but I managed to go around it by changing the CView to a CFormView and building a resource dialog with a ListView control, attaching it to the CListCtrl-derived class.
If anyone still has any suggestions on how could I solve this problem entirely, I'd appreciate them.
This sounds like it may be a focus or command routing issue, although that doesn't explain why it works OK in VS2003. You might try routing the command and/or focus messages from the splitter ctrl to vwTerminaisTeste, and/or from the MDIChild to the splitter. If you haven't already, you may need to derive your own splitter window. The command/focus forwarding would be something like...
BEGIN_MESSAGE_MAP(MySplitter, CSplitterWnd)
ON_WM_SETFOCUS()
END_MESSAGE_MAP(...)
void MySplitter::OnSetFocus(CWnd* pOldWnd)
{
// forward focus to the view window
m_vwTerminaisTeste.SetFocus();
}
BOOL MySplitter::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// let the view have first crack at the command
if (m_vwTerminaisTeste.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise, do default handling
return MySplitter::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}