仅对月份和年份使用 TMonthCalendar

Use TMonthCalendar for months and years only

我的意思是我想让日历始终显示在月视图中,如下所示:

预期的 TMonthCalendar 视图:

所以当我点击一个月时,它不会显示该月的日期,而是停留在这个屏幕上并调用事件。

在 Vista 之前,底层 Win32 MonthCal control that TMonthCalendar 包装根本没有视图的概念,所以你不能做你在 XP 和更早版本中所要求的,除非你找到支持的第 3 方日历你想要那些 Windows 版本。

但是,在 Vista 及更高版本中,底层的 MonthCal 控件是视图感知的(但 TMonthCalendar 本身不是)。当用户更改活动视图时,您可以手动发送 MCM_SETCURRENTVIEW message to the TMonthCalendar's HWND to set its initial view to MCMV_YEAR, and subclass its WindowProc property to intercept CN_NOTIFY messages (the VCL's wrapper for WM_NOTIFY) looking for the MCN_VIEWCHANGE 通知。您无法将控件锁定到特定视图,但您可以在用户将活动视图从年视图更改为月视图时做出反应,然后您可以根据需要将日历重置回年视图。

例如:

class TMyForm : public TForm
{
__published:
    TMonthCalendar *MonthCalendar1;
    ...
private:
    TWndMethod PrevMonthCalWndProc;
    void __fastcall MonthCalWndProc(TMessage &Message);
    ...
public:
    __fastcall TMyForm(TComponent *Owner)
    ...
};

#include "MyForm.h"
#include <Commctrl.h>

#ifndef MCM_SETCURRENTVIEW

#define MCMV_MONTH      0
#define MCMV_YEAR       1

#define MCM_SETCURRENTVIEW (MCM_FIRST + 32)
#define MCN_VIEWCHANGE     (MCN_FIRST - 4) // -750

typedef struct tagNMVIEWCHANGE
{
    NMHDR           nmhdr;
    DWORD           dwOldView;
    DWORD           dwNewView;
} NMVIEWCHANGE, *LPNMVIEWCHANGE;

#endif

__fastcall TMyForm(TComponent *Owner)
    : TForm(Owner)
{
    if (Win32MajorVersion >= 6)
    {
        SendMessage(MonthCalendar1->Handle, MCM_SETCURRENTVIEW, 0, MCMV_YEAR);
        PrevMonthCalWndProc = MonthCalendar1->WindowProc;
        MonthCalendar1->WindowProc = MonthCalWndProc;
    }
}

void __fastcall TMyForm::MonthCalWndProc(TMessage &Message)
{
    PrevMonthCalWndProc(Message);
    if (Message.Msg == CN_NOTIFY)
    {
        if (reinterpret_cast<NMHDR*>(Message.LParam)->code == MCN_VIEWCHANGE)
        {
            LPNMVIEWCHANGE lpNMViewChange = static_cast<LPNMVIEWCHANGE>(Message.LParam);
            if ((lpNMViewChange->dwOldView == MCMV_YEAR) && (lpNMViewChange->dwNewView == MCMV_MONTH))
            {
                // do something ...
                SendMessage(MonthCalendar1->Handle, MCM_SETCURRENTVIEW, 0, MCMV_YEAR);
            }
        }
    }
}

如果您使用的是 C++Builder 10.1 Berlin 或更高版本,请查看较新的 TCalendarView and TCalendarPicker 组件。它们都有一个 DisplayMode 属性,您可以为当前视图设置为 TDisplayMode::dmYear,还有一个 On(Calendar)ChangeView 事件来响应用户的视图更改。