Click here to Skip to main content
15,861,125 members
Articles / Desktop Programming / MFC
Article

MS Outlook style Calendar

Rate me:
Please Sign up or sign in to vote.
4.92/5 (49 votes)
6 Aug 200511 min read 291.7K   9.4K   167   78
A custom CWnd derived control which simulates the functionality of MS Outlook Calendar control.

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

Image 1

Week view

Image 2

Introduction

Like many developers I searched within the CodeProject 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 tasks 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/Tasks) 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

  1. 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
  2. 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.
      1. On the Settings For... dropdown ListBox select All Configurations.
      2. 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.
      1. Select All Configurations from the Configuration: dropdown ListBox.
      2. Click on the Linker option from the tree control.
      3. Next click on Input to display the input values.
      4. 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.
      5. 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

Image 3

Visual Studio .NET 2003

Image 4

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 //}}AFX_DATA_MAP 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();
// Display Calendar in Month View
m_WVCtrl.SetCurrentDate(dtS, FALSE, WV_MONTHVIEW);

or

COleDateTime dtS = COleDateTime::GetCurrentDate();
// Display Calendar in Week View
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

    This method is used to delete all the data items related to this control.

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

    // Display Date Range!!
    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

    Returns a 32-bit application-specific value associated with the specified item.

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

    // Set WVCtrl date for week display
    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 Task", 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

    Changes the background color of the Calendar control.

Syntax

    m_WVCtrl.SetBkColor(RGB(255, 0, 0); // Set to red 
                                        // background color

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();
    
    // Display calendar in month view and 
    // today's date would be highlighted.
    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

    // Setup the Calendar control
    CBitmap bmpImgSm;
    m_ImgList.Create(16, 16, ILC_COLOR24 | ILC_MASK, 0, 1);
    
    // Load 256 color bitmap containing the images...
    bmpImgSm.LoadBitmap(IDB_BMPREMINDER);
    
    // Place bitmap into image list...
    m_ImgList.Add(&bmpImgSm, RGB(0, 255, 0));
    
    // Attach image list to the Calendar Control
    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 tasks based on color.

Syntax

    dtSDate.SetDateTime(2005, 8, 6, 12, 00, 0);
    // 45 minutes for lunch
    dtWDate.SetDateTime(2005, 8, 6, 12, 45, 0);    
    // Display as a task, use task image
    int nItem = m_WVCrtrl.InsertItem(dtSDate, dtEDate, 
                                "Lunch with Rolando", 1); 
    // Set appointment to green color
    m_WMCtrl.SetItemColor(nItem, RGB(0, 255, 0)); 
    
    
    dtSDate.SetDateTime(2005, 8, 6, 8, 30, 0);
    // 2 hour appointment
    dtWDate.SetDateTime(2005, 8, 6, 10, 30, 0);    
    nItem = m_WVCrtrl.InsertItem(dtSDate, dtEDate, 
                                 "Sales meeting", 0);
    // Set appointment to blue color
    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");
    // 999 use this internal value
    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:

  1. 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)
  2. Next add the following line to your message map:
    ON_NOTIFY(NM_DBLCLK, IDC_CALCTRL, OnCellDblClick)
    ON_NOTIFY(NM_CLICK, IDC_CALCTRL, OnCellClick)
  3. 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.

    Image 5

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

History

  • July 11th, 2005 - Began development of this code.
  • July 18th, 2005 - Completed initial development.
  • August 6th, 2005 - Released to CodeProject.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Founder Virtual Cyber Studios, LLC
United States United States
I have been programming Windows applications since 1990 (v 3.0). Remember Borland's Turbo C/C++ and Microsoft C/C++ 6? Both were in Text mode... WTF | :WTF:

Comments and Discussions

 
QuestionRegarding scrolling Pin
trk200429-May-13 2:04
trk200429-May-13 2:04 
QuestionIt's a good control,but hava several bug Pin
kalrey9-Aug-11 20:16
kalrey9-Aug-11 20:16 
GeneralFix to GetItemData() Pin
Member 371720425-Feb-11 4:37
Member 371720425-Feb-11 4:37 
Generaldo you have new version for unicode Pin
logi00123-Dec-09 2:23
logi00123-Dec-09 2:23 
GeneralVB6 usage Pin
MTeefy30-Nov-09 7:06
MTeefy30-Nov-09 7:06 
GeneralSetTime() shows DATE instead of TIME in both controls... Pin
AlexEvans27-Aug-08 22:09
AlexEvans27-Aug-08 22:09 
GeneralNIce job, but... Pin
AlexEvans24-Aug-08 17:12
AlexEvans24-Aug-08 17:12 
GeneralRe: NIce job, but... Pin
Rolando Cruz25-Aug-08 1:49
Rolando Cruz25-Aug-08 1:49 
GeneralRe: NIce job, but... Pin
AlexEvans25-Aug-08 2:46
AlexEvans25-Aug-08 2:46 
QuestionVS 2005 control library Pin
pseudokris11-Feb-08 13:48
pseudokris11-Feb-08 13:48 
QuestionUse this control in a vb.net 2003 project Pin
dbaratelli14-Nov-06 6:56
dbaratelli14-Nov-06 6:56 
GeneralSmall bug Pin
Ice_2k16-Oct-06 1:21
Ice_2k16-Oct-06 1:21 
QuestionWow! Excellent control! Pin
Willem_Le_Roux10-Jul-06 5:12
Willem_Le_Roux10-Jul-06 5:12 
AnswerRe: Wow! Excellent control! Pin
Rolando Cruz10-Jul-06 15:05
Rolando Cruz10-Jul-06 15:05 
GeneralRe: Wow! Excellent control! Pin
Willem_Le_Roux10-Jul-06 22:22
Willem_Le_Roux10-Jul-06 22:22 
GeneralSimilar control for ASP.NET (open-source) Pin
Dan Letecky28-Jun-06 10:30
Dan Letecky28-Jun-06 10:30 
QuestionWhy don't help us????? Pin
genesi36026-May-06 21:23
genesi36026-May-06 21:23 
QuestionGreat work - let's try printing again... Pin
arnoldkempt18-May-06 8:01
arnoldkempt18-May-06 8:01 
QuestionExcellent !!...Just wondered though ?? Pin
si_6926-Feb-06 6:02
si_6926-Feb-06 6:02 
AnswerRe: Excellent !!...Just wondered though ?? Pin
Rolando Cruz26-Feb-06 10:24
Rolando Cruz26-Feb-06 10:24 
GeneralSmall bug in GetDateRange Pin
Tom Archer19-Feb-06 14:55
Tom Archer19-Feb-06 14:55 
GeneralRe: Small bug in GetDateRange Pin
Rolando Cruz19-Feb-06 16:17
Rolando Cruz19-Feb-06 16:17 
GeneralNew entries don't display Pin
Tom Archer18-Feb-06 13:41
Tom Archer18-Feb-06 13:41 
GeneralUse in VB Pin
tassieboy9-Feb-06 17:12
tassieboy9-Feb-06 17:12 
GeneralRe: Use in VB Pin
yangyancheng7-Jul-06 19:09
yangyancheng7-Jul-06 19:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.