Month Calendar ControlsMonth Calendar Controls*
*Contents  *Index  *Topic Contents
*Previous Topic: NMLVODSTATECHANGE
*Next Topic: Month Calendar Control Reference

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.

arrowy.gifAbout Month Calendar Controls

arrowy.gifUsing Month Calendar Controls

arrowy.gifMonth Calendar Control Reference

About Month Calendar Controls

A month calendar control 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 in a dialog box.

Month calendar control in a dialog box.

An application creates a month calendar control by calling the CreateWindowEx function, 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 is implemented in version 4.70 and later of Comctl32.dll.

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.

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.

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.

//   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);
}

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. It then loops to set the 15th bit in each element of the array, using the application-defined BOLDDAY macro.

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;
}

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 could simply 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.


Up Top of Page
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.