What is
this control?
This is an
attempt to reproduce the functionality of
MS Outlook Calendar
control as it appears in the
Calendar
view. It supports similar features as the
MS Calendar control.
This is a work in progress. Study the code
in the demo, there you will see how to
access the date item data when overriding
clicks and double clicks. Below are a couple
of screen shots of the control:
Month view

Week view

Introduction
Like many
developers I searched within the ucancode
and other sites for a
control similar to this one
but could not find one so I decided to
create my own. I needed a
control
with similar functionality, but not exactly
the same as the
Calendar control found in
MS Outlook.
This
piece or code/control
was developed to help me display
appointments and tucancode.nets in a Real Estate
program that I am developing. I did not like
the one that was already available but I
wanted the look and feel to be similar to
MS-Outlook.
I hope you will find this control
useful and use it in your applications.
What this
code provides
- It is
completely written using
MFC
(no ATL, no Unicode, no .NET). If you
want this you are free to modify the
code.
- This
code has been tested in Win 2000 and Win
XP Professional. I have not tested it on
any other versions of Windows, but the
only function I would worry about is
GradientFill
,
but according to MSDN it is available as
of Win 98 so it would work fine from
that version on.
- This
code compiles successfully in VS 6 and
VS .NET 2003.
- This is
a work in progress so further additions
to the code will be coming.
- Does
not support date items of more than one
day. This is a feature I will be adding
later.
- Does
not support drag-and-drop of date items
from one date cell to another. This is a
feature I will be adding later.
One of the
things I learned about the original
Outlook Calendar
control after I created
this control was that it can display week
views from 1 to 6 weeks at a time. This is
one of the modifications I will be making to
this control in the near future.
Disclaimer
and acknowledgements
This
control
and the source code
are free to be used with
commercial and non commercial software.
However you are not allowed to sell
the source code for profit. The author of
this article does not take any
responsibility for any damage done or caused
directly or indirectly by this
source code
or an application using this
source code.
If you
decide to redistribute the
source code, please include my
name and e-mail somewhere in the source. If
you create an application with this control,
I would appreciate an email describing what
it is or a screen shot of it so that I'll
know it is being used and may serve as an
incentive to continue improving this code/control.
Special
thanks go to Tom Furuya for sharing his
excellent ColorSpy utility. It was very
useful in determining the colors and the
magnified views of the mouse pointer
locations were critical in getting some of
the drawing dimensions correct in this
control.
Background
The code and
its classes in this article provide all the
functionality to not only display a
Calendar control
in Week
or Month
views but also to include and display
entries (Appointments/Tucancode.nets) for the
selected dates. Although this code does not
provide the dialog boxes or windows
necessary to enter entries it does provide
you with the methods, properties and
overridables necessary to create, modify and
delete these entries.
I know this
code is not perfect and that someone may
actually find a better way to paint the
control. I have done all that I can to make
sure the painting of different views are as
efficient as possible. Of course, if I make
further enhancements or fixes to the code or
if any of you come up with fixes, I will
update this article.
Using the
code
- The
first step in using the
CWVDateCtrl
class is to add the following files to
your project:
-
WVDateCtrl.h/.cpp
-
WVCellData.h/.cpp
-
WVCellDataItem.h/.cpp
- You
will also need to add a library link to
the project.
- For
VS 6, click on Project + Settings...
(Alt+F7) to display the Project
Settings dialog box.
-
On
the Settings For... dropdown
ListBox select All
Configurations.
-
Next, click on the Link tab and
enter "msimg32.lib"
within the Object/library
modules. This library is needed
to use the
GradientFill
Windows function, which is used
to highlight the current day of
the
Month or
Week.
- For
VS 7, click on the Project +
<ProjectName> Properties... menu
option to display the Project
Property Pages dialog box.
-
Select All Configurations
from the Configuration: dropdown
ListBox.
-
Click on the Linker
option from the tree control.
-
Next click on Input to
display the input values.
-
For
Additional Dependencies
enter "msimg32.lib". This
library is needed to use the
GradientFill
Windows function, which is used
to highlight the current day of
the Month or Week.
-
Click on the OK button.
You also
need to add a custom control object within
your FormView or Dialog Window. Make sure to
name the class:
DBSWMDateCtrl
.
Visual
Studio 6

Visual
Studio .NET 2003

Now we
create the variable for this
control.
Assign the variable name
m_WVCtrl
by pressing the right mouse button on the
Dialog or FormView class and clicking the
Add Member Variable... menu option.
Enter
CWMDateCtrl
as the variable type and
m_WVCtrl
as the variable name.
Next, you
need to attach the variable name to the
custom control.
Within the FormView or Dialog class code,
locate the
DoDataExchange
procedure and add the following code
anywhere after the
line:
DDX_Control(pDX, IDC_CALCTRL, m_WMCtrl);
Now, within
the FormView or Dialog box (usually within
OnInitialUpdate
or
OnInitDialog
)
enter the following lines of code. You can
initially display the Calendar control in
Month or Week view by simply specifying
WV_MONTHVIEW
or
WV_WEEKVIEW
.
This method is
explained in more detail below:
COleDateTime dtS = COleDateTime::GetCurrentDate();
m_WVCtrl.SetCurrentDate(dtS, FALSE, WV_MONTHVIEW);
or
COleDateTime dtS = COleDateTime::GetCurrentDate();
m_WVCtrl.SetCurrentDate(dtS, FALSE, WV_WEEKVIEW);
If you need
to change the view of the control at runtime
you can use the
SetView
method:
m_WMCtrl.SetView(WV_WEEKVIEW, TRUE);
or
m_WMCtrl.SetView(WV_MONTHVIEW, TRUE);
When you
compile your code and display the window
which contains this custom control you
should see the
Calendar control displayed in
Week or
Month
view.
Member
functions
These
functions are in alphabetical order.
void
CWMDateCtrl::DeleteAllItems()
Description
Syntax
m_WVCtrl.DeleteAllItems();
BOOL
CWMDateCtrl::DeleteItem(long nItem)
Description
This
method is used to delete a specific data
item as specified by the
nItem
parameter. The parameter is the ID
number of the data item added to the
custom control with the
InsertItem
method.
Syntax
void CWeekViewDlg::OnCellDblClick(NMHDR *pNotifyStruct,
LRESULT *pResult)
{
NM_WVCELLDATA *pData = (NM_WVCELLDATA *)pNotifyStruct;
if (pData->pItem != NULL)
m_WVCtrl.DeleteItem(pData->nItem);
}
COleDateTime CWMDateCtrl::GetCurrentDate()
Description
Returns
the current date for this control. The
current date is the highlighted cell
within the Week or Month view.
Syntax
COleDateTime dtCurDate = m_WVCtrl.GetCurrentDate();
void
CWMDateCtrl::GetDateRange(COleDateTime
*pStartDate, COleDateTime *pEndDate)
Description
Use this
method to retrieve the current start and
end date
based on how the
control is displayed. If
the control
is displayed in Month view, as pictured
above, this method will return the
following values:
pStartDate
will equal 1/31/2005 and
pEndDate
will equal 3/13/2005.
If the
control
is displayed in Week view, as pictured
above, this method will return the
following values:
pStartDate
will equal 2/14/2005 and
pEndDate
will equal 2/20/2005.
Syntax
CString strBuf;
COleDateTime dtS, dtE;
m_WVCtrl.GetDateRange(&dtS, &dtE);
strBuf.Format("Date Range: %s - %s",
dtS.Format("%m/%d/%Y"),
dtE.Format("%m/%d/%Y"));
int
CWMDateCtrl::GetDay()
int
CWMDateCtrl::GetMonth()
int
CWMDateCtrl::GetYear()
Description
This
method returns the
day,
month or
year
of the current
date.
Syntax
int nCurrentDate = m_WVCtrl.GetDay();
int nCurrentMonth = m_WVCtrl.GetMonth();
int nCurrentYear = m_WVCtrl.GetYear();
int
CWMDateCtrl::GetView()
Description
This
method returns one of two values
WV_WEEKVIEW
or
WV_MONTHVIEW
.
This indicates the current display state
of the control.
Syntax
if (m_WVCtrl.GetView() == WV_WEEKVIEW)
m_WVCtrl.SetView(WV_MONTHVIEW);
else
m_WVCtrl.SetView(WM_WEEKVIEW);
DWORD
CWMDateCtrl::GetItemData(long nItem)
Description
Syntax
NM_WVCELLDATA *pData = (NM_WVCELLDATA *)pNotifyStruct;
if (pData->pItem != NULL)
DWORD dwValue = m_WVCtrl.GetItemData(pData->nItem);
...
long
CWMDateCtrl::InsertItem(COleDateTime
dtStart, COleDateTime dtEnd, CString strLine
/*=""*/, int nImage /*=-1*/)
Description
Inserts
a date
item into the custom
control.
For an item to be displayed within the
control the first parameter of this
method should be within range of the
date set by the
SetCurrentDate
method. The next two parameters are
optional and are used to specify if the
date item time is displayed using
regular (FALSE
)
or military (TRUE
)
time and which image from an attached
image list is used when painting the
date
item.
Syntax
dtS.SetDate(2005, 2, 19);
m_WVCtrl.SetCurrentDate(dtS, FALSE, WV_MONTHVIEW);
dtS.SetDateTime(2005, 2, 14, 8, 30, 0);
dtE.SetDateTime(2005, 2, 14, 9, 45, 0);
m_WVCtrl.InsertItem(dtS, dtS, "Monday Appointment", 0);
dtS.SetDateTime(2005, 2, 15, 22, 30, 0);
dtE.SetDateTime(2005, 2, 15, 23, 45, 0);
nItem = m_WVCtrl.InsertItem(dtS, dtE, "Tuesday Tucancode.net", 1);
BOOL
CWMDateCtrl::IsMilitaryTime()
Description
Returns
a
TRUE
or
FALSE
value to determine if the time portion
of the date entries are displayed using
military time (TRUE
)
or regular time (FALSE
).
Syntax
if (m_WVCtrl.IsMilitaryTime())
m_WVCtrl.SetMilitaryTime(FALSE);
else
m_WVCtrl.SetMilitaryTime(TRUE);
void
CWMDateCtrl::SetBkColor(COLORREF clrBk)
Description
Syntax
m_WVCtrl.SetBkColor(RGB(255, 0, 0);
void
CWMDateCtrl::SetCurrentDate(COleDateTime
dtDate, BOOL bMilitaryTime /*= FALSE*/, int
nView /*= WV_WEEKVIEW*/)
Description
This method
is used to specify the date that is to be
used as the current date, if we are
displaying the date
item times using Military or Regular time
and the type of view to be used. Using this
method you have to specify a
date,
preferably the current date (this would be
the highlighted date within the control).
This control would take this
date and
determine which other dates are to be
painted based on the specified view.
Syntax
COleDateTime dtToday = COleDateTime::GetCurrentTime();
m_WVCtrl.SetCurrentDate(dtToday, FALSE, WV_MONTHVIEW);
void
CWMDateCtrl::SetFont(CString strFName, int
nSize)
Description
Use this
method to change the default font and font
size to be used to paint the Calendar
control.
Syntax
m_WVCtrl.SetFont("Verdana", 14);
void
CWMDateCtrl::SetImageList(CImageList
*pImgList)
Description
Use this
method to attach an image list to the
Calendar control. The example
below shows how to attach a 256 color 16
X 16 bitmap to the
control.
Syntax
CBitmap bmpImgSm;
m_ImgList.Create(16, 16, ILC_COLOR24 | ILC_Mucancode.net, 0, 1);
bmpImgSm.LoadBitmap(IDB_BMPREMINDER);
m_ImgList.Add(&bmpImgSm, RGB(0, 255, 0));
m_WVCtrl.SetImageList(&m_ImgList);
void
CWMDateCtrl::SetItemColor(long nItem,
COLORREF clrItem)
Description
Use this
method to set or change the background
color of individual date items. This is
useful to identify the type of
appointments and tucancode.nets based on color.
Syntax
dtSDate.SetDateTime(2005, 8, 6, 12, 00, 0);
dtWDate.SetDateTime(2005, 8, 6, 12, 45, 0);
int nItem = m_WVCrtrl.InsertItem(dtSDate, dtEDate,
"Lunch with Rolando", 1);
m_WMCtrl.SetItemColor(nItem, RGB(0, 255, 0));
dtSDate.SetDateTime(2005, 8, 6, 8, 30, 0);
dtWDate.SetDateTime(2005, 8, 6, 10, 30, 0);
nItem = m_WVCrtrl.InsertItem(dtSDate, dtEDate,
"Sales meeting", 0);
m_WMCtrl.SetItemColor(nItem, RGB(0, 0, 255));
void
CWMDateCtrl::SetItemData(long nItem, DWORD
dwData)
Description
This
function sets the 32-bit
application-specific value associated
with the item specified by
nItem
.
Syntax
int nItem = m_WVCtrl.InsertItem(dtS, dtE, "Lunch time");
m_WVCtrl.SetItemData(nItem, 999);
void
CWMDateCtrl::SetMilitaryTime(BOOL bMil)
Description
Use this
method to set or change the display of
date item times. Setting the parameter
to
TRUE
will paint the date item times using
Military time, otherwise Regular time is
used. This method affects the entire
Calendar control.
Syntax
m_WVCtrl.SetMilitaryTime(TRUE);
void
CWMDateCtrl::SetView(int nV, BOOL bRedraw
/*=TRUE*/)
Description
Use this
method to change the way the
Calendar
control is painted. The
values which can be used are
WV_WEEKVIEW
or
WV_MONTHVIEW
.
Syntax
if (m_WVCtrl.GetView() == WV_WEEKVIEW)
m_WVCtrl.SetView(WV_MONTHVIEW);
else
m_WVCtrl.SetView(WM_WEEKVIEW);
Override
functions
Currently,
there are only two messages that you can
override in order to interact with this
control.
The Calendar control will notify the parent
window with a
NM_CLICK
and
NM_DBLCLK
.
To override these notification messages
follow these instructions:
- Add the
following
PROTECTEDmember
function to your FormView or dialog box
to process double click notifications
from the Calendar control:
afx_msg void OnCellDblClick(NMHDR *pNotifyStruct,
LRESULT* pResult); (Left mouse Double click)
afx_msg void OnCellClick (NMHDR *pNotifyStruct,
LRESULT* pResult); (Left mouse Click)
- Next
add the following line to your message
map:
ON_NOTIFY(NM_DBLCLK, IDC_CALCTRL, OnCellDblClick)
ON_NOTIFY(NM_CLICK, IDC_CALCTRL, OnCellClick)
- Edit
the
OnCellDblClick
/OnCellClick
member function. To access the Calendar
information you need to cast
pNotifyStruct
to
NM_WVCELLDATA
.
NM_WVCELLDATA *pData = (NM_WVCELLDATA *)pNotifyStruct;
NM_WVCELLDATA notification structure
typedef struct tagNM_WVCELLDATA {
NMHDR hdr;
CWVCellData *pCell;
CWVCellDataItem *pItem;
int iRow;
int iColumn;
BOOL bDNFClicked;
long nItem;
} NM_WVCELLDATA;
CWVCellData
*pCell;
This
member variable contains all the
information regarding the actual date
cell of the
Calendar control. You have
access to many functions and procedures
which directly affect the appearance and
behaviour of the Calendar date cell.
Take a
look at the WVCellData.h and
WVCellData.cpp files for more
information on this Calendar object. I
believe all the procedures and functions
are self explanatory.
CWVCellDataItem *pItem;
This
member variable is usually
NULL
unless the user clicks or double clicks
on a data item within a date cell of the
Calendar control. You have access to
functions and procedure which directly
affect the particular date item data.
Take a
look at the WVCellDataItem.h and
WVCellDataItem.cpp files for more
information on this Calendar date item
object. I believe the procedures and
functions are self-explanatory.
int iRow;
int iCol;
These
two member variables contain the mouse
pointer coordinates where the actual
click or double click has occurred.
BOOL
bDNFClicked;
This is
a special member variable. This member
variable will have a value of
TRUE
only when the user clicks on the Does
Not Fit rectangle which is located at
the bottom right part of any Calendar
date cell which can't display all of the
date items within the available cell
area.

When the
user clicks on this object, the
Calendar control will notify
the parent window as if the user has
double clicked the cell at which point
this member variable will be set to
TRUE
.
It is up to you to decide how you want
to handle this. I use this feature to
change the Calendar view from Month to
Week view.
long nItem;
This is
the ID number given to the Calendar date
item (pItem
)
when the
InsertItem
function is used.
Look at
the
OnCellClick
and
OnBtndeleteitem
member functions within the demo program
to find out how I have used this member
variable (CalCtrlDlg.cpp).