简体   繁体   中英

Use TMonthCalendar for months and years only

My point is I want to keep the calendar always on the months view, like this:

Expected TMonthCalendar view:

图片

So that when I click in a month, instead of showing the days of the month, it stays in this screen and call the event.

Prior to Vista, the underlying Win32 MonthCal control that TMonthCalendar wraps has no concept of views at all, so you can't do what you are asking for in XP and earlier, unless you find a 3rd party calendar that supports what you want on those Windows versions.

However, in Vista and later, the underlying MonthCal control is view-aware (but TMonthCalendar itself is not). You can manually send a 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 notification when the user changes the active view. You can't lock the control to a specific view, but you can react to when the user changes the active view from the Year view to the Month view, and then you can reset the calendar back to the Year view if needed.

For example:

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);
            }
        }
    }
}

If you are using C++Builder 10.1 Berlin or later, look at the newer TCalendarView and TCalendarPicker components. They both have a DisplayMode property that you can set to TDisplayMode::dmYear for the current view, and an On(Calendar)ChangeView event to react to view changes by the user.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM