65.9K
CodeProject 正在变化。 阅读更多。
Home

MS Outlook 风格的迷你日历控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (33投票s)

2002年1月27日

CPOL

7分钟阅读

viewsIcon

520032

downloadIcon

6847

一个自定义的 CWnd 派生控件,模拟了 MS Outlook 迷你日历控件的功能。

这是什么控件?

这是对 MS Outlook 迷你日历控件功能的重现,该控件出现在日期选择控件和日视图调度程序中。它支持 MS 控件的许多相同功能。

以下是该控件的一些屏幕截图。

(标准 1 个月视图,显示“今天”和“无”按钮)

(12 个月视图)

(8 个月视图,显示标题选择弹出窗口)

(4 个月视图,显示多选)

该控件能做什么?

  • 支持 3D 边框,类似于 MS Outlook(可选)
  • 支持“今天”按钮和/或“无”按钮。(两者都可选)
  • 支持不同的字体用于标题、星期行、日期数字和特殊日期数字。
  • 支持突出显示今天的日期。(可选)
  • 支持 N 行和 N 列。(见屏幕截图)
  • 单选或多选。(多选可以跨越多个月份)
  • 多选可以跨越多个月份。
  • 支持特殊日期高亮显示。(见屏幕截图)
  • 支持根据屏幕分辨率、行/列数和父窗口大小自动选择字体大小。
  • 标题日期选择器弹出列表。(见屏幕截图)
  • 多选可以限制为最多选择 X 个连续天数。
  • 当设置为 1 行、1 列时,显示 6 周的日历,并在右上角单元格显示开始日期之前的日期,在左下角单元格显示结束日期之后的日期,当行数或列数超过 1 时。

该控件如何工作?

该控件由一个名为 CFPSMiniCalendarCtrl 的 CWnd 派生类和许多支持类组成。几个可用的窗口样式控制控件的外观。行数和列数可以通过简单的函数调用来指定。字体也可以通过函数调用进行自定义。

窗口样式

FMC_MULTISELECT 启用多选模式
FMC_NOHIGHLIGHTTODAY 禁用突出显示今天的日期
FMC_TODAYBUTTON 启用“今天”按钮
FMC_NONEBUTTON 启用“无”按钮
FMC_AUTOSETTINGS 根据行/列数和父窗口大小自动配置控件
FMC_NO3DBORDER 禁用自定义 3D 边框
FMC_NOSHOWNONMONTHDAYS 禁用显示非本月日期。通常,在显示单行/单列日历时,将显示在 6 周日历中的上个月和下个月的日期,以灰色显示。此选项禁用这些日期的显示。

重要方法

SetRowsAndColumns (int iRows, int iCols)
设置控件将显示的行数和列数。
SetCurrentMonthAndYear (int iMonth, int iYear)
设置控件将在第一行和第一列显示的月份/年份。其他单元格将从此日期开始递增。
SetBackColor (COLORREF cColor)
设置控件的背景颜色。默认为 GetSysColor(COLOR_WINDOW)
SetMaxSize (SIZE size)
如果启用了自动配置设置,此方法设置控件可以占用的最大尺寸。您可以使用任何所需的 SIZE 或两个常量 FMC_MAX_SIZE_NONE 和 FMC_MAX_SIZE_PARENT 中的一个
SetMaxSelDays (int iValue)
如果启用了多选,此方法设置可以选择的连续天数的最大数量。您可以使用任何从 1 开始的正值,或者使用常量 FMC_NO_MAX_SEL_DAYS。
SetDefaultMinFontSize (int iValue)
如果启用了自动配置,此设置控件可以用于适应的最小字体大小。如果达到最小字体大小仍不合适,控件将停止自动调整大小并使用此字体大小。内部默认值(如果未调用此方法)为 5。
SetDefaultFont (LPCTSTR lpszValue)
如果启用了自动配置,则设置各种选项使用的字体名称。内部默认值(如果未调用此方法)为“Tahoma”
SetHeaderFont (LPCTSTR lpszFont, int iSize, BOOL bBold, BOOL bItalic, BOOL bUnderline, COLORREF cColor)
设置标题使用的字体。此标题包含月份名称和年份数字。
SetDaysOfWeekFont (LPCTSTR lpszFont, int iSize, BOOL bBold, BOOL bItalic, BOOL bUnderline, COLORREF cColor)
设置星期标题使用的字体。此标题包含星期标签(日 一 二 三 四 五 六)。
SetDaysFont (LPCTSTR lpszFont, int iSize, BOOL bBold, BOOL bItalic, BOOL bUnderline, COLORREF cColor)
设置日期数字使用的字体。
SetSpecialDaysFont (LPCTSTR lpszFont, int iSize, BOOL bBold, BOOL bItalic, BOOL bUnderline, COLORREF cColor)
设置当日期是“特殊”日期时,日期数字使用的字体。
GetDate 返回控件中选择的数据。用于单选模式。
GetDateSel (COleDateTime& dtBegin, COleDateTime& dtEnd)
检索多选模式下选择的日期范围。在单选模式下也有效。
IsDateSelected (COleDateTime& dt)
如果指定的日期被选中,则返回 TRUE,否则返回 FALSE。
ScrollLeft (int iCount)
将月份向后滚动指定的月份数。
ScrollRight (int iCount)
将月份向前滚动指定的月份数。
SetSpecialDaysCallback (funcSPECIALDATE pValue)
该控件使用回调函数,以便包含的应用程序可以提供有关特殊日期的信息。此函数用于设置此回调函数。默认情况下,没有特殊日期。
此函数的格式为
typedef BOOL (CALLBACK* funcSPECIALDATE)(COleDateTime&);

