我的观点是我想让日历始终显示在月份视图中,如下所示:
预期的 TMonthCalendar 视图:
这样当我单击一个月时,它不会显示该月的日期,而是停留在此屏幕上并调用该事件。
在 Vista 之前,封装的底层Win32 MonthCal 控件TMonthCalendar
根本没有视图的概念,因此您无法在 XP 和更早版本中执行您所要求的操作,除非您在那些 Windows 上找到支持您想要的内容的第 3 方日历版本。
但是,在 Vista 和更高版本中,底层的 MonthCal 控件是视图感知的(但TMonthCalendar
它本身不是)。您可以手动向's发送MCM_SETCURRENTVIEW
消息以将其初始视图设置为,并将其属性子类化以在用户更改活动视图时拦截消息(VCL 的包装器)以查找通知。您无法将控件锁定到特定视图,但您可以在用户将活动视图从“年”视图更改为“月”视图时做出反应,然后可以根据需要将日历重置回“年”视图。TMonthCalendar
HWND
MCMV_YEAR
WindowProc
CN_NOTIFY
WM_NOTIFY
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
组件TCalendarPicker
。它们都有一个DisplayMode
您可以TDisplayMode::dmYear
为当前视图设置的属性,以及一个On(Calendar)ChangeView
对用户的视图更改做出反应的事件。