| 
 //继承自TCustomGrid并带有CheckBox的日历  
{ 
   修改的日历组件 
   加入了CheckBox的功能 
   主要是用于我写的一个电视广告合同串联编排的管理软件 
   QQ:250198418 
   Email:lqcros@126.com 
 
} 
unit SampleCalendar; 
 
interface 
 
uses 
  SysUtils, Classes, Controls, Grids, Windows, Messages, StdCtrls, Graphics, Forms; 
 
type 
  TSampleCalendar = class(TCustomGrid) 
  private 
    { Private declarations } 
    FSelArray: Array of boolean;   //记录每一个单元格的Checked状态; 
    FSelectColor: TColor;          //选择单元格颜色 
    FDate: TDateTime; 
    FMonthOffset: integer; 
    FOnChange: TNotifyEvent; 
 
    procedure SetCalendarDate(Value: TDateTime); 
    function  GetDateElement(Index: integer): integer;                       //   note   the   Index   parameter 
    procedure SetDateElement(Index: integer; Value: integer); 
    function  GetChecked(Index: integer): boolean; 
    procedure SetChecked(Index: integer; Value: boolean); 
    procedure SetSelectColor(Value: TColor); 
  protected 
    { Protected declarations } 
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; 
      AState: TGridDrawState);override; 
    procedure WMSize(var Msg: TWMSize); message WM_SIZE; 
    procedure UpdateCalendar; 
    function  DayNum(ACol: integer; ARow: integer): integer; 
    procedure NextMonth; 
    procedure PrevMonth; 
    procedure NextYear; 
    procedure PrevYear; 
    procedure Change; 
    function SelectCell(ACol, ARow: Longint): Boolean; override; 
 
    procedure KeyDown(var Key: Word; Shift: TShiftState); override; 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); override; 
//    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; 
//      X, Y: Integer); override; 
 
  public 
    { Public declarations } 
 
    constructor Create(AOwner: TComponent); override; 
 
//    procedure Click; 
    property  CalendarDate: TDateTime read FDate write SetCalendarDate; 
    property  Day:   integer index 3 read GetDateElement write SetDateElement; 
    property  Month: integer index 2 read GetDateElement write SetDateElement; 
    property  Year:  integer index 1 read GetDateElement write SetDateElement; 
    property  Checked[Index: integer]: boolean read GetChecked write SetChecked;   //设置或提取单元格状态 
  published 
    { Published declarations } 
    property  SelectColor: TColor read FSelectColor write SetSelectColor default clBtnFace; 
    property  Align;                                         //   publish   properties 
    property  BorderStyle; 
    property  Color; 
    property  FixedColor; 
    property  Font; 
    property  GridLineWidth; 
    property  ParentColor; 
    property  ParentFont; 
    property  Options; 
 
    property  OnClick;                                       //   publish   events 
    property  OnDblClick; 
    property  OnDragDrop; 
    property  OnDragOver; 
    property  OnEndDrag; 
    property  OnKeyDown; 
    property  OnKeyPress; 
    property  OnKeyUp; 
 
    property OnChange: TNotifyEvent read FOnChange write FOnChange; 
  end; 
 
var 
  ShortDayNames1: array[1..7] of string; 
 
procedure Register; 
 
implementation 
 
procedure Register; 
begin 
  RegisterComponents('Samples', [TSampleCalendar]); 
end; 
 
constructor TSampleCalendar.Create(AOwner: TComponent); 
 
begin 
    inherited; 
//  初始化日历组件的外观 
    ColCount   :=   7; 
    RowCount   :=   7; 
    RowHeights[0] := 35; 
    FixedCols  :=   0; 
    FixedRows  :=   1; 
    BorderStyle := bsNone; 
    Color      := clBtnFace; 
    FixedColor := $00ACACAC; 
    SelectColor := $00ACACAC; 
    ScrollBars := ssNone; 
    Options := [goVertLine,goHorzLine,goDrawFocusSelected]; 
 
    FDate      :=  Now; 
 
    SetLength(FSelArray, 31); 
 
    ShortDayNames1[1] := '日'; 
    ShortDayNames1[2] := '一'; 
    ShortDayNames1[3] := '二'; 
    ShortDayNames1[4] := '三'; 
    ShortDayNames1[5] := '四'; 
    ShortDayNames1[6] := '五'; 
    ShortDayNames1[7] := '六'; 
 
    UpdateCalendar(); 
 
end; 
 
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime); 
var 
    i: integer; 
begin 
    FDate   :=   Value;                                             //   Set   the   new   date   value 
 
    for i := 0 to 31 do 
    FSelArray := false; 
 
    //Refresh();                                                 //   Update   the   onscreen   image 
    UpdateCalendar();                                       //   this   previously   called   Refresh 
    Change();                                                       //   this   is   the   only   new   statement    
end; 
 
function  TSampleCalendar.GetDateElement(Index: integer): Integer;                       //   note   the   Index   parameter 
var 
    AYear,   AMonth,   ADay: word; 
begin 
    DecodeDate(FDate, AYear,   AMonth,   ADay);                         //   break   encoded   date   into   elements 
    case Index of 
        1:   result   :=   AYear; 
        2:   result   :=   AMonth; 
        3:   result   :=   ADay; 
    else 
        result := -1; 
    end; 
end; 
 
