Month Calendar Controls


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.

About Month Calendar Controls

The month calendar control is implemented in version 4.70 and later of Comctl32.dll. It provides a simple and intuitive way for a user to select a date from a familiar interface. The following illustration shows a month calendar control.

An application creates a month calendar control by calling the CreateWindowEx function and specifying MONTHCAL_CLASS as the window class. The class is registered when the month calendar class is loaded from the common controls dynamic-link library (DLL). Register this class by calling the InitCommonControlsEx function, specifying the ICC_DATE_CLASSES bit flag in the accompanying INITCOMMONCONTROLSEX structure.

 

Note  

 

 

The Month Calendar Control User Interface

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.

Scrolling the control's display

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 ( VK_NEXT ) 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 MCM_SETMONTHDELTA message or the corresponding macro, MonthCal_SetMonthDelta . However, the PAGE UP and PAGE DOWN keys change the selected month by one, regardless of the number of months displayed or the value set by MCM_SETMONTHDELTA.

Selecting a nonadjacent month

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.

Selecting a different year

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.

Selecting the current day

If a month calendar control is not using the MCS_NOTODAY style, the user can return to the current day by clicking the "Today" text at the bottom of the control. If the current day is not visible, the control updates its display to show it. Related keyboard commands are:

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.

Day States

Month calendar controls that use the MCS_DAYSTATE style support day states. The control uses day state information to determine how it draws specific days within the control. Day state information is expressed as a 32-bit data type, MONTHDAYSTATE . Each bit in a MONTHDAYSTATE bit field (1 through 31) represents the state of a day in a month. If a bit is on, the corresponding day will be displayed in bold; otherwise, it will be displayed with no emphasis.

An application can explicitly set day state information by sending the MCM_SETDAYSTATE message or by using the corresponding macro, MonthCal_SetDayState . Additionally, month calendar controls that use the MCS_DAYSTATE style send MCN_GETDAYSTATE notification messages to request day state information. For more information on supporting day states, see Processing the MCN_GETDAYSTATE Notification Message and Preparing the MONTHDAYSTATE Array.

Month Calendar Control Styles

Month calendar controls have several styles that determine their appearance and behavior. When you create the control using CreateWindowEx , include the desired styles in the dwStyle parameter.

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 the GetWindowLong and SetWindowLong functions.

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 MCM_SETMAXSELCOUNT message or the accompanying macro, MonthCal_SetMaxSelCount .

When a month calendar control uses the MCS_WEEKNUMBERS style, it displays week numbers at the left side of each month. If the MCS_NOTODAY style is applied, the control no longer circles the current day.

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.

Localization

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".

Month Calendar Control Notification Messages

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 WM_NOTIFY messages.

The following notification messages are used with month calendar controls.

Notification Description
MCN_GETDAYSTATE Requests information about which days should be displayed in bold. For more information, see Preparing the MONTHDAYSTATE Array.
MCN_SELCHANGE 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.
MCN_SELECT Notifies the parent that the user has explicitly selected a date.

Times in the Month Calendar Control

Because the month calendar control cannot be used to select a time, the time related fields of the SYSTEMTIME structure need to be handled differently. When the control is created, it will insert the current time into its "Today" date and time.

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.

MCM_SETCURSEL The control will copy the time fields as they are, without validation or modification.
MCM_SETRANGE 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.
MCM_SETSELRANGE 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.
MCM_SETTODAY 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.

Using Month Calendar Controls

This section provides information and sample code for implementing month calendar controls.

Creating a Month Calendar Control

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 MonthCal_GetMinReqRect macro to request size information and then resizes the control by calling SetWindowPos . If you subsequently change the font with WM_SETFONT , the dimensions of the control will not change. You must call MonthCal_GetMinReqRect again and resize the control to fit the new font.

Example

Processing the MCN_GETDAYSTATE Notification Message

Month calendar controls send the MCN_GETDAYSTATE notification message to request information about how the days within the visible months should be displayed. The following application-defined function, DoNotify, processes MCN_GETDAYSTATE by filling an array of MONTHDAYSTATE values to highlight the 15th day of each month.

DoNotify extracts the number of MONTHDAYSTATE values needed from the cDayState member of the NMDAYSTATE structure that lParam points to. The function then loops to set the 15th bit in each element of the array, using the application-defined BOLDDAY macro.

Example

Preparing the MONTHDAYSTATE Array

Both the MCM_SETDAYSTATE message and MCN_GETDAYSTATE notification message require an array of MONTHDAYSTATE values to determine how dates will be displayed. Each month that the control displays must have a corresponding element within the array.

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.