How do you programmatically mark a date in Delphi's TDateTimePicker's calendar?

前端 未结 2 1242
广开言路
广开言路 2020-12-03 18:58

When users click a DateTimePicker, set to drop down a calendar, I would like various dates (chosen via code I create) to highlighted in some way--colored background, bold fo

2条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-03 19:43

    Yes, you can do this. First, you have to initialize the control:

    const
      DTM_GETMCSTYLE = DTM_FIRST + 12;
      DTM_SETMCSTYLE = DTM_FIRST + 11;
    ...
    SendMessage(DateTimePicker1.Handle,
      DTM_SETMCSTYLE,
      0,
      SendMessage(DateTimePicker1.Handle, DTM_GETMCSTYLE, 0, 0) or MCS_DAYSTATE);
    

    (uses CommCtrl).

    Then you simply have to respond to the MCN_GETDAYSTATE notification. Either you can create your own TDateTimePicker descendant, or you can use an 'interceptor class'.

    type
      TDateTimePicker = class(ComCtrls.TDateTimePicker)    
      protected
        procedure WndProc(var Message: TMessage); override;
      end;
    
      ...
    
    procedure TDateTimePicker.WndProc(var Message: TMessage);
    var
      i: integer;
    begin
      inherited;
      case Message.Msg of
        WM_NOTIFY:
          with PNMDayState(Message.LParam)^ do
            if nmhdr.code = MCN_GETDAYSTATE then
            begin
              // The first visible day is SystemTimeToDateTime(stStart);
              // cDayState is probably three, because most often three months are
              // visible at the same time. Of course, the second of these is the
              // 'currently displayed month'.
              // Each month is represented by a DWORD (32-bit unsigned integer)
              // bitfield, where 0 means not bold, and 1 means bold.
              // For instance, the following code will select all days:
              for i := 0 to cDayState - 1 do
                PMonthDayState(Cardinal(prgDayState) + i*sizeof(TMonthDayState))^ := $FFFFFFFF;
            end;
      end;
    end;
    

    Another example: Assume that the current display consists of three months, and that you only want to select days in the 'currently displayed month', that is, in the middle month. Assume that you want every third day to be selected, starting with a selected day.

    Then you want to use the bitfields

    Month  Bitfield
    0      00000000000000000000000000000000
    1      01001001001001001001001001001001
    2      00000000000000000000000000000000
    

    which are

    Month  Bitfield
    0      $00000000
    1      $49249249
    2      $00000000
    

    in hexadecimal. So you do

    for i := 0 to cDayState - 1 do
      if i = 1 then
        PMonthDayState(cardinal(prgDayState) + i*sizeof(TMonthDayState))^ := $49249249
      else
        PMonthDayState(cardinal(prgDayState) + i*sizeof(TMonthDayState))^ := $00000000;
    

    Screenshot

提交回复
热议问题