procedure TSampleCalendar.SetDateElement(Index: integer; Value: integer); 
var 
    AYear, AMonth, ADay: word; 
begin 
    if (Value   >   0) then                                                                    //   all   elements   must   be   positive 
    begin 
        DecodeDate(FDate, AYear, AMonth, ADay);       //   get   current   date   elements 
        case Index of 
            1: AYear  := Value; 
            2: AMonth := Value; 
            3: ADay   := Value; 
        else 
            exit; 
        end; 
    end; 
    FDate   :=   EncodeDate(AYear,   AMonth,   ADay);                   //   encode   the   modified   date 
    //Refresh();                                                                         //   update   the   visible   calendar 
    UpdateCalendar();                                                               //   this   previously   called   Refresh 
    Change();                                                                               //   this   is   new 
end; 
 
procedure TSampleCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect; 
      AState: TGridDrawState); 
var 
    TheText: string; 
    TempDay: integer; 
    Checked: boolean; 
    CheckRect: TRect; 
const 
    CheckBox : array[Boolean] of Integer = (DFCS_BUTTONCHECK, 
    DFCS_BUTTONCHECK or DFCS_CHECKED); 
begin 
    if gdSelected in AState then 
    begin 
        Canvas.Brush.Color := SelectColor; 
        Canvas.FillRect(ARect); 
    end 
    else 
    begin 
        if (ARow >= FixedRows) and (ACol >= FixedCols) then 
        Canvas.Brush.Color := Color 
        else 
        Canvas.Brush.Color := FixedColor;   // 
        Canvas.FillRect(ARect); 
    end; 
 
    if (ARow = 0) then 
        TheText := ShortDayNames1[ACol + 1] 
    else 
    begin 
        TheText := ''; 
        TempDay := DayNum(ACol, ARow);                                       //   DayNum   is   defined   later 
        if (TempDay <> -1) then 
        begin 
            if TempDay <= 9 then 
            TheText := ' ' + IntToStr(TempDay)   //日期右对齐,美观 
            else 
            TheText := IntToStr(TempDay); 
        end; 
    end; 
 
    CheckRect.Top    := ARect.Top  + (ARect.Bottom - ARect.Top - 17) div 2; 
    CheckRect.Bottom := CheckRect.Top  + 16; 
    CheckRect.Left   := ARect.Left + (ARect.Right - ARect.Left - Canvas.TextWidth('11') - 16) div 2; 
    CheckRect.Right  := CheckRect.Left + 16; 
 
    if (ARow >= FixedRows) and (ACol >= FixedCols) then 
    begin 
        if TheText <> '' then 
        begin 
            Checked := FSelArray[StrToInt(TheText)]; 
            Canvas.FillRect(CheckRect); 
            DrawFrameControl(Canvas.Handle, CheckRect, DFC_BUTTON, CheckBox[Checked]); 
        end; 
    end; 
 
    if (ARow >= FixedRows) and (ACol >= FixedCols) then 
    begin 
        CheckRect.Left := CheckRect.Left + 18; 
        CheckRect.Top  := ARect.Top + (ARect.Bottom - ARect.Top - Canvas.TextHeight(TheText)) div 2; 
        CheckRect.Bottom := Arect.Bottom; 
        CheckRect.Right := Arect.Right -3; 
 
        DrawText(Canvas.Handle, pchar(TheText), Length(TheText), CheckRect, DT_LEFT); 
    end 
    else 
    begin 
        CheckRect := ARect; 
        CheckRect.Top := ARect.Top + (ARect.Bottom - ARect.Top - Canvas.TextHeight(TheText)) div 2; 
        DrawText(Canvas.Handle, pchar(TheText), Length(TheText), CheckRect, DT_CENTER); 
    end; 
 
end; 
 
procedure TSampleCalendar.WMSize(var Msg: TWMSize); 
var 
    GridLines: integer; 
begin 
    GridLines        := 6 * GridLineWidth;                                     //   calculated   combined   size   of   all   lines 
    DefaultColWidth  := (Msg.Width  - GridLines) div 7;         //   set   new   default   cell   width 
    DefaultRowHeight := (Msg.Height - GridLines) div 7;     //   and   cell   height 
    inherited; 
end; 
 
procedure TSampleCalendar.UpdateCalendar; 
var 
    AYear, AMonth, ADay: word; 
    FirstDate: TDateTime; 
begin 
    if (FDate <> 0) then                                                     //   only   calculate   offset   if   date   is   valid 
    begin 
        DecodeDate(FDate, AYear,   AMonth,   ADay);     //   get   elements   of   date 
        FirstDate    := EncodeDate(AYear,   AMonth,   1);       //   date   of   the   first 
        FMonthOffset := 2 - DayOfWeek(FirstDate);     //   generate   the   offset   into   the   grid 
        Row := (ADay - FMonthOffset) div 7 + 1; 
        Col := (ADay - FMonthOffset) mod 7; 
    end; 
    Refresh();                                                                         //   always   repaint   the   control 
end; 
 
function TSampleCalendar.DayNum(ACol: integer; ARow: integer): integer; 
begin 
    Result := FMonthOffset + ACol + (ARow - 1) * 7;               //   calculate   day   for   this   cell 
 
    if ((result < 1) or (result > MonthDays[IsLeapYear(Year)][Month])) then 
    result := -1;       //   return   -1   if   invalid 
end; 
 
