Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   Kalender (https://www.delphipraxis.net/93735-kalender.html)

Alter Mann 10. Jun 2007 17:12


Kalender
 
Hallo,

habe gerade einen kleinen Kalender fertig gestellt und stelle in hiermit zur Verfügung!

Ich habe bisher keinerlei Anpassungen bzg. anderer Delphiversionen vorgenommen, so wie es ist
läuft es unter D7 (wegen DateUtils), sollte aber mit ein paar Anpassungen auch unter andernen
Versionen laufen.

Der Kalender hat (leider) ein paar Bugs die sich leider nicht so einfach finden lassen und
weil das so ist, ist er auch Open-Source.

Die einzigste Bedingung die ich habe, ist das alle Änderungen hier veröffentlich werden.

Gruss

Alter Mann

[Edit]
Ups...

Jetzt sind alle Dateien bei. [Edit] Plus Beispiel inkl. aller Dateien für Delphi 7.[/Edit]
[/Edit]

PS Kleine Anmerkung sei noch gestattet:

Das Beispiel zeigt ungefähr wo es hingehen soll, vielleicht noch DB-Anbindung.

Was mich da ein wenig verwundert ist die Darstellung zur Desginzeit und zur Laufzeit bzw.
die unterschiedliche Darstellung zwischen Componenten auf Form plaziert und zur Laufzeit
erstellt(siehe Calendar.zip), genauso im Beispiel.

DeddyH 10. Jun 2007 17:17

Re: Kalender
 
Ööhhhmmm.... da fehlt aber die Unit uCalendar im Archiv :angel:

BFI2007 15. Jun 2007 11:17

Re: Kalender
 
echt ey

Alter Mann 19. Jun 2007 17:56

Re: Kalender
 
Hallo


Ich habe mir nartürlich Gedanken gemacht und den ganzen Code neugeschrieben.
Es sind soweit alle 'irrsinnigen' Bugs rausgeflogen und 'andere?' dafür reingekommen.

Die jeniegen die sich den alten Code angetan haben, meine Bewunderung und Entschuldigung.

Für alle Intressierten:

Es fehlt noch die DB-Anbindung und Multiselect.

Aber vielleicht ist ja der/die Eine oder Andere so Hilfsbereit und stellt
die entsprechende Ableitung zur Verfügung.

Viele Grüsse

Alter Mann

Alter Mann 20. Jun 2007 19:09

Re: Kalender
 
Hi,

auch wenn es scheinbar keiner Braucht, hier die DB-Anbindung.
Doch zuerst müssen wir die Kalender-Componente aktuallisieren:

Delphi-Quellcode:
  TCalendarControl = class(TCustomControl)
  private
  ...
    FDates       : Array of TDateTime;
    FMaxRecords  : Integer;
  ...
  protected
  ...
    procedure  DataChange(Sender: TObject); virtual;
    function   DateInArray(aDate : TDateTime) : Boolean;
  ...
  end;

...

constructor TCalendarControl.Create(aOwner : TComponent);
begin
  ...
  SetLength(FDates, 31);
  FMaxRecords  := -1;
  ...
end;

...

procedure  TCalendarControl.DataChange(Sender: TObject);
begin
end;

function   TCalendarControl.DateInArray(aDate : TDateTime) : Boolean;
var
  I : Integer;
begin
  Result := False;
  for I := Low(FDates) to High(FDates) do
   if FDates[I] = aDate then
   begin
     Result := True;
     Break;
   end;
end;

...

procedure  TCalendarControl.DoDateChange(aOldDate, aNewDate : TDateTime);
begin
  SetLength(FDates, 0);
  SetLength(FDates, 31);
  FMaxRecords  := -1;
  DataChange(Self);
  if Assigned(FOnDateChange) then FOnDateChange(Self, aOldDate, aNewDate);
end;

...

procedure  TCalendarControl.Paint;
   ...
          if DateInArray(CE.EntryDate) then Font.Style := Font.Style + [fsBold]
                                       else Font.Style := Font.Style - [fsBold];
          if FOptions.TrailingDays then
   ...
end;
Delphi-Quellcode:
  TDBCalendarControl = class(TCalendarControl)
  private
    FDataLink  : TFieldDataLink;
    function GetDataField: string;
    function GetDataSource: TDataSource;
    function GetField: TField;
    procedure SetDataField(const Value: string);
    procedure SetDataSource(Value: TDataSource);
    procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
  protected
    procedure DataChange(Sender: TObject);         override;
    function IsDateTimeField : Boolean;
    procedure Loaded;                              override;
    procedure LoadDatesForMonth;
    procedure Notification(aComponent: TComponent;
                           Operation: TOperation); override;
  public
    constructor Create(aOwner: TComponent);        override;
    destructor Destroy;                           override;
    property Field: TField read GetField;
    property DataField: string read GetDataField write SetDataField;
    property DataSource: TDataSource read GetDataSource write SetDataSource;
  end;

...

{
************  TDBCalendarControl
}

(* public *)

constructor TDBCalendarControl.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  FDataLink              := TFieldDataLink.Create;
  FDataLink.Control      := Self;
  FDataLink.OnDataChange := DataChange;
end;

destructor TDBCalendarControl.Destroy;
begin
  FDataLink.Free;
  FDataLink := nil;
  inherited Destroy;
end;


(* private *)


procedure  TDBCalendarControl.DataChange(Sender: TObject);
begin
  if (FDataLink.Field <> nil) and not FDataLink.DataSourceFixed then
  begin
    if FMaxRecords <> FDataLink.DataSet.RecordCount - 1 then
    begin
      FMaxRecords := FDataLink.DataSet.RecordCount - 1;
      FDataLink.DataSourceFixed := True;
      LoadDatesForMonth;
    end;
  end;
end;

function   TDBCalendarControl.GetDataField: string;
begin
  Result := FDataLink.FieldName;
end;

function   TDBCalendarControl.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;

function   TDBCalendarControl.GetField: TField;
begin
  Result := FDataLink.Field;
end;

procedure  TDBCalendarControl.SetDataField(const Value: string);
begin
  FDataLink.FieldName := Value;
end;

procedure  TDBCalendarControl.SetDataSource(Value: TDataSource);
begin
  if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
    FDataLink.DataSource := Value;
  if Value <> nil then Value.FreeNotification(Self);
end;

procedure  TDBCalendarControl.CMGetDataLink(var Message: TMessage);
begin
  Message.Result := Integer(FDataLink);
end;


(* protected *)

function   TDBCalendarControl.IsDateTimeField : Boolean;
begin
  with FDataLink do
    Result := (Field <> nil) and (Field.DataType in [ftDateTime, ftTimeStamp]);
end;

procedure  TDBCalendarControl.LoadDatesForMonth;
var
  I : Integer;
  DT : TDateTime;
  Y1, Y2, M1, M2, D1, D2 : Word;
begin
  FDataLink.DataSet.First;
  for I := 0 to FDataLink.DataSet.RecordCount - 1 do
  begin
    if IsDateTimeField then
      DT := Trunc(FDataLink.Field.AsDateTime)
    else
      DT := Trunc(FDataLink.Field.AsDateTime);

    DecodeDate(DT, Y1, M1, D1);
    DecodeDate(FDate, Y2, M2, D2);
    if (Y1 = Y2) and (M1 = M2) then FDates[D1] := DT;
    FDataLink.DataSet.Next;
  end;
  Invalidate;
  FDataLink.DataSourceFixed := False;
end;

procedure  TDBCalendarControl.Loaded;
begin
  inherited Loaded;
  if (csDesigning in ComponentState) then DataChange(Self);
end;

procedure  TDBCalendarControl.Notification(aComponent: TComponent;
                                            Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (FDataLink <> nil) and
    (AComponent = DataSource) then DataSource := nil;
end;
Um die Sache Rund zu machen fehlt noch dies:

Delphi-Quellcode:

  TExDBCalendar = class(TDBCalendarControl)
  published
    property CalendarDate;
    property Colors;
    property DataField;
    property DataSource;
    property Font;
    property Options;
    property OnDayClick;
    property OnDateChange;
  end;
Das war es.


Gruss

marabu 20. Jun 2007 19:44

Re: Kalender
 
Hallo Alter Mann,

dass ein solches Control niemand braucht möchte ich nicht unterschreiben. Jedenfalls finde ich es nett von dir, dass du deine Komponente hier zur Verfügung stellst.

Beim Drüberschauen stellt sich mir die Frage, ob nicht ein Bookmark die Methode LoadDatesFromMonth() aufwerten würde. Immerhin verschiebst du den Datensatzzeiger. Dann sehe ich eine bedingte Zuweisung an DT, bei der beide Zweige gleich lauten, sodass die Bedingung eigentlich ungeprüft entfallen kann.

Für einen produktiven Einsatz würde ich eine lose Kopplung zwischen Control und Datenbank vorziehen. Hast du dir mal die Komponente TMonthCalendar und dort speziell das Ereignis OnGetMonthInfo() angeschaut?

Freundliche Grüße

Alter Mann 20. Jun 2007 19:49

Re: Kalender
 
Hi marabu,

TMonthCalendar habe ich mir schon angeschaut, allerdings nicht OnGetMonthInfo, was ich nachholen werde.
Das mit DT ist mir auch klar, habe aber noch keine bessere Idee.

Mitarbeit erwünscht.

Bis bald und Danke.

Gruss

Alter Mann

Alter Mann 20. Jun 2007 20:02

Re: Kalender
 
Hi marabu,

manchmal bin auch ich schnell(beim drüberlesen) :wink:

Klar PMonthDayState würde die Sache auch machen, aber die Compo auch 'aufblähen'.
Man muss auf OnGetMonthInfo reagieren und die Sache in Paint doch wieder umsetzen.
Es sei denn, es gibt Handfeste Argumente, die dagegen Sprechen.

MfG

Alter Mann

marabu 20. Jun 2007 20:13

Re: Kalender
 
Mir gefällt die Entkopplung von Funktionalitäten, wie sie über OnGetMonthInfo() möglich wird.

Zu der Typprüfung: Ich würde einfach eine Exception werfen, wenn sich der Feldtyp beim ersten Zugriff als falsch herausstellt. Die Prüfung sollte auf keinen Fall innerhalb einer Schleife über potentiell Tausenden von Datensätzen statt finden.

Statt DataSet.First() bietet sich vielleicht DataSet.Locate() an. So könntest du in einer riesigen Tabelle Laufzeitvorteile gewinnen. Und nicht das Bookmarking vergessen.

Gute Nacht

Alter Mann 20. Jun 2007 20:18

Re: Kalender
 
Hi marabu,

wie würde das Aussehen?
Zitat:

Statt DataSet.First() bietet sich vielleicht DataSet.Locate() an. So könntest du in einer riesigen Tabelle Laufzeitvorteile gewinnen. Und nicht das Bookmarking vergessen.
Gruss

Alter Mann

PS Entschuldigung wenn ich Dich von einer anderen 'wichtigeren' Sache abhalte.

Gute Nacht


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:30 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz