【问题标题】:Use TMonthCalendar for months and years only仅使用 TMonthCalendar 数月和数年
【发布时间】:2019-03-19 17:43:31
【问题描述】:

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

预期的 TMonthCalendar 视图:

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

【问题讨论】:

  • 请先选择一种语言。 delphic++ 的答案可能不同。
  • 我在 C++ 中工作,但我可能会适应 delphi,所以更多的是一个理论问题。
  • “这更像是一个理论问题” 这将被拒绝为太宽泛,你必须具体。请删除 delphi 标签,甚至删除 c++ 和 delphi。您可能会询问如何控制该特定 vcl 组件的行为。
  • 嗯,这就是禁用将视图从几个月切换到几天的行为。经过几个小时的研究,我没有找到办法。无论如何,感谢您帮助编辑帖子。
  • 如果您不介意控件来回动画视图,请在单击和按键后发送 MCM_SETCURRENTVIEW。

标签: c++builder vcl c++builder-xe3


【解决方案1】:

在 Vista 之前,TMonthCalendar 包装的底层 Win32 MonthCal control 根本没有视图的概念,因此您无法在 XP 和更早版本中执行您所要求的操作,除非您找到支持的第三方日历你想要的那些 Windows 版本。

但是,在 Vista 及更高版本中,底层的 MonthCal 控件是可感知的(但 TMonthCalendar 本身不是)。您可以手动向TMonthCalendarHWND 发送MCM_SETCURRENTVIEW 消息以将其初始视图设置为MCMV_YEAR,并将其WindowProc 属性子类化以拦截CN_NOTIFY 消息(VCL 的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 或更高版本,请查看较新的 TCalendarViewTCalendarPicker 组件。它们都有一个DisplayMode 属性,您可以将其设置为TDisplayMode::dmYear 用于当前视图,以及一个On(Calendar)ChangeView 事件以响应用户的视图更改。

【讨论】:

  • 不幸的是,我使用的是 C++Builder XE3,它没有可用的组件。
  • 我想这是我能从我需要的东西中得到的最接近的结果,但仍然需要评估转换是否不会成为问题。无论如何,谢谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
  • 2019-06-14
  • 1970-01-01
  • 2018-06-26
  • 2021-08-15
相关资源
最近更新 更多