procedure TSampleCalendar.NextMonth; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, 1), AYear, AMonth, ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.PrevMonth; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, -1), AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.NextYear; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, 12), AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.PrevYear; 
var 
    AYear, AMonth, ADay: word; 
    i: integer;     
begin 
    DecodeDate(IncMonth(CalendarDate,   -12),   AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.Change; 
begin 
  if Assigned(FOnChange) then FOnChange(Self) 
end; 
 
function TSampleCalendar.SelectCell(ACol, ARow: Longint): Boolean; 
begin 
  if (DayNum(ACol,ARow) = -1)  then 
  Result := false 
  else 
  Result := true; 
//    Result := inherited(ACol, ARow); 
end; 
{ 
procedure TSampleCalendar.Click; 
var 
    TempDay: integer; 
begin 
    TempDay := DayNum(Col, Row);                         // get   the   day   number   for   the   clicked   cell 
    if (TempDay <>  -1) then  Day := TempDay;            // change   day   if   valid 
end; 
} 
procedure TSampleCalendar.KeyDown(var Key: Word; Shift: TShiftState); 
var 
    TempDay: integer; 
begin 
  inherited KeyDown(Key, Shift); 
  if Key = VK_SPACE then 
  begin 
    TempDay := DayNum(Col, Row); 
    if TempDay <> -1 then 
    begin 
        FSelArray[TempDay] := Not FSelArray[TempDay]; 
        Day := TempDay; 
    end; 
  end; 
  Refresh(); 
end; 
 
procedure TSampleCalendar.MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); 
var 
    TempDay: integer; 
begin 
  inherited MouseDown(Button, Shift, X, Y); 
  if Button = mbLeft then 
  begin 
    TempDay := DayNum(Col, Row); 
    if TempDay <> -1 then 
    begin 
        FSelArray[TempDay] := Not FSelArray[TempDay]; 
        Day := TempDay; 
    end; 
  end; 
  Refresh(); 
end; 
{ 
 
procedure TSampleCalendar.MouseUp(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); 
begin 
  try 
    case FGridState of 
      gsSelecting: 
        begin 
          Click; 
        end; 
    end; 
    inherited MouseUp(Button, Shift, X, Y); 
  finally 
    FGridState := gsNormal; 
  end; 
end; 
} 
 
function TSampleCalendar.GetChecked(Index: integer): boolean; 
begin 
    Result := false; 
    if (Index >= 1) and (Index <=31) then 
    Result := FSelArray[Index]; 
end; 
 
procedure TSampleCalendar.SetChecked(Index: integer; Value: boolean); 
begin 
    if (Index >= 1) and (Index <=31) then 
    if FSelArray[Index] <> Value then 
    begin 
        FSelArray[Index] := Value; 
    end; 
end; 
 
procedure TSampleCalendar.SetSelectColor(Value: TColor); 
begin 
  if FSelectColor <> Value then 
  begin 
    FSelectColor := Value; 
    Refresh(); 
  end; 
end; 
 
end.  
 
 
 
2007-8-18 22:05:46     
修改笔记  发表评语???      
 
2007-8-20 10:05:27    加入了,Enabled 功能{ 
   修改的日历组件 
   加入了CheckBox的功能 
   主要是用于我写的一个电视广告合同串联编排的管理软件 
   QQ:250198418 
   Email:lqcros@126.com 
 
} 
unit SampleCalendar; 
 
interface 
 
uses 
  SysUtils, Classes, Controls, Grids, Windows, Messages, StdCtrls, Graphics, Forms; 
 
type 
  TSampleCalendar = class(TCustomGrid) 
  private 
    { Private declarations } 
    FSelArray: Array of boolean;   //记录每一个单元格的Checked状态; 
    FSelectColor: TColor;          //选择单元格颜色 
    FDate: TDateTime; 
    FMonthOffset: integer; 
    FOnChange: TNotifyEvent; 
 
    procedure SetCalendarDate(Value: TDateTime); 
    function  GetDateElement(Index: integer): integer;                       //   note   the   Index   parameter 
    procedure SetDateElement(Index: integer; Value: integer); 
    function  GetChecked(Index: integer): boolean; 
    procedure SetChecked(Index: integer; Value: boolean); 
    procedure SetSelectColor(Value: TColor); 
    procedure CMEnabledChanged( var Msg: TMessage ); message cm_EnabledChanged; 
 
  protected 
    { Protected declarations } 
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; 
      AState: TGridDrawState);override; 
    procedure WMSize(var Msg: TWMSize); message WM_SIZE; 
    procedure UpdateCalendar; 
    function  DayNum(ACol: integer; ARow: integer): integer; 
    procedure NextMonth; 
    procedure PrevMonth; 
    procedure NextYear; 
    procedure PrevYear; 
    procedure Change; 
    function SelectCell(ACol, ARow: Longint): Boolean; override; 
 
    procedure KeyDown(var Key: Word; Shift: TShiftState); override; 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); override; 
//    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; 
//      X, Y: Integer); override; 
 
  public 
    { Public declarations } 
 
    constructor Create(AOwner: TComponent); override; 
 
//    procedure Click; 
    property  CalendarDate: TDateTime read FDate write SetCalendarDate; 
    property  Day:   integer index 3 read GetDateElement write SetDateElement; 
    property  Month: integer index 2 read GetDateElement write SetDateElement; 
    property  Year:  integer index 1 read GetDateElement write SetDateElement; 
    property  Checked[Index: integer]: boolean read GetChecked write SetChecked;   //设置或提取单元格状态 
  published 
    { Published declarations } 
    property  SelectColor: TColor read FSelectColor write SetSelectColor default clBtnFace; 
    property  Align;                                         //   publish   properties 
    property  BorderStyle; 
    property  Color; 
    property  FixedColor; 
    property  Font; 
    property  GridLineWidth; 
    property  ParentColor; 
    property  ParentFont; 
    property  Options; 
    property  Enabled; 
 
    property  OnClick;                                       //   publish   events 
    property  OnDblClick; 
    property  OnDragDrop; 
    property  OnDragOver; 
    property  OnEndDrag; 
    property  OnKeyDown; 
    property  OnKeyPress; 
    property  OnKeyUp; 
 
    property OnChange: TNotifyEvent read FOnChange write FOnChange; 
  end; 
 
var 
  ShortDayNames1: array[1..7] of string; 
 
procedure Register; 
 
implementation 
 
procedure Register; 
begin 
  RegisterComponents('Samples', [TSampleCalendar]); 
end; 
 
constructor TSampleCalendar.Create(AOwner: TComponent); 
 
begin 
    inherited; 
//  初始化日历组件的外观 
    ColCount   :=   7; 
    RowCount   :=   7; 
    RowHeights[0] := 35; 
    FixedCols  :=   0; 
    FixedRows  :=   1; 
    BorderStyle := bsNone; 
    Color      := clBtnFace; 
    FixedColor := $00ACACAC; 
    SelectColor := $00ACACAC; 
    ScrollBars := ssNone; 
    Enabled    := true; 
    Options := [goVertLine,goHorzLine,goDrawFocusSelected]; 
 
    FDate      :=  Now; 
 
    SetLength(FSelArray, 31); 
 
    ShortDayNames1[1] := '日'; 
    ShortDayNames1[2] := '一'; 
    ShortDayNames1[3] := '二'; 
    ShortDayNames1[4] := '三'; 
    ShortDayNames1[5] := '四'; 
    ShortDayNames1[6] := '五'; 
    ShortDayNames1[7] := '六'; 
 
    UpdateCalendar(); 
 
end; 
 
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime); 
var 
    i: integer; 
begin 
    FDate   :=   Value;                                             //   Set   the   new   date   value 
 
    for i := 0 to 31 do 
    FSelArray := false; 
 
    //Refresh();                                                 //   Update   the   onscreen   image 
    UpdateCalendar();                                       //   this   previously   called   Refresh 
    Change();                                                       //   this   is   the   only   new   statement    
end; 
 
function  TSampleCalendar.GetDateElement(Index: integer): Integer;                       //   note   the   Index   parameter 
var 
    AYear,   AMonth,   ADay: word; 
begin 
    DecodeDate(FDate, AYear,   AMonth,   ADay);                         //   break   encoded   date   into   elements 
    case Index of 
        1:   result   :=   AYear; 
        2:   result   :=   AMonth; 
        3:   result   :=   ADay; 
    else 
        result := -1; 
    end; 
end; 
 
procedure TSampleCalendar.SetDateElement(Index: integer; Value: integer); 
var 
    AYear, AMonth, ADay: word; 
begin 
    if (Value   >   0) then                                                                    //   all   elements   must   be   positive 
    begin 
        DecodeDate(FDate, AYear, AMonth, ADay);       //   get   current   date   elements 
        case Index of 
            1: AYear  := Value; 
            2: AMonth := Value; 
            3: ADay   := Value; 
        else 
            exit; 
        end; 
    end; 
    FDate   :=   EncodeDate(AYear,   AMonth,   ADay);                   //   encode   the   modified   date 
    //Refresh();                                                                         //   update   the   visible   calendar 
    UpdateCalendar();                                                               //   this   previously   called   Refresh 
    Change();                                                                               //   this   is   new 
end; 
 
procedure TSampleCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect; 
      AState: TGridDrawState); 
var 
    TheText: string; 
    TempDay: integer; 
    Checked: boolean; 
    CheckRect: TRect; 
const 
    CheckBox : array[Boolean] of Integer = (DFCS_BUTTONCHECK, 
    DFCS_BUTTONCHECK or DFCS_CHECKED); 
