Home

MFC Controls - Month Calendar

 

Introduction

The Win32 API provides a control used to select dates on a colorful calendar. The dates used and the way they display are based on the Regional Settings of the Control Panel. It may also depend on the operating system:

This convenient control is called Month Calendar. The title bar of the control displays two buttons and two labels. The left button allows the user to select the previous month by clicking the button. The left label displays the currently selected month. The right label displays the year of the displayed date. The right button is used to get to the next month.

The calendar can be configured to display more than one month. Here is an example that displays two months:

If the control is displaying more than one month, the buttons would increment or decrement by the previous or next month in the list. For example, if the control is displaying April and May, if the user clicks the left button, the control would display March and April. If the control is displaying April and May and the user clicks the right button, the control would display May and June. Also, to select any month of the current year, the user can click the name of the month, which displays the list of months and this allows the user to click the desired month:

To select a year, the user clicks the year number. This changes the year label into a spin button:

To change the year, the user can click the up or down arrows of the spin button. As the spin button is displaying, the user can also use the arrow keys of the keyboard to increase or decrease the value.

Under the title bar, the short names of week days display, using the format set in Control Panel. In US English, the first day is usually Sunday. The first day can be changed by the programmer.

On the control, the currently selected date has a circle around. To select a date on the control, the user clicks the desired date, which changes from the previous selection.

In the main area, the numeric days of the month display on a white background (this color and any color on the control can be changed as we will see in the next section). To select a date, the user clicks it in the list. By default, the calendar opens with today's day circled with a hand-drawn-look-alike ellipse. Using the buttons of the title bar, the month label, and/or the year, the user can change the date. If at one time the calendar is displaying a date other than today, and if the user wants to return to today's date, he can click the bottom label that displays Today (you as the programmer can hide the Today label if you want).

Month Calendar Creation

To create a calendar, on the Toolbox, you can click the Month Calendar Control button and click a dialog box, a form or the desired container. The Month Calendar control is based on the CMonthCalCtrl class. Therefore, to dynamically create this control, declare a CMonthCalCtrl variable or a pointer to CMonthCalCtrl. Here is an example:

// Exercise1Dlg.h : header file

class CExercise1Dlg : public CDialog
{
// Construction
public:
	CExercise1Dlg(CWnd* pParent = NULL); // standard constructor

private:
	CMonthCalCtrl *ctlCalendar;

};

The CMonthCalCtrl class, like all other control-oriented classes of the MFC library, is equipped with a Create() method that can be used to programmatically create a calendar and place it on a form or container. Here is an example:

CExercise1Dlg::CExercise1Dlg(CWnd* pParent /*=NULL*/)
	: CDialog(CExercise1Dlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CExercise1Dlg)
	
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	ctlCalendar = new CMonthCalCtrl;
}

	. . . No Change

/////////////////////////////////////////////////////////////////////////////
// CExercise1Dlg message handlers

BOOL CExercise1Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog. The framework does this automatically
	// when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE); // Set big icon
	SetIcon(m_hIcon, FALSE); // Set small icon

	// TODO: Add extra initialization here

	ctlCalendar->Create(WS_TABSTOP | WS_CHILD | 
			WS_VISIBLE | WS_BORDER,
			CPoint(20, 20), this, 0x224);

	return TRUE; // return TRUE unless you set the focus to a control
}

Calendar Properties

After placing a Month Calendar on a dialog box or a form, it displays the current month and only one month. This is because, by default, its width and height are set enough to accommodate a month. To display more than one month, change the width of the control to provide enough space:

In the same way, you can increase the height to display many months.

To make it a highly visual object, a calendar uses different colors to represent the background, week days, the background of the title bar, the text of the title bar, the text of the days of the previous month, and the text of the days of the subsequent month. Of course, you can programmatically change these colors. Although any color is allowed in any category, you should make sure that the calendar is still reasonably appealing and usable.

To change the colors of the Month Calendar control, you can call the CMonthCalCtrl::SetColor() method. Its syntax is:

COLORREF SetColor(int nRegion, COLORREF ref);

 

By default, the title of the Month Calendar control appears on top of a blue background. If you want a different color, pass the nRegion argument as MCSC_TITLEBK, and pass the color of your choice as the ref argument: 
By default, the labels on the title bar display in a white color. To change the color used to paint the text of the labels, you can pass the nRegion argument as MCSC_TITLETEXT, and pass the color of your choice as the ref argument

Under the title bar, the short names of week days display, using the format set in Control Panel. In US English, the first day is Sunday. If you want to start with a different day, call the SetFirstDayOfWeek() method. Its syntax is:

BOOL SetFirstDayOfWeek(int iDay, int* lpnOld = NULL);

The first argument, and the only one required, must be an integer of the following values:

Value Weekday
0 Monday
1 Tuesday
2 Wednesday
3 Thursday
4 Friday
5 Saturday
6 Sunday


If the calendar is already functioning, to find what its first day of the week is, you can call the GetFirstDayOfWeek() method. Its syntax is:

int GetFirstDayOfWeek(BOOL* pbLocal = NULL) const;

This method returns an integer that is one of the values in the above table.

The names of weekdays use the same color as the color set when passing the MCSC_TITLETEXT value as the nRegion argument to the SetColor() method. Under the names of the week, there is a horizontal line used as the separator. By default, this line separator is painted in black but it uses the same color as the numeric values of the days of the selected month.

