如何在Delphi的TCalendar组件中更改单元格颜色?

3

我需要在一个在Android和iOS上运行的应用程序中,更改TCalendar组件中某些单元格的颜色。我正在使用Delphi Seattle 10进行开发。是否有任何方法可以实现这一点?

1个回答

2

这段代码在Delphi XE5下可以运行。不幸的是,我没有Delphi 10来检查这段代码。

type
  TMyCalendar = class(TCalendar)
  private
    FSelectedDays: set of byte;
    procedure ApplyStyle; override;
  end;

...

{ TMyCalendar }

procedure TMyCalendar.ApplyStyle;
var
  i: word;
  LB: TListBox;
begin
  inherited;
  if FSelectedDays <> [] then
  begin
    LB := TListBox(TStyleObject(Children.Items[0]).Children.Items
      [TStyleObject(Children.Items[0]).Children.Count - 1]);
    for i := 0 to LB.Count - 1 do
      if (Assigned(LB.ItemByIndex(i))) and
        (StrToInt(LB.ItemByIndex(i).Text) in FSelectedDays) then
      begin
        LB.ItemByIndex(i).StyledSettings := LB.ItemByIndex(i).StyledSettings -
          [TStyledSetting.ssStyle];
        LB.ItemByIndex(i).Font.Style := LB.ItemByIndex(i).Font.Style +
          [TFontStyle.fsBold];
        With TRectangle.Create(LB.ItemByIndex(i)) do
        begin
          Parent := LB.ItemByIndex(i);
          Align := TAlignLayout.alClient;
          Fill.Color := TAlphaColorRec.Red;
          Opacity := 0.5;
        end;
      end;
  end;
end;

然后创建一个TMyCalendar类的实例:

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    MyCalendar: TMyCalendar;
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyCalendar := TMyCalendar.Create(Self);
  MyCalendar.Parent := Self;
  MyCalendar.Position.X := 1;
  MyCalendar.Position.Y := 1;
  MyCalendar.FSelectedDays := [9, 11]; // <-set other days here and check the month
end;

附加

有另外一种方法可以访问表示月份天数列表的私有变量FDays。您可以声明一个 class helper,在属性 Days 中公开它:

  TMyCalendarHelper = class helper for TCalendar
    function GetDays: TListBox;
    procedure SetDays(const Value: TListBox);
    property Days: TListBox read GetDays write SetDays;
  end;

...

{ TMyCalendarHelper }

function TMyCalendarHelper.GetDays: TListBox;
begin
  result := Self.FDays;
end;

procedure TMyCalendarHelper.SetDays(const Value: TListBox);
begin
  Self.FDays := Value;
end;

然后在类的子类中,您可以使用 Days 属性来控制该 ListBox 及其项。

procedure TMyCalendar.ApplyStyle;
var
  i: word;
//  LB: TListBox;//<-you do not need it any more
begin
  inherited;
  if FSelectedDays <> [] then
  begin
//    LB := TListBox(TStyleObject(Children.Items[0]).Children.Items//<-you do not need it
//      [TStyleObject(Children.Items[0]).Children.Count - 1]);//<-you do not need it
    for i := 0 to Days.Count - 1 do
      if (Assigned(Days.ItemByIndex(i))) and
        (StrToInt(Days.ItemByIndex(i).Text) in FSelectedDays) then
      begin
        Days.ItemByIndex(i).StyledSettings := Days.ItemByIndex(i).StyledSettings -
          [TStyledSetting.ssStyle];
        Days.ItemByIndex(i).Font.Style := Days.ItemByIndex(i).Font.Style +
          [TFontStyle.fsBold];
        //Do other things you want with Days.ItemByIndex(i)

追加 2 有可能修正天数的绘制方式。

  TMyCalendar = class(TCalendar)
  private
    FSelectedDays: set of byte;
    procedure PaintChildren; override;
  end;
procedure TMyCalendar.PaintChildren;
var
  i: word;
  TMPC: TAlphaColor;
  R: TRectF;
begin
  inherited;
  if FSelectedDays <> [] then
  begin
    for i := 0 to Days.Count - 1 do
      if (Assigned(Days.ItemByIndex(i))) and
        (StrToInt(Days.ItemByIndex(i).Text) in FSelectedDays) then
      begin
        TMPC := Days.ItemByIndex(i).Canvas.Fill.Color;
        R := Days.ItemByIndex(i).AbsoluteRect;
        R.Inflate(Position.X, Position.Y, -Position.X, -Position.Y);
        Days.ItemByIndex(i).Canvas.BeginScene;
        Days.ItemByIndex(i).Canvas.Fill.Color := TAlphaColorRec.Red;
        Days.ItemByIndex(i).Canvas.FillRect(R, 0, 0, [], 0.5);
        Days.ItemByIndex(i).Canvas.EndScene;
        Days.ItemByIndex(i).Canvas.Fill.Color := TMPC;
      end;
  end;
end; 

@elcharlie,我已经附加了另一种访问FDays私有变量的方法。 - asd-tm
不幸的是,它在我的 Delphi Seattle 上无法工作,显示日历不显示日期的单元格 :( - elcharlie
@elcharlie 请明确指出哪里出了问题。你能够控制 Days.ItemByIndex(i) 吗?Assigned(Days)=true 吗? - asd-tm
抱歉,在Delphi 10中,TCalendar对象中没有名为FDays的属性。 - elcharlie
最终,我让它正常工作了。最后,我按照你一开始说的做法,使用了助手类,而这是我之前无法做到的。非常感谢你的帮助。 - elcharlie
@elcharlie 不用谢,看看我回答的第三次编辑。另一种标记日期的方法是通过重写 PaintChildren 方法实现的。我发现它比使用 TRectangle 创建的方法有一些优点。您无需添加额外的代码来处理点击事件。 - asd-tm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接