begin 
    if gdSelected in AState then 
    begin 
        Canvas.Brush.Color := SelectColor; 
        Canvas.FillRect(ARect); 
    end 
    else 
    begin 
        if (ARow >= FixedRows) and (ACol >= FixedCols) then 
        Canvas.Brush.Color := Color 
        else 
        Canvas.Brush.Color := FixedColor;   // 
        Canvas.FillRect(ARect); 
    end; 
 
    if (ARow = 0) then 
        TheText := ShortDayNames1[ACol + 1] 
    else 
    begin 
        TheText := ''; 
        TempDay := DayNum(ACol, ARow);                                       //   DayNum   is   defined   later 
        if (TempDay <> -1) then 
        begin 
            if TempDay <= 9 then 
            TheText := ' ' + IntToStr(TempDay)   //日期右对齐,美观 
            else 
            TheText := IntToStr(TempDay); 
        end; 
    end; 
 
    CheckRect.Top    := ARect.Top  + (ARect.Bottom - ARect.Top - 17) div 2; 
    CheckRect.Bottom := CheckRect.Top  + 16; 
    CheckRect.Left   := ARect.Left + (ARect.Right - ARect.Left - Canvas.TextWidth('11') - 16) div 2; 
    CheckRect.Right  := CheckRect.Left + 16; 
 
    if (ARow >= FixedRows) and (ACol >= FixedCols) then 
    begin 
        if TheText <> '' then 
        begin 
            Checked := FSelArray[StrToInt(TheText)]; 
            Canvas.FillRect(CheckRect); 
            if Enabled then 
            DrawFrameControl(Canvas.Handle, CheckRect, DFC_BUTTON, CheckBox[Checked]) 
            else 
            DrawFrameControl(Canvas.Handle, CheckRect, DFC_BUTTON, CheckBox[Checked] or DFCS_INACTIVE); 
        end; 
    end; 
 
    if (ARow >= FixedRows) and (ACol >= FixedCols) then 
    begin 
        CheckRect.Left := CheckRect.Left + 18; 
        CheckRect.Top  := ARect.Top + (ARect.Bottom - ARect.Top - Canvas.TextHeight(TheText)) div 2; 
        CheckRect.Bottom := Arect.Bottom; 
        CheckRect.Right := Arect.Right -3; 
 
        DrawText(Canvas.Handle, pchar(TheText), Length(TheText), CheckRect, DT_LEFT); 
    end 
    else 
    begin 
        CheckRect := ARect; 
        CheckRect.Top := ARect.Top + (ARect.Bottom - ARect.Top - Canvas.TextHeight(TheText)) div 2; 
        DrawText(Canvas.Handle, pchar(TheText), Length(TheText), CheckRect, DT_CENTER); 
    end; 
 
end; 
 
procedure TSampleCalendar.WMSize(var Msg: TWMSize); 
var 
    GridLines: integer; 
begin 
    GridLines        := 6 * GridLineWidth;                                     //   calculated   combined   size   of   all   lines 
    DefaultColWidth  := (Msg.Width  - GridLines) div 7;         //   set   new   default   cell   width 
    DefaultRowHeight := (Msg.Height - GridLines) div 7;     //   and   cell   height 
    inherited; 
end; 
 
procedure TSampleCalendar.UpdateCalendar; 
var 
    AYear, AMonth, ADay: word; 
    FirstDate: TDateTime; 
begin 
    if (FDate <> 0) then                                                     //   only   calculate   offset   if   date   is   valid 
    begin 
        DecodeDate(FDate, AYear,   AMonth,   ADay);     //   get   elements   of   date 
        FirstDate    := EncodeDate(AYear,   AMonth,   1);       //   date   of   the   first 
        FMonthOffset := 2 - DayOfWeek(FirstDate);     //   generate   the   offset   into   the   grid 
        Row := (ADay - FMonthOffset) div 7 + 1; 
        Col := (ADay - FMonthOffset) mod 7; 
    end; 
    Refresh();                                                                         //   always   repaint   the   control 
end; 
 
function TSampleCalendar.DayNum(ACol: integer; ARow: integer): integer; 
begin 
    Result := FMonthOffset + ACol + (ARow - 1) * 7;               //   calculate   day   for   this   cell 
 
    if ((result < 1) or (result > MonthDays[IsLeapYear(Year)][Month])) then 
    result := -1;       //   return   -1   if   invalid 
end; 
 
procedure TSampleCalendar.NextMonth; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, 1), AYear, AMonth, ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.PrevMonth; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, -1), AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.NextYear; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, 12), AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.PrevYear; 
var 
    AYear, AMonth, ADay: word; 
    i: integer;     
begin 
    DecodeDate(IncMonth(CalendarDate,   -12),   AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.Change; 
begin 
  if Assigned(FOnChange) then FOnChange(Self) 
end; 
 
function TSampleCalendar.SelectCell(ACol, ARow: Longint): Boolean; 
begin 
  if Enabled then 
  if (DayNum(ACol,ARow) = -1)  then 
  Result := false 
  else 
  Result := true; 
//    Result := inherited(ACol, ARow); 
end; 
{ 
procedure TSampleCalendar.Click; 
var 
    TempDay: integer; 
begin 
    TempDay := DayNum(Col, Row);                         // get   the   day   number   for   the   clicked   cell 
    if (TempDay <>  -1) then  Day := TempDay;            // change   day   if   valid 
end; 
} 
procedure TSampleCalendar.KeyDown(var Key: Word; Shift: TShiftState); 
var 
    TempDay: integer; 
begin 
  inherited KeyDown(Key, Shift); 
  if Key = VK_SPACE then 
  begin 
    TempDay := DayNum(Col, Row); 
    if TempDay <> -1 then 
    begin 
        if Enabled then 
        begin 
            FSelArray[TempDay] := Not FSelArray[TempDay]; 
            Day := TempDay; 
        end; 
    end; 
  end; 
  Refresh(); 
end; 
 
procedure TSampleCalendar.MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); 
var 
    TempDay: integer; 
begin 
  inherited MouseDown(Button, Shift, X, Y); 
  if Button = mbLeft then 
  begin 
    TempDay := DayNum(Col, Row); 
    if TempDay <> -1 then 
    begin 
        if Enabled then 
        begin 
            FSelArray[TempDay] := Not FSelArray[TempDay]; 
            Day := TempDay; 
        end; 
    end; 
  end; 
  Refresh(); 
