A month calendar control implements a calendar-like user interface. This provides the user with a very intuitive and recognizable method of entering or selecting a date. The control also provides the application with the means to obtain and set the date information in the control using existing data types.
The month calendar control is implemented in

An application creates a month calendar control by calling the
The month calendar control user interface allows the user to select a date from the displayed days or change the control's display in various ways.
By default, when a user clicks the arrow buttons in the top left or top right of the month calendar control, the control updates its display to show the previous or next month. If the month calendar control is displaying more than one month at a time, the display changes by the number of months currently in view. That is, if the month calendar displays January, February, and March and the user clicks the top right arrow button, the control updates its display to show April, May, and June. The user can also perform the same action by clicking the partial months displayed before the first month and after the last month.
The following keyboard commands can also be used to change the current month.
| PAGE UP ( |
Move to the next month. |
| PAGE DOWN (VK_PRIOR) | Move to the previous month. |
| HOME (VK_HOME) | Move to the first day of the current month. |
| END (VK_END) | Move to the last day of the current month. |
| CTRL + HOME | Move to the first visible month. |
| CTRL + END | Move to the last visible month. |
An application can change the number of months by which the control updates
its display by using the
When a user clicks the name of a displayed month, a pop-up menu appears that lists all months within the year. The user can select a month on the list. If the user's selection is not visible, the month calendar control scrolls its display to show the chosen month.
If the user clicks the year displayed next to a month name, an up-down control appears in place of the year. The user can change the year with this control. The month calendar control updates its display for the selected year when the up-down control loses focus. The related keyboard commands are:
| CTRL + VK_NEXT | Move to the next year. |
| CTRL + VK_PRIOR | Move to the previous year. |
If a month calendar control is not using the
| VK_LEFT | Move to the previous day. |
| VK_RIGHT. | Move to the next day. |
| VK_UP | Move to the previous week. |
| VK_DOWN | Move to the next week. |
Month calendar controls that use the
An application can explicitly set day state information by sending the
Month calendar controls have several
After creating the control, you can change all of the styles except for
MCS_DAYSTATE and
Month calendar controls that use the MCS_MULTISELECT style allow the user
to select a range of days. By default, the control allows the user to select
seven contiguous days. Your application can change the control's default
behavior by using the
When a month calendar control uses the
The MCS_DAYSTATE style is helpful when you want the control to highlight specific dates by displaying them in bold. For more information, see Day States.
The month-calendar control gets its format and all strings from LOCALE_USER_DEFAULT. For Windows 2000 and later systems, it gets the month title format from LOCALE_SYEARMONTH. Thus even with the same DLL version, the appearance of the control may vary slightly depending on the system software on which your application runs. For example, with Windows NT 4.0, the month title will look like: "September 1998". With Windows 2000, it will look like: "September, 1998".
A month calendar control sends notification messages when it receives user
input or must request day state information (MCS_DAYSTATE style only). The
control's parent receives these notifications as
The following notification messages are used with month calendar controls.
| Notification | Description |
|---|---|
| Requests information about which days should be displayed in bold. For more information, see Preparing the MONTHDAYSTATE Array. | |
| Notifies the parent that the selected date or range of dates has changed. The control sends this notification when the user explicitly changes the selection within the current month, or when the selection is implicitly changed in response to next/previous month navigation. | |
| Notifies the parent that the user has explicitly selected a date. |
Because the month calendar control cannot be used to select a time, the
time related fields of the
When a time is later set programmatically, the control will either copy the time fields as they are or validate them first and then, if invalid, store the current default times. Following is a list of the messages that set a date and a description of how the time fields are treated by the message.
| The control will copy the time fields as they are, without validation or modification. | |
| The time fields of the structures passed in will be validated. If they are valid, the time fields will be copied without modification. If they are invalid, the control will copy the time fields from the "Today" date and time. | |
| The time fields of the structures passed in will be validated. If they are valid, the time fields will be copied without modification. If they are invalid, the control will retain the time fields from the current selection ranges. | |
| The control will copy the time fields as they are, without validation or modification. |
When a date is retrieved from the control, the time fields will be copied from the stored times without modification. Handling of the time fields by the control is provided as a convenience to the programmer. The control does not examine or modify the time fields as a result of any operation other than those listed above.
This section provides information and sample code for implementing month calendar controls.
To create a month calendar control, use the CreateWindowEx function, specifying MONTHCAL_CLASS as the window class. You must first register the window class by calling the InitCommonControlsEx function, specifying the ICC_DATE_CLASSES bit in the accompanying INITCOMMONCONTROLSEX structure.
The following example demonstrates how to create a month calendar control
in an existing modeless dialog box. Note that the size values passed to CreateWindowEx
are all zeros. Because the minimum required size depends on the font the
control uses, the DoNotify example function uses the
Example
// CreateMonthCal -- Creates a month calendar control in a dialog box.
// Returns the handle to the month calendar control
// if successful, or NULL otherwise.
//
// hwndOwner -- Handle to the owner of the dialog box.
// g_hinst -- Global handle to the program instance.
//
/////
HWND WINAPI CreateMonthCal(HWND hwndOwner)
{
HWND hwnd;
RECT rc;
INITCOMMONCONTROLSEX icex;
// Load the window class.
icex.dwSize = sizeof(icex);
icex.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&icex);
// Create a modeless dialog box to hold the control.
g_hwndDlg = CreateDialog(g_hinst,
MAKEINTRESOURCE(IDD_DIALOG1),
hwndOwner,
DlgProc);
// Create the month calendar.
hwnd = CreateWindowEx(0,
MONTHCAL_CLASS,
"",
WS_BORDER | WS_CHILD | WS_VISIBLE | MCS_DAYSTATE,
0,0,0,0, // resize it later
g_hwndDlg,
NULL,
g_hinst,
NULL);
// Get the size required to show an entire month.
MonthCal_GetMinReqRect(hwnd, &rc);
// Arbitrary values
#define LEFT 35
#define TOP 40
// Resize the control now that the size values have been obtained.
SetWindowPos(hwnd, NULL, TOP, LEFT,
LEFT + rc.right, TOP + rc.bottom,
SWP_NOZORDER);
// Set colors for aesthetics.
MonthCal_SetColor(hwnd, MCSC_BACKGROUND, RGB(175,175,175));
MonthCal_SetColor(hwnd, MCSC_MONTHBK, RGB(248,245,225));
return(hwnd);
}
Month calendar controls send the
DoNotify extracts the number of MONTHDAYSTATE values needed
from the cDayState member of the
Example
BOOL WINAPI DoNotify(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
#define BOLDDAY(ds,iDay) if(iDay>0 && iDay<32)\
(ds)|=(0x00000001<<(iDay-1))
#define lpnmDS ((NMDAYSTATE *)lParam)
#define MAX_MONTHS 12
MONTHDAYSTATE mds[MAX_MONTHS];
INT i, iMax;
LPNMHDR hdr = (LPNMHDR)lParam;
switch(hdr->code){
case MCN_GETDAYSTATE:
iMax=lpnmDS->cDayState;
for(i=0;i<iMax;i++){
mds[i] = (MONTHDAYSTATE)0;
BOLDDAY(mds[i],15);
}
lpnmDS->prgDayState = mds;
break;
}
return FALSE;
}
Both the
To support these messages, your application must properly prepare the array. The following is a simple macro that sets a bit in a MONTHDAYSTATE value for a given day within that month.
#define BOLDDAY(ds,iDay) if(iDay>0 && iDay<32)\
(ds)|=(0x00000001<<(iDay-1))
Using this macro, an application can loop through an array of important dates, setting bits within the corresponding array elements. This approach is not the most efficient, of course, but works well for many purposes. As long as your application sets MONTHDAYSTATE bits appropriately, it does not matter how those bits were set.