如何使用此控件

本文档提供的演示应用程序是了解控件工作原理以及如何在自己的应用程序中实现该控件的绝佳示例。以下是使用该控件的基本步骤。

  1. 将“FPSMiniCalendarCtrl.h”、“FPSMiniCalendarCtrl.cpp”、“FPSMiniCalendarListCtrl.h”和“FPSMiniCalendarListCtrl.cpp”文件添加到您的项目中。
  2. 在您的“stdafx.h”文件中包含“FPSMiniCalendarCtrl.h”。(您也可以在计划使用它的每个类头文件中包含它。)
  3. 在您的类的 .h 文件中,声明一个 CFPSMiniCalendarCtrl 类型的成员。(请参见下面的示例 1)
  4. 在您的类的 .cpp 文件中(OnCreate、OnInitialUpdate 或 OnInitDialog 函数都可以)。调用 Create 函数,并指定所需的样式和控件的位置。(请参见下面的示例 2。)
  5. 如果需要,通过调用 SetDate 或 SetDateSel 方法设置日期选择。
  6. 如果需要,通过调用 SetRowsAndColumns 方法设置所需的行数和列数。
  7. 如果需要,通过调用 SetSpecialDaysCallback 方法设置您所需的特殊日期回调函数。
  8. 如果您不使用自动配置,则应调用 RedrawWindow 方法以确保用户看到刷新后的设置。
  9. 您可能还想在您的类中设置一个通知消息映射,以便在日期选择更改时收到通知。(请参见下面的示例 3。)

使用特殊日期回调函数

特殊日期回调函数用于使控件能够高亮显示(通常是粗体)具有特殊意义的日期。这可能是节假日、计划好的约会等。回调函数必须按如下方式定义。

BOOL CALLBACK IsSpecialDateCallback(COleDateTime &dt);

它可以是全局函数,也可以是您类之一的静态成员。

实现应返回 FALSE(如果给定日期不是特殊的)和 TRUE(如果它是特殊的)。

注意:此函数被调用得相当频繁,因此请尽量不要在此函数中执行任何耗时的过程。

示例 1(.h 文件修改)

    // .h file, inside your classes definition

    CFPSMiniCalendarCtrl m_wndCalendar;

示例 2(.cpp 文件修改,OnCreate 函数)

    // .cpp file before any methods are implemented

    #define WMID_CALENDAR   WM_USER+1
    
    // .cpp file (OnCreate, OnInitialUpdate or OnInitDialog will all work OK)

    m_wndCalendar.Create(NULL, NULL, WS_CHILD | WS_VISIBLE | FMC_MULTISELECT |
                                     FMC_AUTOSETTINGS | FMC_TODAYBUTTON | 
                                     FMC_NONEBUTTON, 
                         CalendarRect, this, WMID_CALENDAR);
    m_wndCalendar.SetDate(COleDateTime::GetCurrentTime());  // optional 
    m_wndCalendar.SetRowsAndColumns(3,4);  // optional
    m_wndCalendar.SetSpecialDaysCallback(IsSpecialDateCallback);  // optional
  

示例 3(如何接收选择更改通知)

    // ********************************************************
    // in your classes .h file, locate the end of the message map function
    // declaration look for DECALRE_MESSAGE_MAP()

    // immediately before DECLARE_MESSAGE_MAP(), insert the following line

    afx_msg void OnCalendarClick(NMHDR * pNotifyStruct, LRESULT * result );

    // ********************************************************
    // in your classes .cpp file, locate the end of the message map call area
    // look for END_MESSAGE_MAP()

    // immediately before END_MESSAGE_MAP(), insert the following line

    ON_NOTIFY(NM_CLICK, WMID_CALENDAR, OnCalendarClick)

    // ********************************************************
    // in your classes .cpp file, move to the end of the file and add the 
    // following lines

    void CYourClassName::OnCalendarClick(NMHDR * , LRESULT * )
    {
        COleDateTime dtBegin;
        COleDateTime dtEnd;

        m_wndCalendar.GetDateSel(dtBegin, dtEnd);

        // TODO: Add your custom handler here
    }

  

注释

这段代码并不完美,不适用于所有情况,但至少对于我的项目来说,它受到了高度评价(尤其是终端用户)。我正在努力将此控件作为我之前发布的日期编辑控件的拾取器。(点击此处查看日期编辑控件。)

我非常感谢您对我实现或代码的任何评论。谢谢。

更新

2002年1月28日 感谢 Pierre MEINDRE 指出一些与星期名称和每周第一天相关的国际化问题,也感谢他建议了禁用日历视图中非本月日期显示的选项。此外,感谢 Rainer Mangold 指出确定每周第一天的正确方法(大概)。

更改:
添加了 SetDayOfWeekNameGetDayOfWeekName 函数,以便星期标题行可以根据区域设置正确显示。
添加了 SetFirstDayOfWeek 函数,用于设置在星期标题和日期显示区域中显示的每周第一天。
添加了一个选项来启用/禁用日历中非本月日期的显示。现在有一个新的窗口样式可以在创建时设置,并且有 SetShowNoneMonthDayGetShowNoneMonthDay 函数。
纠正了标题列表弹出窗口中可能同时高亮显示 2 个项目的问题。
修改了 OnLButtonDownOnMouseMove 代码,以便在单击模式日历中,NM_CLICK 消息直到鼠标按钮释放(即 OnLButtonUp)后才发送。这更好地模拟了 MS Outlook 控件。

© . All rights reserved.