How to capture windows message from the up/down button of a CDateTimeCtrl control? - visual-c++

I am using a CDateTimeCtrl, along with a callback field, in my dialog application. All works well as intended but I want to capture the windows message when the up-down button ( looks a lot like the spin control) of the CDateTimeCtrl is clicked without success. Spy++ reported the class of the up-down button to be msctls_updown32. Spy++ message log offer no clue either. How do I capture the mouse click messages from this up-down control ( looks like an OLE control to me)?
Edited: : I've tried handling the UDN_DELTAPOS message like so but still unable to capture the message from CMyTimeCtrl.
class CMyTimeCtrl : public CDateTimeCtrl
{
DECLARE_DYNAMIC(CMyTimeCtrl)
public:
CMyTimeCtrl();
virtual ~CMyTimeCtrl();
protected:
int m_msec;
DECLARE_MESSAGE_MAP()
public:
virtual void DoDataExchange(CDataExchange* pDX);
afx_msg void OnDtnFormat(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDtnFormatquery(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDtnWmkeydown(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDeltaposSpin(NMHDR* pNMHDR, LRESULT* pResult);
};
BEGIN_MESSAGE_MAP(CMyTimeCtrl, CDateTimeCtrl)
ON_NOTIFY(WM_NOTIFY, UDN_DELTAPOS, &CMyTimeCtrl::OnDeltaposSpin)
ON_NOTIFY_REFLECT(DTN_FORMAT, &CMyTimeCtrl::OnDtnFormat)
ON_NOTIFY_REFLECT(DTN_FORMATQUERY, &CMyTimeCtrl::OnDtnFormatquery)
ON_NOTIFY_REFLECT(DTN_WMKEYDOWN, &CMyTimeCtrl::OnDtnWmkeydown)
END_MESSAGE_MAP()

Thanks, with the guidance from the comment section I manage to resolve my issue. In the message map I made an error, corrected as shown below. Now it's working fine. In my resource section, the IDC_STATIC value is 1000:
BEGIN_MESSAGE_MAP(CMyTimeCtrl, CDateTimeCtrl)
ON_NOTIFY(UDN_DELTAPOS, IDC_STATIC, &CMyTimeCtrl::OnDeltaposSpin)
ON_NOTIFY_REFLECT(DTN_FORMAT, &CMyTimeCtrl::OnDtnFormat)
ON_NOTIFY_REFLECT(DTN_FORMATQUERY, &CMyTimeCtrl::OnDtnFormatquery)
ON_NOTIFY_REFLECT(DTN_WMKEYDOWN, &CMyTimeCtrl::OnDtnWmkeydown)
END_MESSAGE_MAP()

Related

MFC on form create event

I have simple FMC dialog form. Can't find how to manage event that should be called on form create moment. Something like onFormCreate like it is in VB or Delphi.
How to create such functionality?
My simple form header:
#pragma once
// CMFCApplicationUPTDlg dialog
class CMFCApplicationUPTDlg : public CDialog
{
// Construction
public:
CMFCApplicationUPTDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_MFCAPPLICATIONUPT_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedButton1();
};
You want to handle it in the OnInitDialog() member function. At the point that OnInitDialog() is called, the dialog and all of its child windows will have been created. However, the dialog will still be invisible to the user. After exiting OnInitDialog(), the dialog will be shown to the user.
So, it is the place where you would want to do initialization of your dialog.
You need to implement OnInitDialog in your own derived class.
BOOL CMFCApplicationUPTDlg::OnInitDialog()
{
// this will create the controls you defined in the resources.
BOOL retValue = __super::OnInitDialog();
// initialize (or add new controls to ) your dialog content here.
// ...
return retValue;
}

Setting Cedit Text

I have the following code in trying to set the text in a Cedit text box:
class CMetaDlg : public CDialogEx
{
public:
CMetaDlg();
// Dialog Data
enum { IDD = IDD_META };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
public:
CEdit m_author;
CEdit m_sources;
afx_msg void OnBnClickedOk();
};
CMetaDlg::CMetaDlg() : CDialogEx(CMetaDlg::IDD)
{
}
void CMetaDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_AUTHOR, m_author);
DDX_Control(pDX, IDC_SOURCES, m_sources);
}
BEGIN_MESSAGE_MAP(CMetaDlg, CDialogEx)
ON_BN_CLICKED(IDOK, &CMetaDlg::OnBnClickedOk)
END_MESSAGE_MAP()
void CEmergenceApp::OnFileMeta()
{
CMetaDlg md;
md.DoModal();
md.m_author.SetWindowTextW(CEmergenceView::GetDoc()->author);
md.m_sources.SetWindowTextW(CEmergenceView::GetDoc()->sources);
}
This gives me a debug assertion error. I am assuming the problem lies in the lines:
md.m_author.SetWindowTextW(CEmergenceView::GetDoc()->author);
md.m_sources.SetWindowTextW(CEmergenceView::GetDoc()->sources);
As commenting them out, everything works fine.
When you call DoModal the dialog is created, the edit controls are created and then when the user clicks OK or Cancel the edit controls and dialog window are destroyed. Then DoModal returns. I do not understand what you are trying to do by trying to set the edit control's text after the dialog box closes.

What is the proper way to handle a screen rotation and the media route button and the existing session?

The example on https://developers.google.com/cast/cast_2nd-screen_app_tutorial shows a onDestroy method which calls unregisterMediaRouteProvider. This causes the MediaRouter.Callback.onRouteUnselected method to get called which in turn ends the session. This leads to the app getting disconnected from the chromecast device and the MediaRouteButton stops being blue. Below is the onDestroy method from the example:
#Override
protected void onDestroy() {
MediaRouteHelper.unregisterMediaRouteProvider(mCastContext);
mCastContext.dispose();
super.onDestroy();
}
So my question is, what is the proper way to handle screen rotation when using the chromecast device from an app?
You can try using isFinishing() method of Activity to figure out if onDestroy is called due to application really "finishing" or is called for other reasons. Another option is to handle orientation change yourself.
You can see the guidelines for handling setup/destruction of the Chromecast (such as when orientation change is happening) on https://developers.google.com/cast/docs/android_sender
The relevant sections of code are the following ones:
#Override
protected void onResume() {
super.onResume();
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
#Override
protected void onPause() {
if (isFinishing()) {
mMediaRouter.removeCallback(mMediaRouterCallback);
}
super.onPause();
}
And also the following code:
#Override
protected void onStart() {
super.onStart();
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
#Override
protected void onStop() {
mMediaRouter.removeCallback(mMediaRouterCallback);
super.onStop();
}
It is also a good idea to have a boolean value in your program, for instance "wasLaunched" or "isConnected" to keep track of whether the connection to the chromecast is active or not. I use this variable in my code to check if I can send messages to the receiver or not. Then simply remember to save this variable and restore it when there is an orientation change on the device. This works for me in my chromecast enabled app. The code for saving/restoring my variable, so it survices orientation change is shown below:
protected void onSaveInstanceState(Bundle bundle) {
if (bundle!=null)
{
bundle.putBoolean("wasLaunched", wasLaunched);
}
super.onSaveInstanceState(bundle);
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState!=null)
{
wasLaunched = savedInstanceState.getBoolean("wasLaunched");
}
super.onRestoreInstanceState(savedInstanceState);
};
Of course you can also put other stuff in your bundle that needs to survive an orientation change. I am not using the onDestroy override you describe there, nor is it mentioned in the google documentation I link to. But I use the teardown() method described in that document I link to for cleaning up, but this only happens when I close the connection, because I dont want to close the connection to the chromecast upon orientation change.

Crashing while executing GetParent(). Closing of a modeless dialog box

I am creating a modeless dialog box. The dialog box is called from the menu item of main frame window.
MainFrm.h
CModeless* modeless;
bool modelessDlgOpen;
MainFrm.cpp
void CMainFrame::OnDatabaseMLdlg()
{
// TODO: Add your command handler code here
if (modelessDlgOpen == TRUE)
return;
modelessDlgOpen = TRUE;
modeless = new CModeless(this);
//modeless->Create(IDD_MLDLG, GetDesktopWindow());
modeless->Create(IDD_MLDLG, this);
mbPoll->ShowWindow(SW_SHOW);
}
When menu item is clicked, OnDatabaseMLdlg() function is called and a modeless dialog box with resource ID IDD_MLDLG appears.
The issue is while closing the modeless dialog box.
I am not able to find out the correct method to have a clean closure / destroy of this modeless dialog box. Upon clicking the cross button in right-top corner, which message gets
generated?
My current code which I have tried is as follows. (producing code related only to the closure of the dialog box)
MLDLG.h
#pragma once
#define WM_MLDLG_CLOSED (WM_USER + 555)
// CModeless dialog
class CModeless : public CDialog
{
DECLARE_DYNAMIC(CModeless)
public:
CModeless(CWnd* pParent = NULL); // standard constructor
virtual ~CModeless();
// Dialog Data
enum { IDD = IDD_MLDLG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL);
afx_msg void OnNcDestroy();
virtual void PostNcDestroy();
CWnd* mParent;
afx_msg void OnBnClickedCancel();
};
MLDLG.cpp
void CModeless::OnNcDestroy()
{
CDialog::OnNcDestroy();
// TODO: Add your message handler code here
}
void CModeless::PostNcDestroy()
{
CDialog::PostNcDestroy();
GetParent()->PostMessage(WM_MLDLG_CLOSED,0,0); // **CRASHES HERE**
delete this;
}
void CModeless::OnBnClickedCancel()
{
// TODO: Add your control notification handler code here
//CDialog::OnCancel();
DestroyWindow();
}
Not able to understand what am I doing wrong or what am I missing?
I can provide additional details in case required.
Thanks in advance.
EDIT-20130612: Additional information:
My constructor is as follows:
CModeless::CModeless(CWnd* pParent /*=NULL*/)
: CDialog(CModeless::IDD, pParent)
{
mParent = pParent;
if (mParent == NULL)
{
MessageBox(L"mParent is NULL");
}
else
{
MessageBox(L"mParent is not NULL");
}
}
Here, I have verified that mParent is not NULL.
PostNCDestroy() is called VERY late and most of the useful state of the MFC window is not valid at that point. GetParent() is probably returning NULL, which will cause a crash the way you are using it.
Try moving the PostMessage call to OnDestroy() before calling the base class implementation there.
Another option is to cache the parent's hWnd and call ::PostMessage() on that hWnd;

Click event for static text

I have a static text named IDC_STATIC for which I made a click event, but it is not getting called when it's clicked.
ON_BN_CLICKED(IDC_STATIC, ontest) //(begin message map)
void test::ontest(my method)
{
MessageBox("success");
}
afx_msg void test(); //(header file)
What is wrong with the code?
The solution is to go to the static text control's properties and enable Notify.

Resources