본문 바로가기
delphi

TMonthCalendar 컴포넌트를 활용한 날짜 마킹 기법

by doran365 2024. 8. 8.

개요

TDateTimePicker 또는 TMonthCalendar 컴포넌트를 사용하여 특정 날짜를 강조하거나 마킹하는 기능은 사용자에게 중요한 일정을 시각적으로 표시하는 데 유용합니다. 본 기사에서는 기본 컴포넌트인 TMonthCalendar를 이용하여 원하는 날짜를 마킹(볼드체)하는 방법에 대해 자세히 알아보겠습니다.

TMonthCalendar의 "OnGetMonthInfo" 이벤트 활용

이 이벤트는 TMonthCalendar 컴포넌트에 새로운 월이 표시될 때 호출되며, 화면에 노출되는 일자에 대한 특정 속성을 초기화할 때 사용됩니다. 이를 통해 특정 날짜를 굵게 표시할 수 있습니다.

기본적인 날짜 마킹 방법

예를 들어, 표시된 달력의 1일과 8일을 굵게 표시하려면 다음과 같은 코드를 사용할 수 있습니다:

BoldDays([1, 8], MonthBoldInfo);

또는

unsigned bolddays[2] = {1, 2};
BoldDays(bolddays, MonthBoldInfo);

매월 다른 사용자 지정일자 마킹

위와 같이 처리하면 모든 월에 동일한 날짜가 굵게 표시됩니다. 하지만 일정 관리와 같이 매월 다른 특정 날을 마킹해야 하는 경우에는 약간의 추가 처리가 필요합니다.

OnGetMonthInfo 이벤트 처리

OnGetMonthInfo 이벤트는 달력의 월이 바뀔 때마다 발생합니다. 이 이벤트는 첫 번째는 이전 달, 두 번째는 이번 달, 세 번째는 다음 달에 대해 각각 호출됩니다. 따라서 현재 월만 선택하여 마킹 날짜 리스트를 얻고 표시해야 합니다. 이때 월만 넘어오므로 연도를 유추해야 합니다.

TMonthCalendar의 "BoldDays" 함수 사용

BoldDays 함수는 지정된 날짜들을 1~31 비트로 매핑하여 DWORD 값으로 MonthBoldInfo에 반환합니다.

MonthCalendar1.BoldDays([3, 21, 28], MonthBoldInfo); // Day 3, 21, 28

테스트 프로그램 구현

TEST 프로그램 결과

다음은 특정한 날짜를 굵게 표시하는 테스트 프로그램의 결과입니다.

TEST 프로그램 소스

unit uTestMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, CommCtrl;

type
  TForm1 = class(TForm)
    calendar: TMonthCalendar;
    procedure calendarGetMonthInfo(Sender: TObject; Month: Cardinal;
      var MonthBoldInfo: Cardinal);
  private
    function SetExistDateToCalenar(ADate: TDateTime): DWORD;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TArrBold = array of DWORD;
const
  testBoldDates : array[1..12] of array[0..6] of DWORD =
    ((1,3,4,6,7,8,9), (1,2,3,4,5,9,10), (4,6,8,15,19,20,21),
     (11,22,23,24,25,29,30), (11,12,13,14,15,19,20), (5,10,15,20,25,26,27),
     (2,4,6,8,10,12,14), (12,14,16,18,20,22,24), (1,3,5,7,5,9,10),
     (4,8,12,16,20,24,28), (1,2,4,8,16,21,22), (1,3,5,16,20,24,28));

var
  _LastMonth : integer;
  _LastYear : integer;
  _LastTickCount : Integer;
  _CallCountOfMonthInfo : Integer;

function CheckTickCount:Boolean;
var
  C:Cardinal;
begin
  C:=GetTickCount;
  Result: = _LastTickCount+100 < C;
  _LastTickCount := C;
end;

function TForm1.SetExistDateToCalenar(ADate: TDateTime) : DWORD;
var
  DayStates: array[0..2] of DWORD;
  mon : DWORD;
  arrDate : array of DWORD;
  yy, mm, dd : Word;
begin
  result := 0;

  DecodeDate(ADate, yy, mm, dd);
  if Length(testBoldDates[mm])>0 then
  begin
    calendar.BoldDays(testBoldDates[mm], mon);
    DayStates[1] := mon;
    result := mon;
  end
  else
  begin
    DayStates[1] := 0;
    result := 0;
  end;

  DayStates[0] := 0;
  DayStates[2] := 0;
  SendMessage(calendar.Handle, MCM_SETDAYSTATE, 3, longint(@DayStates));
end;

procedure TForm1.calendarGetMonthInfo(Sender: TObject; Month: Cardinal;
  var MonthBoldInfo: Cardinal);
var
  dd : TDateTime;
  tmp : string;
  Year, Mon, Day, YearMonth: Word;
begin
  if CheckTickCount Or ((Month<>_LastMonth+1) And Not ((_LastMonth=12) And (Month=1))) then
  begin
    DecodeDate((Sender As TMonthCalendar).Date, Year, Mon, Day);
    if Month>Mon then Dec(Year);
  end 
  else
  begin
    if _LastMonth=12
      then Year:=_LastYear+1
      else Year:=_LastYear;
  end;
  _LastMonth:=Month;
  _LastYear:=Year;

  Inc(_CallCountOfMonthInfo);
  if _CallCountOfMonthInfo=2 then 
  begin
    tmp := Format('%4d-%2d-01', [Year, Month]);
    tmp := StringReplace(tmp, ' ', '0', []);
    MonthBoldInfo := SetExistDateToCalenar(StrToDate(tmp));
  end
  else
    MonthBoldInfo := 0;

  if _CallCountOfMonthInfo = 3 then
    _CallCountOfMonthInfo := 0;
end;

end.

버튼 클릭 시 특정 날짜 마킹 예제

procedure TForm1.btnTestClick(Sender: TObject);
var
  monInfo : Cardinal;
  DayStates: array[0..2] of DWORD;
begin
  calendar.BoldDays([1,2,3,4,5,6,7,8,9], monInfo);
  DayStates[0] := 0;
  DayStates[1] := monInfo;
  DayStates[2] := 0;
  SendMessage(calendar.Handle, MCM_SETDAYSTATE, 3, longint(@DayStates));
end;

결론

TMonthCalendar 컴포넌트를 사용하여 특정 날짜를 마킹하는 방법은 사용자에게 중요한 일정을 강조하는 데 매우 유용합니다. OnGetMonthInfo 이벤트와 BoldDays 함수를 적절히 활용하면 각 월마다 다른 날짜를 효과적으로 표시할 수 있습니다. 이와 같은 기능을 구현하면 일정 관리와 같은 어플리케이션에서 큰 도움이 될 것입니다.