Как программно отметить дату в календаре TDateTimePicker в Delphi?

когда пользователи нажимают DateTimePicker, установите для выпадающего календаря, я хотел бы, чтобы различные даты (выбранные с помощью кода, который я создаю) были каким-то образом выделены-цветной фон, жирный шрифт, цветной шрифт, это не имеет значения. Я просто хочу отметить определенные даты. ... Как мне это сделать?

спасибо, как всегда!

2 ответов


Да, вы можете сделать это. Во-первых, вы должны инициализировать элемент управления:

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).

тогда вы просто должны ответить на MCN_GETDAYSTATE уведомления. Либо вы можете создать свой собственный TDateTimePicker потомок, или вы можете использовать 'перехватчик класса'.

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;

другой пример: Предположим, что текущий дисплей состоит из трех месяцев и что вы хотите выбрать только дни в "текущем отображаемом месяце", то есть в среднем месяце. Предположить что вы хотите, чтобы каждый третий день был выбран, начиная с выбранного дня.

тогда вы хотите использовать bitfields

Month  Bitfield
0      00000000000000000000000000000000
1      01001001001001001001001001001001
2      00000000000000000000000000000000

, которые

Month  Bitfield
0      000000
1      249249
2      000000

в шестнадцатеричном виде. Так ты

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

скриншот http://privat.rejbrand.se/datetimepick.png


OnGetMonthInfo событие выглядит на BoldDays массив для отметки дней в месяце.

извлечено из справки:

используйте BoldDays для кодирования дней текущего месяца, которые должны отображаться жирным шрифтом. Значение, возвращаемое BoldDays, может быть присвоено параметру MonthBoldInfo обработчика событий OnGetMonthInfo. Days-это массив целых чисел без знака, соответствующих дням, которые должны быть смелый.

посмотреть в справке.

Edit:

DateTimePicker.BoldDays доступен.

OnGetMonthInfo устарел в Delphi XE, вместо этого используйте OnGetMonthBoldInfo. Все еще не придумал лучший способ снова представить мероприятие.

редактирование 2 : Я действительно пошел с повторным введением события, но кажется, что сообщение windows не привязано к TDateTimePicker. Очень плохо. Я думаю, решение Andreas с переходом прямо к api сообщений windows является лучшим.