カレンダーコンポーネントの文字色を設定

# カレンダーコンポーネントの文字色を設定（土曜日・日曜日・祝日）

カレンダーコンポーネントは、デフォルトのままでは文字の色がすべて同じだったりしますが、土曜日・日曜日・祝日など文字の色を設定したい場合が多いと思いますので、今回はいくつかのコンポーネントで文字色の設定を試したいと思います。

なお、休日の判定は、
[Delphi で "指定した日が祝日かどうか" を調べる - Qiita](https://qiita.com/ht_deko/items/a0cbbbd899c1c016ae67)
のIsSpecialHoliday関数を使用しています。



## TCalendarPicker、TCalendarView の場合

TCalendarPicker、TCalendarViewは、Delphi 10.1 Update2で追加されました。

![CalendarView_2020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318490/5e497411-af62-9425-58b1-79c49a6357a3.png)


土曜日は青、日曜日や祝日は赤の文字で表示したい場合、OnDrawDayItemイベントで、

```pascal:Unit1.pas
procedure TForm1.CalendarView1DrawDayItem(Sender: TObject;
  DrawParams: TDrawViewInfoParams; CalendarViewViewInfo: TCellItemViewInfo);
var
    S: String;
begin
    if DayOfWeek(CalendarViewViewInfo.Date) = 1 then
        DrawParams.ForegroundColor := clRed;
    if DayOfWeek(CalendarViewViewInfo.Date) = 7 then
        DrawParams.ForegroundColor := clBlue;

    if IsSpecialHoliday(CalendarViewViewInfo.Date, S) then
        DrawParams.ForegroundColor := clRed;
end;
```

のような感じで、文字の色を変更します。

参照：[カレンダー ビューの利用 - RAD Studio](http://docwiki.embarcadero.com/RADStudio/Rio/ja/%E3%82%AB%E3%83%AC%E3%83%B3%E3%83%80%E3%83%BC_%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AE%E5%88%A9%E7%94%A8)


## TRzDateTimeEdit、TRzCalendarの場合

TRzDateTimeEdit、TRzCalendarは、Konopka Signature VCL Controls 6.2.3に含まれており、GetItパッケージマネージャ－にて無償で入手できます。
（10.3 RioのGetItでは「Bonus KSVC 6.2.3」と表記されてます。）

![RzCalendar2020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318490/5d0b9b7d-1dbf-a972-faca-1f3a739ab9db.png)


土曜日は青、日曜日や祝日は赤の文字で表示したい場合、OnGetDayFormatイベントで文字色を指定します。

```pascal:Unit1.pas
  TForm1 = class(TForm)
    RzDateTimeEdit1: TRzDateTimeEdit;
    RzCalendar1: TRzCalendar;

    procedure FormCreate(Sender: TObject);
    procedure RzDateTimeEdit1GetDayFormat(Sender: TObject; DayDate: TDateTime;
      Year, Month, Day: Word; var DayColor, DayFontColor: TColor;
      var DayFontStyle: TFontStyles);
    procedure RzCalendar1GetDayFormat(Sender: TObject; DayDate: TDateTime; Year,
      Month, Day: Word; var DayColor, DayFontColor: TColor;
      var DayFontStyle: TFontStyles);
    procedure RzDateTimeEdit1ViewDateChange(Sender: TObject; ViewDate: TDateTime);
  private
    { Private 宣言 }
    CurrentViewDate: TDateTime;    // RzDateTimeEdit1用
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    with RzDateTimeEdit1 do
    begin
        EditType := etDate;

        CaptionClearBtn := 'クリア';
        CaptionTodayBtn := '今日';
    end;

    with RzCalendar1 do
    begin
        //CaptionClearBtn := 'クリア';
        CaptionTodayBtn := '今日';

        Elements := Elements - [ceClearButton];
    end;

    CurrentViewDate := 0;
end;

// RzDateTimeEdit:OnGetDayFormatイベント
procedure TForm1.RzDateTimeEdit1GetDayFormat(Sender: TObject; DayDate: TDateTime;
  Year, Month, Day: Word; var DayColor, DayFontColor: TColor; var DayFontStyle: TFontStyles);
var
    S: String;
    isSameYMView: Boolean;
begin
    isSameYMView := SameDate(StartOfTheMonth(DayDate), StartOfTheMonth(CurrentViewDate));
    // TRzCalendarのViewDateプロパティに該当するものがないのでViewDateChangeイベントで取得したViewDateで比較

    if (DayOfWeek(DayDate) = 1) or IsSpecialHoliday(DayDate, S) then    // 日曜日か祝日
    begin
        DayFontColor := clRed;
        if not isSameYMView then
            DayFontColor := RGB(255, 144, 144);
    end
    else if DayOfWeek(DayDate) = 7 then                                 // 土曜日
    begin
        DayFontColor := clBlue;
        if not isSameYMView then
            DayFontColor := RGB(128, 128, 255);
    end;
end;

// RzCalendar:OnGetDayFormatイベント
procedure TForm1.RzCalendar1GetDayFormat(Sender: TObject; DayDate: TDateTime;
  Year, Month, Day: Word; var DayColor, DayFontColor: TColor; var DayFontStyle: TFontStyles);
var
    S: String;
    isSameYMView: Boolean;
begin
    isSameYMView := SameDate(StartOfTheMonth(DayDate), StartOfTheMonth(TRzCalendar(Sender).ViewDate));

    if (DayOfWeek(DayDate) = 1) or IsSpecialHoliday(DayDate, S) then    // 日曜日か祝日
    begin
        DayFontColor := clRed;
        if not isSameYMView then
            DayFontColor := RGB(255, 144, 144);
    end
    else if DayOfWeek(DayDate) = 7 then                                 // 土曜日
    begin
        DayFontColor := clBlue;
        if not isSameYMView then
            DayFontColor := RGB(128, 128, 255);
    end;
end;

procedure TForm1.RzDateTimeEdit1ViewDateChange(Sender: TObject; ViewDate: TDateTime);
begin
    CurrentViewDate := ViewDate;
end;
```

TRzCalendarではViewDateプロパティでカレンダーの年月が確認しているのですが、TRzDateTimeEditにはViewDateプロパティがないので、OnViewDateChangeイベントで取得したViewDateの値でカレンダーの年月を確認しています。

## TCalendar（VCL）の場合

TCalendarには、文字色の設定ができるようなイベントがないのですが、TCalendarを継承して、DrawCellメソッドをoverrideすることで、文字色などを設定することができます。

![CalendarStd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318490/b8e818b9-7b0e-ad6f-be48-9ac8cc1f8395.png)


```pascal:CalendarEx.pas
type
  TCalendarEx = class(TCalendar)
    
  protected
    { Protected 宣言 }
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
    
  end;

implementation

procedure TCalendarEx.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
	S: String;
	ADay: Integer;
begin
	if not (gdFixed in AState) then
	begin
		if (StartOfWeek + ACol) mod 7 = 0 then	// 日曜日
			Canvas.Font.Color := clRed;
		if (StartOfWeek + ACol) mod 7 = 6 then	// 土曜日
			Canvas.Font.Color := clBlue;
		
		ADay := StrToIntDef(CellText[ACol, ARow], 0);
		if (ADay > 0) and IsSpecialHoliday(EncodeDate(Year, Month, ADay), S) then	// 祝日
			Canvas.Font.Color := clRed;
	end;

	inherited DrawCell(ACol, ARow, ARect, AState)
end;
```


## 最後に

Delphiに標準搭載のコンポーネントには、他にも、VCLはTDateTimePicker・TMonthCalendar、FMXはTDateEdit・TCalendarがあるのですが、これらに関しては、土曜日・日曜日・祝日などの文字色の設定の方法はわかりませんでした・・