Under the line separator, the numeric days of the month are listed. By default, the numeric days of the control display above a white background which is the Window system color. To change background color of the area where the numeric days appear, pass the nRegion of the SetColor() method as MCSC_MONTHBK, and pass the color of your choice as the ref argument.

The numbers of the days of the month display in two colors. The real days of the selected month display, by default, in a black color as the WindowText system color. To change this color, pass the nRegion of the SetColor() method as MCSC_TRAILINGTEXT, and pass the color of your choice as the ref argument. 

Under the names of the week and their line separator, the numeric days of the month are listed. These days display in a different color. To specify the color of the days of the current month, pass the nRegion of the SetColor() method as MCSC_TEXT, and pass the color of your choice as the ref argument.

The Month Calendar control is used to let the user know today's date in two ways. On the calendar, today's date is circled by a hand-drawn ellipse. In the bottom section of the calendar, today's date is also displayed as a sentence. At design time, to display or hide the indication of today’s date, use the No Today property. If it is checked or set to True, which is the default in MFC, a circled label would not appear at the bottom of the control:

If it is unchecked or set to False, a circled label would not appear at the bottom of the control as seen in the previous screenshots.

As mentioned already, by default, the today label at the bottom of the control appears. To programmatically hide the today label, you can apply the MCS_NOTODAY style. Here is an example:

BOOL CExercise1Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog. The framework does this automatically
	// when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE); // Set big icon
	SetIcon(m_hIcon, FALSE); // Set small icon

	// TODO: Add extra initialization here

	ctlCalendar->Create(WS_TABSTOP | WS_CHILD | 
		WS_VISIBLE | WS_BORDER | MCS_NOTODAY,
		CPoint(20, 20), this, 0x224);

	return TRUE; // return TRUE unless you set the focus to a control
}

We also mentioned that today date appears with a circle. If you want to hide just the circle, apply the MCS_NOTODAYCIRCLE style:

BOOL CExercise1Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog. The framework does this automatically
	// when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE); // Set big icon
	SetIcon(m_hIcon, FALSE); // Set small icon

	// TODO: Add extra initialization here

	ctlCalendar->Create(WS_TABSTOP | WS_CHILD | 
		WS_VISIBLE | WS_BORDER |
		MCS_NOTODAYCIRCLE,
		CPoint(20, 20), this, 0x224);

	return TRUE; // return TRUE unless you set the focus to a control
}

At any time, a particular date is selected and has an ellipse with the same color as the background of the title bar. By default, the selected date is today's date. When the user clicks the calendar, a date is selected. To find out what date the user selected, you can access the CMonthCalCtrl::GetCurSel() method. It is overloaded in three versions whose syntaxes are:

BOOL GetCurSel(COleDateTime& refDateTime) const;
BOOL GetCurSel(CTime& refDateTime) const;
BOOL GetCurSel(LPSYSTEMTIME pDateTime) const;

Here is an example:

void CExercise1Dlg::OnRetrieveBtn() 
{
	// TODO: Add your control notification handler code here
	UpdateData();
	CTime tme = this->m_dtpCurrent.GetCurrentTime();
	this->m_Result.Format("%s", tme.Format("%A, %B %d, %Y"));
	UpdateData(FALSE);
}

When the user clicks the Month Calendar control, one date is selected. To control whether the user can select one or more dates, at design time, set the value of the Multi Select property accordingly. For example, if you want the user to select a range of dates on the control, set the Muilti Select property to true (MSVC .NET) or check its check box (MSVC 6). To programmatically allow the user to select more than one day, apply the MCS_MULTISELECT style:

BOOL CExercise1Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog. The framework does this automatically
	// when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE); // Set big icon
	SetIcon(m_hIcon, FALSE); // Set small icon

	// TODO: Add extra initialization here

	ctlCalendar->Create(WS_TABSTOP | WS_CHILD | 
		WS_VISIBLE | WS_BORDER |
		MCS_NOTODAYCIRCLE | MCS_MULTISELECT,
	CPoint(20, 20), this, 0x224);

	return TRUE; // return TRUE unless you set the focus to a control
}

With this property set, the user can select many days in the calendar. You also can programmatically select a range of days. To to this, you can call the CMonthCalCtrl::SetSelRange() method. It comes in three versions whose syntaxes are:

BOOL SetSelRange(const COleDateTime& pMinRange, const COleDateTime& pMaxRange);
BOOL SetSelRange(const CTime& pMinRange, const CTime& pMaxRange);
BOOL SetSelRange(const LPSYSTEMTIME pMinRange, const LPSYSTEMTIME pMaxRange);

After the user has selected a range date on the calendar, to find out what that range is, you can call the CMonthCalCtrl::GetSelRange() method.

As mentioned already, to change the month and subsequently the year of the calendar, the user can click the buttons continuously. To control the allowable dates the user can navigate from and to, you can call the CMonthCalCtrl::SetRange() method. It comes in three versions whose syntaxes are:

BOOL SetRange(const COleDateTime* pMinRange, const COleDateTime* pMaxRange);
BOOL SetRange(const CTime* pMinRange, const CTime* pMaxRange);
BOOL SetRange(const LPSYSTEMTIME pMinRange, const LPSYSTEMTIME pMaxRange);

The first argument, nMinRange is the starting date of the desired range. The second argument, nMaxRange, is the end desired date the user can navigate to.

 

Copyright © 2004-2005 FunctionX, Inc.