end; 
{ 
 
procedure TSampleCalendar.MouseUp(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); 
begin 
  try 
    case FGridState of 
      gsSelecting: 
        begin 
          Click; 
        end; 
    end; 
    inherited MouseUp(Button, Shift, X, Y); 
  finally 
    FGridState := gsNormal; 
  end; 
end; 
} 
 
function TSampleCalendar.GetChecked(Index: integer): boolean; 
begin 
    Result := false; 
    if (Index >= 1) and (Index <=31) then 
    Result := FSelArray[Index]; 
end; 
 
procedure TSampleCalendar.SetChecked(Index: integer; Value: boolean); 
begin 
    if (Index >= 1) and (Index <=31) then 
    if FSelArray[Index] <> Value then 
    begin 
        FSelArray[Index] := Value; 
    end; 
end; 
 
procedure TSampleCalendar.SetSelectColor(Value: TColor); 
begin 
  if FSelectColor <> Value then 
  begin 
    FSelectColor := Value; 
    Refresh(); 
  end; 
end; 
 
procedure TSampleCalendar.CMEnabledChanged( var Msg: TMessage); 
begin 
  inherited; 
  Refresh; 
end; 
 
end.   
 
 
2007-8-20 10:49:39    CheckBox 在右边 { 
   修改的日历组件 
   加入了CheckBox的功能 
   主要是用于我写的一个电视广告合同串联编排的管理软件 
   QQ:250198418 
   Email:lqcros@126.com 
 
} 
unit SampleCalendar; 
 
interface 
 
uses 
  SysUtils, Classes, Controls, Grids, Windows, Messages, StdCtrls, Graphics, Forms; 
 
type 
  TSampleCalendar = class(TCustomGrid) 
  private 
    { Private declarations } 
    FSelArray: Array of boolean;   //记录每一个单元格的Checked状态; 
    FSelectColor: TColor;          //选择单元格颜色 
    FDate: TDateTime; 
    FMonthOffset: integer; 
    FOnChange: TNotifyEvent; 
 
    procedure SetCalendarDate(Value: TDateTime); 
    function  GetDateElement(Index: integer): integer;                       //   note   the   Index   parameter 
    procedure SetDateElement(Index: integer; Value: integer); 
    function  GetChecked(Index: integer): boolean; 
    procedure SetChecked(Index: integer; Value: boolean); 
    procedure SetSelectColor(Value: TColor); 
    procedure CMEnabledChanged( var Msg: TMessage ); message cm_EnabledChanged; 
 
  protected 
    { Protected declarations } 
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; 
      AState: TGridDrawState);override; 
    procedure WMSize(var Msg: TWMSize); message WM_SIZE; 
    procedure UpdateCalendar; 
    function  DayNum(ACol: integer; ARow: integer): integer; 
    procedure NextMonth; 
    procedure PrevMonth; 
    procedure NextYear; 
    procedure PrevYear; 
    procedure Change; 
    function SelectCell(ACol, ARow: Longint): Boolean; override; 
 
    procedure KeyDown(var Key: Word; Shift: TShiftState); override; 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); override; 
//    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; 
//      X, Y: Integer); override; 
 
  public 
    { Public declarations } 
 
    constructor Create(AOwner: TComponent); override; 
 
//    procedure Click; 
    property  CalendarDate: TDateTime read FDate write SetCalendarDate; 
    property  Day:   integer index 3 read GetDateElement write SetDateElement; 
    property  Month: integer index 2 read GetDateElement write SetDateElement; 
    property  Year:  integer index 1 read GetDateElement write SetDateElement; 
    property  Checked[Index: integer]: boolean read GetChecked write SetChecked;   //设置或提取单元格状态 
  published 
    { Published declarations } 
    property  SelectColor: TColor read FSelectColor write SetSelectColor default clBtnFace; 
    property  Align;                                         //   publish   properties 
    property  BorderStyle; 
    property  Color; 
    property  FixedColor; 
    property  Font; 
    property  GridLineWidth; 
    property  ParentColor; 
    property  ParentFont; 
    property  Options; 
    property  Enabled; 
 
    property  OnClick;                                       //   publish   events 
    property  OnDblClick; 
    property  OnDragDrop; 
    property  OnDragOver; 
    property  OnEndDrag; 
    property  OnKeyDown; 
    property  OnKeyPress; 
    property  OnKeyUp; 
 
    property OnChange: TNotifyEvent read FOnChange write FOnChange; 
  end; 
 
var 
  ShortDayNames1: array[1..7] of string; 
 
procedure Register; 
 
implementation 
 
procedure Register; 
begin 
  RegisterComponents('Samples', [TSampleCalendar]); 
end; 
 
constructor TSampleCalendar.Create(AOwner: TComponent); 
 
begin 
    inherited; 
//  初始化日历组件的外观 
    ColCount   :=   7; 
    RowCount   :=   7; 
    RowHeights[0] := 35; 
    FixedCols  :=   0; 
    FixedRows  :=   1; 
    BorderStyle := bsNone; 
    Color      := clBtnFace; 
    FixedColor := $00ACACAC; 
    SelectColor := $00ACACAC; 
    ScrollBars := ssNone; 
    Enabled    := true; 
    Options := [goVertLine,goHorzLine,goDrawFocusSelected]; 
 
    FDate      :=  Now; 
 
    SetLength(FSelArray, 31); 
 
    ShortDayNames1[1] := '日'; 
    ShortDayNames1[2] := '一'; 
    ShortDayNames1[3] := '二'; 
    ShortDayNames1[4] := '三'; 
    ShortDayNames1[5] := '四'; 
    ShortDayNames1[6] := '五'; 
    ShortDayNames1[7] := '六'; 
 
    UpdateCalendar(); 
 
end; 
 
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime); 
var 
    i: integer; 
begin 
    FDate   :=   Value;                                             //   Set   the   new   date   value 
 
    for i := 0 to 31 do 
    FSelArray := false; 
 
    //Refresh();                                                 //   Update   the   onscreen   image 
    UpdateCalendar();                                       //   this   previously   called   Refresh 
    Change();                                                       //   this   is   the   only   new   statement    
end; 
 
function  TSampleCalendar.GetDateElement(Index: integer): Integer;                       //   note   the   Index   parameter 
var 
    AYear,   AMonth,   ADay: word; 
begin 
    DecodeDate(FDate, AYear,   AMonth,   ADay);                         //   break   encoded   date   into   elements 
    case Index of 
        1:   result   :=   AYear; 
        2:   result   :=   AMonth; 
        3:   result   :=   ADay; 
    else 
        result := -1; 
    end; 
end; 
 
procedure TSampleCalendar.SetDateElement(Index: integer; Value: integer); 
var 
    AYear, AMonth, ADay: word; 
begin 
    if (Value   >   0) then                                                                    //   all   elements   must   be   positive 
    begin 
        DecodeDate(FDate, AYear, AMonth, ADay);       //   get   current   date   elements 
        case Index of 
            1: AYear  := Value; 
            2: AMonth := Value; 
            3: ADay   := Value; 
        else 
            exit; 
        end; 
    end; 
    FDate   :=   EncodeDate(AYear,   AMonth,   ADay);                   //   encode   the   modified   date 
    //Refresh();                                                                         //   update   the   visible   calendar 
    UpdateCalendar();                                                               //   this   previously   called   Refresh 
    Change();                                                                               //   this   is   new 
end; 
 
procedure TSampleCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect; 
      AState: TGridDrawState); 
var 
    TheText: string; 
    TempDay: integer; 
    Checked: boolean; 
    CheckRect: TRect; 
const 
    CheckBox : array[Boolean] of Integer = (DFCS_BUTTONCHECK, 
    DFCS_BUTTONCHECK or DFCS_CHECKED); 
begin 
    if gdSelected in AState then 
    begin 
        Canvas.Brush.Color := SelectColor; 
        Canvas.FillRect(ARect); 
    end 
    else 
    begin 
        if (ARow >= FixedRows) and (ACol >= FixedCols) then 
        Canvas.Brush.Color := Color 
        else 
        Canvas.Brush.Color := FixedColor;   // 
        Canvas.FillRect(ARect); 
    end; 
 
    if (ARow = 0) then 
        TheText := ShortDayNames1[ACol + 1] 
    else 
    begin 
        TheText := ''; 
        TempDay := DayNum(ACol, ARow);                                       //   DayNum   is   defined   later 
        if (TempDay <> -1) then 
        begin 
            if TempDay <= 9 then 
            TheText := ' ' + IntToStr(TempDay)   //日期右对齐,美观 
            else 
            TheText := IntToStr(TempDay); 
        end; 
    end; 
 
    if (ARow >= FixedRows) and (ACol >= FixedCols) then 
    begin 
        CheckRect.Left := ARect.Left + (ARect.Right - ARect.Left - Canvas.TextWidth('11') - 18) div 2; 
        CheckRect.Top  := ARect.Top + (ARect.Bottom - ARect.Top - Canvas.TextHeight(TheText)) div 2; 
        CheckRect.Bottom := Arect.Bottom; 
        CheckRect.Right := ARect.Right; 
 
        DrawText(Canvas.Handle, pchar(TheText), Length(TheText), CheckRect, DT_LEFT); 
    end 
    else 
    begin 
        CheckRect := ARect; 
        CheckRect.Top := ARect.Top + (ARect.Bottom - ARect.Top - Canvas.TextHeight(TheText)) div 2; 
        DrawText(Canvas.Handle, pchar(TheText), Length(TheText), CheckRect, DT_CENTER); 
    end; 
         
 
    CheckRect.Top    := ARect.Top  + (ARect.Bottom - ARect.Top - 16) div 2; 
    CheckRect.Bottom := CheckRect.Top  + 15; 
    CheckRect.Left   := CheckRect.Left + Canvas.TextWidth('11') + 2; 
    CheckRect.Right  := CheckRect.Left + 14;; 
 
    if (ARow >= FixedRows) and (ACol >= FixedCols) then 
    begin 
        if TheText <> '' then 
        begin 
            Checked := FSelArray[StrToInt(TheText)]; 
            Canvas.FillRect(CheckRect); 
            if Enabled then 
            DrawFrameControl(Canvas.Handle, CheckRect, DFC_BUTTON, CheckBox[Checked]) 
            else 
            DrawFrameControl(Canvas.Handle, CheckRect, DFC_BUTTON, CheckBox[Checked] or DFCS_INACTIVE); 
        end; 
    end; 
 
 
 
end; 
 
procedure TSampleCalendar.WMSize(var Msg: TWMSize); 
var 
    GridLines: integer; 
begin 
    GridLines        := 6 * GridLineWidth;                                     //   calculated   combined   size   of   all   lines 
    DefaultColWidth  := (Msg.Width  - GridLines) div 7;         //   set   new   default   cell   width 
    DefaultRowHeight := (Msg.Height - GridLines) div 7;     //   and   cell   height 
    inherited; 
end; 
 
procedure TSampleCalendar.UpdateCalendar; 
var 
    AYear, AMonth, ADay: word; 
    FirstDate: TDateTime; 
begin 
    if (FDate <> 0) then                                                     //   only   calculate   offset   if   date   is   valid 
    begin 
        DecodeDate(FDate, AYear,   AMonth,   ADay);     //   get   elements   of   date 
        FirstDate    := EncodeDate(AYear,   AMonth,   1);       //   date   of   the   first 
        FMonthOffset := 2 - DayOfWeek(FirstDate);     //   generate   the   offset   into   the   grid 
        Row := (ADay - FMonthOffset) div 7 + 1; 
        Col := (ADay - FMonthOffset) mod 7; 
    end; 
    Refresh();                                                                         //   always   repaint   the   control 
end; 
 
function TSampleCalendar.DayNum(ACol: integer; ARow: integer): integer; 
begin 
    Result := FMonthOffset + ACol + (ARow - 1) * 7;               //   calculate   day   for   this   cell 
 
    if ((result < 1) or (result > MonthDays[IsLeapYear(Year)][Month])) then 
    result := -1;       //   return   -1   if   invalid 
end; 
 
procedure TSampleCalendar.NextMonth; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, 1), AYear, AMonth, ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.PrevMonth; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, -1), AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.NextYear; 
var 
    AYear, AMonth, ADay: word; 
    i: integer; 
begin 
    DecodeDate(IncMonth(CalendarDate, 12), AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.PrevYear; 
var 
    AYear, AMonth, ADay: word; 
    i: integer;     
begin 
    DecodeDate(IncMonth(CalendarDate,   -12),   AYear,   AMonth,   ADay); 
    Year  := AYear; 
    Month := AMonth; 
    Day   := ADay; 
    for i := 0 to 31 do 
    FSelArray := false; 
    Refresh(); 
end; 
 
procedure TSampleCalendar.Change; 
begin 
  if Assigned(FOnChange) then FOnChange(Self) 
end; 
 
function TSampleCalendar.SelectCell(ACol, ARow: Longint): Boolean; 
begin 
  if Enabled then 
  if (DayNum(ACol,ARow) = -1)  then 
  Result := false 
  else 
  Result := true; 
//    Result := inherited(ACol, ARow); 
end; 
{ 
procedure TSampleCalendar.Click; 
var 
    TempDay: integer; 
begin 
    TempDay := DayNum(Col, Row);                         // get   the   day   number   for   the   clicked   cell 
    if (TempDay <>  -1) then  Day := TempDay;            // change   day   if   valid 
end; 
} 
procedure TSampleCalendar.KeyDown(var Key: Word; Shift: TShiftState); 
var 
    TempDay: integer; 
begin 
  inherited KeyDown(Key, Shift); 
  if Key = VK_SPACE then 
  begin 
    TempDay := DayNum(Col, Row); 
    if TempDay <> -1 then 
    begin 
        if Enabled then 
        begin 
            FSelArray[TempDay] := Not FSelArray[TempDay]; 
            Day := TempDay; 
        end; 
    end; 
  end; 
  Refresh(); 
end; 
 
procedure TSampleCalendar.MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); 
var 
    TempDay: integer; 
begin 
  inherited MouseDown(Button, Shift, X, Y); 
  if Button = mbLeft then 
  begin 
    TempDay := DayNum(Col, Row); 
    if TempDay <> -1 then 
    begin 
        if Enabled then 
        begin 
            FSelArray[TempDay] := Not FSelArray[TempDay]; 
            Day := TempDay; 
        end; 
    end; 
  end; 
  Refresh(); 
end; 
{ 
 
procedure TSampleCalendar.MouseUp(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); 
begin 
  try 
    case FGridState of 
      gsSelecting: 
        begin 
          Click; 
        end; 
    end; 
    inherited MouseUp(Button, Shift, X, Y); 
  finally 
    FGridState := gsNormal; 
  end; 
end; 
} 
 
function TSampleCalendar.GetChecked(Index: integer): boolean; 
begin 
    Result := false; 
    if (Index >= 1) and (Index <=31) then 
    Result := FSelArray[Index]; 
end; 
 
procedure TSampleCalendar.SetChecked(Index: integer; Value: boolean); 
begin 
    if (Index >= 1) and (Index <=31) then 
    if FSelArray[Index] <> Value then 
    begin 
        FSelArray[Index] := Value; 
    end; 
end; 
 
procedure TSampleCalendar.SetSelectColor(Value: TColor); 
begin 
  if FSelectColor <> Value then 
  begin 
    FSelectColor := Value; 
    Refresh(); 
  end; 
end; 
 
procedure TSampleCalendar.CMEnabledChanged( var Msg: TMessage); 
begin 
  inherited; 
  Refresh; 
end; 
 
end. 
 
[ 本帖最后由 croslq 于 2007-12-13 15:09 编辑 ] 
 
  Image Attachment:
 Calendar.jpg (2007-12-13 15:09, 11.61 K)
  
 
 |