Génération des numéros de jours

De RAD Studio
Aller à : navigation, rechercher

Remonter à Suivi de la date


Insérer les numéros des jours dans le calendrier nécessite plusieurs considérations. Le nombre de jours dans le mois dépend à la fois du mois et de l'année. Le jour de la semaine qui débute le mois dépend aussi du mois et de l'année. Utilisez la fonction IsLeapYear pour déterminer si l'année est bissextile. Utilisez le tableau MonthDays dans l'unité SysUtils pour obtenir le nombre de jours dans le mois.

Une fois récupérées les informations concernant les années bissextiles et le nombre de jours par mois, vous pouvez calculer l'endroit de la grille où s'insère chaque date. Le calcul dépend du premier jour du mois.

Comme vous devez considérer le décalage du premier jour du mois, par rapport à l'origine de la grille, pour chaque cellule à remplir, le meilleur choix consiste à calculer ce nombre après chaque changement de mois ou d'année, et de s'y reporter à chaque fois. Vous pouvez stocker cette valeur dans un champ de classe, puis mettre à jour ce champ à chaque modification de la date.

Pour remplir les cellules avec les numéros de jour appropriés, procédez de la façon suivante :

  1. Ajoutez à la classe un champ décalage du premier jour du mois, ainsi qu'une méthode pour mettre à jour la valeur du champ :
 type
  TSampleCalendar = class(TCustomGrid)
  private
    FMonthOffset: Integer;                                      { storage for the offset }
  .
  .
  .
  protected
    procedure UpdateCalendar; virtual;                      { property for offset access }
  end;
.
.
.
procedure TSampleCalendar.UpdateCalendar;
var
  AYear, AMonth, ADay: Word;
  FirstDate: TDateTime;                             { date of the first day of the month }
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 }
  end;
  Refresh;                                                  { always repaint the control }
end; 
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
    int FMonthOffset;                         // storage for the offset
    .
    .
    .
protected:
    virtual void __fastcall UpdateCalendar(void);
    .
    .
    .
};
void __fastcall TSampleCalendar::UpdateCalendar(void)
{
  unsigned short AYear, AMonth, ADay;
  TDateTime FirstDate;                          // date of first day of the month
  if ((int)FDate != 0)                          // only calculate offset if date is valid
  {
    FDate.DecodeDate(&AYear, &AMonth, &ADay);  // get elements of date
    FirstDate = TDateTime(AYear, AMonth, 1);   // date of the first
    FMonthOffset = 2 - FirstDate.DayOfWeek();  // generate the offset into the grid
  }
  Refresh();                                    // always repaint the control
}
  1. Ajoutez les instructions au constructeur et aux méthodes SetCalendarDate et SetDateElement qui appellent la nouvelle méthode de mise à jour à chaque changement de date :

    constructor TSampleCalendar.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);                                       { this is already here }
      .                                                          { other initializations here }
      .
      .
      UpdateCalendar;                                                    { set proper offset }
    end;
    procedure TSampleCalendar.SetCalendarDate(Value: TDateTime);
    begin  FDate := Value;                                                { this was already here }
      UpdateCalendar;                                       { this previously called Refresh }
    end;
    
    procedure TSampleCalendar.SetDateElement(Index: Integer; Value: Integer);
    begin
      .
      .
      .
        FDate := EncodeDate(AYear, AMonth, ADay);                 { encode the modified date }
        UpdateCalendar;                                     { this previously called Refresh }
      end;
    end; __fastcall TSampleCalendar::TSampleCalendar(TComponent *Owner)
      : TCustomGrid(Owner)
    {
      .
      .
      .
      UpdateCalendar();
    }
    void __fastcall TSampleCalendar::SetCalendarDate(TDateTime Value)
    {
      FDate = Value;                                  // this was already here
      UpdateCalendar();                               // this previously called Refresh
    }
    void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
    {
      .
      .
      .
      FDate = TDateTime(AYear, AMonth, ADay);        // this was already here
      UpdateCalendar();                              // this previously called Refresh
    }
    
  2. Ajoutez une méthode au calendrier renvoyant le numéro du jour à partir des coordonnées ligne/colonne d'une cellule qui lui sont transmises :

     function TSampleCalendar.DayNum(ACol, 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; 
    
    int __fastcall TSampleCalendar::DayNum(int ACol, int ARow)
    {
      int result = FMonthOffset + ACol + (ARow - 1) * 7;       // calculate day for this cell
      if ((result < 1)||(result > MonthDays[IsLeapYear(Year)][Month]))
        result = -1;   // return -1 if invalid
      return result;
    }
    


    Pensez à ajouter la déclaration de DayNum à la déclaration de type du composant.
  3. Vous pouvez désormais calculer l'endroit où s'affichent les dates, et mettre à jour DrawCell pour remplir les cellules :

    procedure TCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
    var
      TheText: string;
      TempDay: Integer;
    begin
      if ARow = 0 then                                        { if this is the header row ...}
        TheText := ShortDayNames[ACol + 1]                           { just use the day name }
      else begin
        TheText := ;                                           { blank cell is the default }
        TempDay := DayNum(ACol, ARow);                            { get number for this cell }
        if TempDay <> -1 then TheText := IntToStr(TempDay);        { use the number if valid }
      end;
      with ARect, Canvas do
        TextRect(ARect, Left + (Right - Left - TextWidth(TheText)) div 2,
          Top + (Bottom - Top - TextHeight(TheText)) div 2, TheText);
    end; 
    
    void __fastcall TSampleCalendar::DrawCell(int ACol, int ARow, const TRect &ARect,
      TGridDrawState AState)
    {
      String TheText;
      int TempDay;
      if (ARow == 0)                                    // this is the header row
        TheText = ShortDayNames[ACol + 1];              // just use the day name
      else
      {
        TheText = "";                                   // blank cell is the default
        TempDay = DayNum(ACol, ARow);                   // get number for this cell
        if (TempDay != -1) TheText = IntToStr(TempDay); // use the number if valid
      }
      Canvas->TextRect(ARect, ARect.Left + (ARect.Right - ARect.Left -
        Canvas->TextWidth(TheText)) / 2,
      ARect.Top + (ARect.Bottom - ARect.Top - Canvas->TextHeight(TheText)) / 2, TheText);
    }
    

Si maintenant vous réinstallez le composant calendrier et le placez dans une fiche, les informations correspondant au mois en cours apparaîtront.

Voir aussi