Link to home
Start Free TrialLog in
Avatar of sternocera
sternocera

asked on

MFC: changing the day state (i.e making bold) a CDateTimeCtrl's underlying CMonthCalCtrl

Hello,

I have an application that uses a CDateTimeCtrl. I'd like to make its pop-up calendar's (CMonthCalCtrl) relevant days bold, by changing their day state, as is possible with plain, un-embedded CMonthCalCtrls. I thought I could just do this:

CDateTimeCtrl my_date_time;
CMonthCalCtrl* pMoCalCtrl = my_date_time..GetMonthCalCtrl();
VERIFY(pMoCalCtrl->ModifyStyle(0, MCS_DAYSTATE)); // change the style to MCS_DAYSTATE
...
pDayState = new MONTHDAYSTATE[nCount];
...
VERIFY(pMoCalCtrl->SetDayState(nCount, pDayState));

However, this still causes an assertion failure from the framework that indicates that the MCS_DAYSTATE style isn't set:

BOOL CMonthCalCtrl::SetDayState(int nMonths, LPMONTHDAYSTATE pStates)
{
      .....  
      ASSERT(GetStyle()&MCS_DAYSTATE);
      .....

How can I prevent this error from occuring, and change the underlying CDateTimeCtrl's CMonthCalCtrl day state to make relevant days bold as desired?

Thanks a lot,
Sternocera

Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

use the ModifyStyleEx member function to set extended windows styles.

  VERIFY(pMoCalCtrl->ModifyStyleEx(0, MCS_DAYSTATE)); // change the style to MCS_DAYSTATE

You also could use

   HWND hwnd = pMoCalCtrl->m_hWnd;
   SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | MCS_DAYSTATE);
 
However some styles don't work if set after creation. I don't know whether the MCS_DAYSTATE style needs a proper initialization or not.

I read in MSDN and it says the following:

-----------------------
After creating the control, you can change all of the styles except for MCS_DAYSTATE and MCS_MULTISELECT. To change these styles, you will need to destroy the existing control and create a new one that has the desired styles. To retrieve or change any other window styles, use theGetWindowLong andSetWindowLong functions.
-----------------------

That would mean that the above won't work. And you already have to *create* the control with the states required.

For creating the control using the correct styles, MSDN gives you two choices:

----------vvvv MSDN ------------------------------
How the month calendar control is created depends on whether you are using the control in a dialog box or creating it in a nondialog window.

To use CMonthCalCtrl directly in a dialog box
In the dialog editor, add a Month Calendar Control to your dialog template resource. Specify its control ID.

Specify any styles required, using the Properties dialog box of the month calendar control.

Use the Add Member Variable Wizard to add a member variable of type CMonthCalCtrl with the Control property. You can use this member to call CMonthCalCtrl member functions.

Use the Properties window to map handler functions in the dialog class for any month calendar control notification messages you need to handle (see Mapping Messages to Functions).

In OnInitDialog, set any additional styles for the CMonthCalCtrl object.

To use CMonthCalCtrl in a nondialog window
Define the control in the view or window class.

Call the control's Create member function, possibly in OnInitialUpdate, possibly as early as the parent window's OnCreate handler function (if you're subclassing the control). Set the styles for the control.
-----------^^^^ MSDN ------------------




Avatar of sternocera
sternocera

ASKER

itsmeandnobodyelse,

That's helpful, thank you. However, it is not apparent how I can apply this information from MSDN to solve my particular problem - changing the day state of a CDateTimeCtrl's underlying CMonthCalCtrl.

Regards,
Sternocera
Avatar of DanRollins
I tried some things on this...
Based on what I read in MSDN, the code in the snippet seems like *should* work (destroy the windows and createte it wwit the new style set), but it always crashes. I provide it not as an answer, but as a starting point for your own explorations.

void CD51Dlg::OnDropdownDatetimepicker1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	CMonthCalCtrl* pMoCalCtrl= m_ctlDtPicker.GetMonthCalCtrl();
 
	DWORD dwStylesEx= GetWindowLong( pMoCalCtrl->m_hWnd, GWL_EXSTYLE );
	DWORD dwStyles= GetWindowLong( pMoCalCtrl->m_hWnd, GWL_STYLE );
	dwStyles |= MCS_DAYSTATE;
 
	char szClassName[200];
	int nRet= GetClassName( pMoCalCtrl->m_hWnd, szClassName, sizeof(szClassName) );
 
	DWORD nID= GetWindowLong( pMoCalCtrl->m_hWnd, GWL_ID );
	
	CRect r;
	pMoCalCtrl->GetWindowRect( &r );
 
	pMoCalCtrl->DestroyWindow();
//	pMoCalCtrl->Create( dwStyles, r, this, nID );  // the dialog is the parent
	pMoCalCtrl->CreateEx( dwStylesEx, szClassName, "", dwStyles, r, this, nID, 0 );
 
	*pResult = 0;
}

Open in new window

This page of a CodeProect forum has an extensive discussion on this.  
The problem is that the CMonthCalCtrl  is created by the CDateTimeCtrl so we don't have nay control over its style settings.  
One person discovered a workaround:  Create a hidden CMonthCalCtrl (which you can control) and the unhide and move it as necessary.  See:
  http://www.codeproject.com/script/Forums/View.aspx?fid=1647&msg=908180
The workaround is described by DRHuff, in blue.
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial