Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TCollection, TCollectionItem (https://www.delphipraxis.net/78510-tcollection-tcollectionitem.html)

uwewo 6. Okt 2006 07:14


TCollection, TCollectionItem
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ich habe am Anfang des Jahres angefangen meine erste Komponente zu programmieren, da ich jetzt wieder mehr Zeit habe möchte ich gerne daran weiterarbeiten.

Es soll eine Kalenderkomponente werden abgeleitet von TCustomGrid. Auf diesem Grid soll man Objekte abgeleitet von TGraphicControl ablegen können, die die Einträge im Kalender verwalten.
Siehe Screenshot.

Um diese Objekte zu verwalten müßte ich meiner Komponente nun die Klasse TCollection hinzufügen, glaube ich jedenfalls.

So und nun zu meinem Verständnisproblem:

1. Wo muß ich die Klasse TCollection erstellen, wahrscheinlich beim erstellen meines Grids, oder?
2. Müssen die TCollectionItems von meinen Einträgen oder die Einträge von TCollectionItems erstellt werden?

Falls jemand etwas direkt in meinen Source schreiben will, kann ich ihn auch noch anhängen.

Habe mir schon sehr viele Quellcodes angeschaut, da aber in den meisten alle möglichen Klassen verschachtelt sind habe ich die Logik einfach noch nicht verstanden.

Hoffe es wahr einigermaßen verständlich was ich von Euch möchte.

Danke im voraus

Uwe

uwewo 9. Okt 2006 06:16

Re: TCollection, TCollectionItem
 
Hi,

Ok, vielleicht war meine Frage zu kompliziert gestellt, deshalb versuche ich es nocheinmal.

Ich habe mir ein Grid erstellt, in dem ich das Datum in Spalten und die Uhrzeit oder frei definierbare Texte, in Zeilen anzeigen lassen kann. Auf dieses Grid, möchte ich DateItems als Einträge im Kalender anzeigen lassen. Siehe Screenshot erstes Posting.

Delphi-Quellcode:
TDateLine = TCustomGrid
TDateItem = TGraphicControl
Wie kann ich am besten die Einträge(TDateItem) verwalten, in TCollection? Oder gibt es bessere Methoden?
Wie müßte ich das ganze dann aufbauen, wo was deklarieren. Für die Zukunft würde ich gerne auch die Einträge in einer DB speichern können.

Hoffe es gibt doch jemand da draußen, der mir eine kleine Hilfestellung geben kann.

Danke

oki 9. Okt 2006 07:37

Re: TCollection, TCollectionItem
 
Hi,

grundsätzlich halte ich TCollection für den richtigen Weg. Nun progge ich nicht jeden Tag Kompos mit TCollection und kann somit meine Hand nicht dafür ins Feuer legen, dass das der perfekte Weg ist. Aber so habe ich es gemacht. Günstig ist es auf jeden Fall ein TListItem-element als Hilfe wie es funst zu benutzen.

als erstes benötigst du ein Control, welches deine Elemente hält. Das hast du ja schon; deine Kalenderkompo als TCustomGrid.
Diese benötigt jetzt eine property Items. das sieht dann etwa so aus:
Delphi-Quellcode:
  TMyControl = class(TCustomControl)
  private
    procedure SetMyItems(const Value: TLCItems);
  published
    property Items: TMyItems read FMyItems write SetMyItems;
  end;


procedure TLineControl.SetMyItems(const Value: TMyItems);
begin
  FMyItems.Assign(Value);
end;
Mein TCollection-Object sieht dann so aus
Delphi-Quellcode:
  TMyItems = class(TCollection)
  private
    FLineControl: TMyControl;
    function GetItem(Index: Integer): TMyItem;
    procedure SetItem(Index: Integer; Value: TMyItem);
  protected
    function GetOwner: TPersistent; override;
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create(AControl: TMyControl);
    function Add: TMyItem;
    procedure Refresh;
    property Items[Index: Integer]: TMyItem read GetItem write SetItem;
    default;
  end;

// hier ein Bspiel für SetItem
procedure TMyItems.SetItem(Index: Integer; Value: TMyItem);
begin
  inherited SetItem(Index, Value);
end;
Hier sind zwei Sachen entscheidend, im Constructor wird das Parent-Control aufgerufen. Dies erfolgt, um denren Zeichenroutinen nach Änderung der Item aufrufen zu können. Im weiteren händelt die Collektion die grundlegenden Methoden für die Erstellung und den Zugriff auf die Item.

Die Item sehen dann so aus:
Delphi-Quellcode:
  TMyItem = class(TCollectionItem)
  private
    FParent: TLCItems;
    FRect : TRect;
    FCaption: String;
    procedure SetCaption(const Value: String);
  protected
  public
    constructor Create(Collection: TCollection); override;
    procedure Update; virtual;
    procedure Assign(Source: TPersistent); override;
    property Data : Pointer read FData write FData;
  published
    property Caption : String read FCaption write SetCaption;
  end;
Denk an die Forward-Deklaration für TMyItems und TMyControl.

gezeichnet wird im TMyControl. Dazu besitzt bei mir TMyControl eine Methode
Delphi-Quellcode:
    procedure DrawItem(Item: TLCItem; ACanvas: TCanvas; var R: TRect); virtual;
Hierbei ist Canvas der Canvas von TMyControl. Es wird direkt in den Canvas gezeichnet. Ob das so die ideale Methode ist mag ich nicht zu sagen. Vielleicht hast du oder ein anderer eine bessere Idee.

gruß oki

uwewo 9. Okt 2006 14:18

Re: TCollection, TCollectionItem
 
Erstmal Vielen Dank oki,

werde mir das ganze mal durch den Kopf gehen lassen und natürlich auch ausprobieren.

Danke, Danke!

oki 11. Okt 2006 15:23

Re: TCollection, TCollectionItem
 
Hi uwewo,

habe deinen code bekommen und schon mal rein geschaut. Ich glaube hier muß man eine grundsätzliche Entscheidung für die Vorgehensweise finden. entweder man benutzt TCollections oder eigene Listen in denen die Elemente gehalten werden. Hierbei ist es dann aber so, dass bei TCollection der weg an TColletionItem nicht vorbei geht. Hier ist dann nichts mit TCustomControl!!! Ein Trick ist es dann vielleicht, wenn mann das CustomControl (hier TDateItem) in einer neuen Eigenschaft "Controldata" versteckt. Ob der Aufwand damit aber nicht zu hoch wird ist hier die Frage.

Alternativ könnte man dann über Object-Listen arbeiten, in denen dann die DateItem gesammelt werden.
Ob das weniger Aufwand ist? Keine Ahnung. Egal über welchen Weg du gehst, helfen kann ich dir sicher. Das es der effektivste Weg ist kann ich aber nicht garantieren. Die Thematik eines anständigen Item-Editors zu designtime hab ich persönlich jedoch noch nicht umgesetzt (war mir für eigene Kompos zu viel Aufwand).

o.k. sag welche Methode du möchtest und es kann los gehen.

Gruß oki

P.S. Nach dem ich meinen eigenen Beitrag noch mal gelesen habe tendiere ich zu den TCollection.

uwewo 12. Okt 2006 06:20

Re: TCollection, TCollectionItem
 
Hallo oki,

danke das Du es dir angeschaut hast, TCollection denke ich wird der richtige Weg sein.

Wäre es möglich TCollection und TCollectionItem zu erstellen, und nur die Eigenschaften von TDateItem
in TCollectionItem zu lesen und zu schreiben?

Damit die eigentliche Routine zum zeichnen, sowie die Eigenschaften von TDateItem in der Klasse TDateItem bleiben?

oki 13. Okt 2006 07:09

Re: TCollection, TCollectionItem
 
Hi,

Zitat:

Zitat von uwewo
Wäre es möglich TCollection und TCollectionItem zu erstellen, und nur die Eigenschaften von TDateItem
in TCollectionItem zu lesen und zu schreiben?

genau das ist der springende Punkt bei der Sache mit TcollectionItem. Willst Du deine Einträge ausschließlich von TCollectionItem ableiten, so müssen diese im Parent per "Hand" gezeichnet werden (auf den vorhandenen Canvas).

Das ist wohl so üblich. Die nächste Frage ist jetzt aber ob man nicht auch einen anderen Weg gehen kann. Wenn es sinn macht die Einträge als TWincontrol auf dem Parent darzustellen, dann kann man natürlich dem TCollectionItem auch eine Eigenschaft vom Typ TControlItem(TCustomControl) verpassen. Deises dann auf das Parent geklebt, und mann spart sich die vielen aufwendigen Zeichenroutinen. Bedenke, das geder Eintrag gezeichnet werden muß, und das für mehrere Zustände (selektiert, nicht selektiert etc.) Ich glaube das grundlegende Plroblem wird wohl eher die Performance sein. Nun gut, zur not können wir es ja einfach ausprobieren.

Ich hab mal angefangen deinen Code zu überarbeiten und werde ihn sicher heute Versandfertig haben. Dann können wir die ersten Sachen vielleicht heute testen und die ersten Ergebnisse posten.

Gruß oki

uwewo 13. Okt 2006 07:53

Re: TCollection, TCollectionItem
 
Hört sich ja gut an. Wenn ich schon etwas vorbereiten kann das Dir hilft, sag Bescheid.

Das Zeichnen der Items auf dem Grid funktioniert ja soweit schon, ich weiß natürlich nicht ob Du es ausprobiert hast.

oki 13. Okt 2006 07:58

Re: TCollection, TCollectionItem
 
Hi,

tschuldige, aber ich bin in 1 Minute offline. Nein hab ich nicht getestet, mach ich noch. Bin nur gerade beim umschreiben.

bis später Gruß oki

oki 13. Okt 2006 14:00

Re: TCollection, TCollectionItem
 
Hi uwewo,

so, jetzt mal zum Ansatz und Aufbau deiner neuen Kompo TDateLine.

TDateLine ist vom Typ TCustomGrid und damit ein Nachfahre von TComponent.
TDateLine hält einen Member TDateItems vom Typ TCollection.
TDateItems hält die Einträge TDateItem vom Typ TCollectionItem.

Da du deine Einträge gerne als TCustomControls haben möchtest, hält jetzt genau jedes TDateItem ein TControlDateItem vom Typ TCustomControl. Somit verknüpfen wir ursächlich jedes Control mit einem Listeneintrag im DateLine.

das sieht im Objectaufbau etwa so aus:
Delphi-Quellcode:
  // Forward
  TDateLine     = class;
  TDateItems    = class;

 TControlDateItem = class(TCustomControl)
  private
    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
    procedure Paint; override;
  public
    { Public-Deklarationen }
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
  published
    { Published-Deklarationen }
 end;
 
  TDateItem = class(TCollectionItem)
  private
    FParent : TDateItems;
    FControlDateItem : TControlDateItem;
  protected
  public
    constructor Create(Collection: TCollection); override;
  end;

  TDateItems = class(TCollection)
  private
    FDateLine: TDateLine;
    function GetItem(Index: Integer): TDateItem;
    procedure SetItem(Index: Integer; Value: TDateItem);
  protected
    function GetOwner: TPersistent; override;
    procedure Update(Item: TDateItem); reintroduce;
  public
    constructor Create(DateLine: TDateLine);
    function Add: TDateItem;
    procedure Refresh;
    property Items[Index: Integer]: TDateItem read GetItem write SetItem;
    default;
  end;

TDateLine = class(TCustomGrid)
  private
    { Private-Deklarationen }
    FDateItems       : TDateItems;
  protected
    { Protected-Deklarationen }
  public
    { Public-Deklarationen }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
      property Items: TDateItems read FDateItems write SetDateItems;
  end;
Ich habe hier die spezifischen Eigenschaften weg gelassen.

Ein neues Item im DateLine kann jetzt wie gewohn erschaffen werden.

Delphi-Quellcode:
var Item : TDateItem;
begin
  Item := MyLineControl.Items.Add;
Im Constructor von TDateItem geschieht jetzt folgendes:
Delphi-Quellcode:
constructor TDateItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FParent := TDateItems(Collection);
  FControlDateItem := TControlDateItem.Create((Collection as TDateItems).FDateLine);
end;
Es wird automatisch ein zugehöriges TControlDateItem kreiert. Achte aber darauf, dass der Owner hier nicht self (das Item) sonder TDateLine, also die Kompo ist. Dort soll das Control ja auch platziert werden.

Jetzt ist mir aufgefallen, dass du ne menge obstruser Eigenschaften definierst. Bsp.
Delphi-Quellcode:
 TControlDateItem = class(TCustomControl)
  private
    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
  public
    { Public-Deklarationen }
  published
    { Published-Deklarationen }
   property Height;// default 65;
   property Width;// default 65;
   property ColLeft     : Integer read FColLeft write FColLeft;
   property RowTop      : Integer read FRowTop write FRowTop;
   property ColCount    : Integer read FColCount write FColCount;
   property RowCount    : Integer read FRowCount write FRowCount;
   property Shape       : TItemForm read FShape write SetShape;
   property Brush       : TBrush read FBrush write SetBrush;
   property Pen         : TPen read FPen write SetPen;
   property Text        : String read FText write SetText;
   property Font        : TFont read FFont write SetFont;
 end;
Ich unterstell mal, das bei entsprechenden Kalendereinträgen niemand die Breite und Höhe in Pixeln eingibt. Damit sind diese Werte für diese Anwendung wenn schon nicht im Public, so doch im published-Teil sehr fraglich.

Hie veröffentlicht mann eher die Eigenschaften:
Delphi-Quellcode:
  property StartDate : TDateTime read FStartDate write SetStartDate;
  property EndDate : TDateTime read FEndDate write SetEndDate;
die entsprechenden Set-Methoden berechnen und setzen dann die richtigen Werte für Höhe, Breite und Position im DateLine. Bei einer Aktualisierung brauchen dann auch nur noch diese Methoden aufgerufen werden und das Control passt sich automatisch den neuen Einstellungen von DateLine an.

Bu, jetzt hab ich krumme Finger, bis später

oki

P.S. in meinem Code per PM entferne die Auskommentierungen vom 11.10 in TDateItems!

uwewo 13. Okt 2006 14:09

Re: TCollection, TCollectionItem
 
So, erstmal Vielen Dank für die große Mühe die Du dir gemacht hast.

Werde mich jetzt am Wochenende ausgehend damit beschäftigen und am Montag meinen Fortschritt mitteilen.

Wünsche Dir ein schönes Wochenende

PS:
Zitat:

Zitat von oki
Jetzt ist mir aufgefallen, dass du ne menge obstruser Eigenschaften definierst.

Ich unterstell mal, das bei entsprechenden Kalendereinträgen niemand die Breite und Höhe in Pixeln eingibt. Damit sind diese Werte für diese Anwendung wenn schon nicht im Public, so doch im published-Teil sehr fraglich.

Dabei muß ich Dir allerdings Recht geben! Aber nicht vergessen ist meine erste Komponente.

oki 13. Okt 2006 16:44

Re: TCollection, TCollectionItem
 
Hi uwewo,

Zitat:

Zitat von uwewo
Aber nicht vergessen ist meine erste Komponente.

Keine Panik, ich lerne auch immer noch kräftig dazu so wie viele andere und es gibt hier im Forum genug Profis vor denen ich den Hut ziehe.

Ich hab gleich noch nen Tip.

wenn ich eine Kompo progge, dann nenne ich sie zuerst TCustomDateLine. Dabei sind alle Eigenschaften public.

Die eigentliche Kompo ist dann TDateLine, bei der ich dann alle notwendigen Eigenschaften published mache. Der Vorteil ist, dass du alle weiteren Nachfahren von deinem TCustomDateLine ableiten kannst, und für den published Teil nur die eigenschaften öffentlich sind die du bei dieser haben willst.

Bsp.:

Delphi-Quellcode:
  TCustomDateLine = class(TCustomGrid)
  private
  public
    property Nachname : String read FNachname write FNachname;
    property Firma : String read FFirma write FFirma;
  end;

  TPrivateDateLine = class(TCustomdateLine)
  published
    property Nachname;
  end;

  TFirmaDateLine = class(TCustomdateLine)
  published
    property Firma;
  end;
Das Bsp. ist jetzt vielleicht nicht so toll, aber was soll's. Ich glaube man sieht worum es geht. Hast du erst mal in deinem TCustomDateLine alle Eigenschaften published, wirst du sie in deinen Nachfahren halt nicht mehr los. das ist manchmal doof.


Also, teste mal rum und schönes Wochenende.

gruß oki

uwewo 16. Okt 2006 06:29

Re: TCollection, TCollectionItem
 
Hi oki,

habe mir das ganze am Wochenende mal angeschaut, leider gab es da zwei Probleme die ich nicht so ganz verstehen kann.

Hier kommt ein Runtime Error, ich vermute mal es liegt daran das die TCollecton noch nicht erstellt wurde.
Delphi-Quellcode:
function TDateItems.Add: TDateItem;
begin
  Result := TDateItem(inherited Add);
  Update(Result);
end;
habe darauf hin mir TListView, TStatusBar angeschaut und den Aufbau verglichen, konnte aber keinen Unterschied zwischen Deinen Deklarationen und z.B. TListView finden.

Zitat:

P.S. in meinem Code per PM entferne die Auskommentierungen vom 11.10 in TDateItems!
Hier erhalte ich einen Fehler beim Kompilieren
Delphi-Quellcode:
constructor TDateItems.Create(DateLine: TDateLine);
begin
// 11.10.2006 
  inherited Create(DateLine);
  FDateLine := DateLine;
end;
Hattest Du den Code ausprobiert?
Kann es sein das der constructor von TDateItems nie ausgeführt wird?

oki 16. Okt 2006 16:20

Re: TCollection, TCollectionItem
 
Hi und sorry,

ich hab es in der Hektik nicht komplet getestet :oops: .
Der Fehler liegt hier:
Delphi-Quellcode:
constructor TDateItems.Create(DateLine: TDateLine);
begin
  // 11.10.2006
  inherited Create(TDateItem);
  FDateLine := DateLine;
end;
Du mußt im Aufruf inherited create einen Klassennamen angeben. Das sagt die OH dazu:
Zitat:

Die Methode erzeugt und initialisiert eine Kollektion.

type TCollectionItemClass = class of TCollectionItem;
constructor Create(ItemClass: TCollectionItemClass);

Beschreibung

Create erwartet als Parameter den Namen einer von TCollection abgeleiteten Klasse. Dieser Parameter legt die Klasse der Elemente fest, die von der Methode Add erzeugt werden.
danach ist die Fehlermeldung weg.

Der Kommentar in SetItem muß natürlich auch raus:
Delphi-Quellcode:
procedure TDateItems.SetItem(Index: Integer; Value: TDateItem);
begin
  // 11.10.2006
  inherited SetItem(Index, Value);
end;
somit lauft das Compiling erst mal. Ich teste jetzt aber auch noch mal das creieren der Items.

gruß oki

oki 16. Okt 2006 17:01

Re: TCollection, TCollectionItem
 
Hi,

nächster Fehler. Im Constructor deines DateLine's muß natürlich die Collection erzeugt werden, sonst nix mit Items.
Delphi-Quellcode:
constructor TDateLine.Create(AOwner: TComponent);
begin
    inherited Create(AOwner); { geerbten Konstruktor aufrufen }
    FDateItems       := TDateItems.Create(self);
...
Im create des Items dann noch folgendes:
Delphi-Quellcode:
constructor TDateItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FParent := TDateItems(Collection);
  FControlDateItem := TControlDateItem.Create((Collection as TDateItems).FDateLine);
  // ohne Parent keine anzeige (Owner in create alleine reicht nicht)!!!!!!!!!!!!!
  FControlDateItem.Parent := (Collection as TDateItems).FDateLine;
end;
Danach hatte ich dann erst mal keine Fehlermeldungen mehr. Die Items werden auch kreiert, sind aber mit Aufruf von CreateItemFromSel nicht sichtbar (verschieb diese Methode in public). Das liegt daran, dass nach dem Create deines Item keine Breite und Höhe gesetzt wird. Hier hab ich hilfsweise zum Test folgendes gemacht (ist so natürlich nicht korrekt):
Delphi-Quellcode:
procedure TDateLine.CreateItemFromSel;
Var SRect : TRect;
    AItem : TDateItem;
begin
   // 13.10.2006 oki
   // hier wie in einer Collection creieren dabei macht es aber wenig Sinn dieses
   // als globalen Member zu halten
   AItem             := self.Items.Add;
   // 13.10.2006 oki FItem.Parent      := Self;
   SRect             := CellRect(Selection.Left, Selection.Top);

   AItem.FControlDateItem.StartDate   := StrToDate(GetSelFirstDate);
   AItem.FControlDateItem.StartTime   := StrToTime(GetSelFirstTime);

   AItem.FControlDateItem.Left        := SRect.Left; //Pixelangabe
   AItem.FControlDateItem.Top         := SRect.Top;  //Pixelangabe
   AItem.FControlDateItem.Width         := SRect.Right - SRect.Left;  //Pixelangabe
   AItem.FControlDateItem.Height         := SRect.Bottom - SRect.Top;  //Pixelangabe
....
Somit ist jetzt erst mal was zu sehen. Grundsätzlich macht das natürlich so wenig Sin. Das zeichnen sollten wir dann später noch mal überarbeiten.

Ich schlage vor, wir forsten erst mal die Klassen auf und bringen da etwas Ordnung rein. Das aber nicht mehr heute.

Gruß oki

uwewo 17. Okt 2006 07:13

Re: TCollection, TCollectionItem
 
Hi oki,

zwei der drei Fehler konnte ich nun auch gestern Abend lokalisieren und beheben.
Trotzdem war es gut für mich zu sehen, daß ich es auch richtig interpretiert hatte.

Habe kleinere Veränderungen beim zeichnen von TControlDateItem vorgenommen zumindest werden diese
wieder auf Größe der Auswahl gezeichnet.

Was mich allerdings schon gestern nach der Fehlersuche beschäftigt hatte war, warum sieht man im TCollectionEditor im OI beim hinzufügen eines neuen TDateItem nicht die Eigenschaften von TControlDateItem? Deshalb dachte ich mir erweitere ich die Propertys wie folgt.

Delphi-Quellcode:
  TDateItem = class(TCollectionItem)
  private
    FControlDateItem : TControlDateItem;
    FParent         : TDateItems;
    //Neu
    FName           : String;
  protected
  public
    constructor Create(Collection: TCollection); override;
    //Neu
    property Name : String read FName write FName;//Neu
    property ControlDateItem : TControlDateItem read FControlDateItem write FControlDateItem;
  end;
Leider hatte dies auch nicht den gewünschten Effekt, vielleicht denke ich zu naiv, werde mich aber weiter damit beschäftigen. Weiteres später.

oki 17. Okt 2006 07:27

Re: TCollection, TCollectionItem
 
Hi uwewo,

wenn du die Eigenschaften des eingebetteten TControlDateItem im OI des TdateItem sehen willst, mußt du wie bei deinem DateLine für Header und SideBar. Dann diese aber auch in den published-Abschnitt. Noch mal zur Erinnerung. Public und published stellen die gleichen Sichtbarkeit dar. Published-Eigenschaften sind genauso öffentlich wie public-Eigenschaften. Nur bei Komponenten werden die published-Eigenschaften im OI angezeigt. Das heißt also, das alle Eigenschaften einer Kompo die in den OI sollen published deklariert werden müssen. Bei einer Klasse die keine Kompo ist macht eine Published-Deklaration wiederum keinen Sinn (wobei sie meines Wissens aber auch keinen Schaden anrichtet).

Also, bau dir einen Wrapper für die TControlDateItem-Eigenschaften oder deklariere alle Eigenschaften die du im DateItem veröffentlichen willst in TDateItem published. Dann mußt du aber für read und write entsprechende Get und Set-Methoden setzen um die geänderten Eigenschaften von TControlDateItem zu holen oder zu setzen. Wenn du ein Bsp. brauchst, sag bescheid.

gruß oki

oki 18. Okt 2006 16:10

Re: TCollection, TCollectionItem
 
Hi Leute,

aktuell stellt sich hier die Frage welcher Weg der bessere ist.

1. Nimmt man TCollection oder eigene Listen?
Ich glaube im Moment ist man mit TCollection gut bedient.

2. Zeichnet man die Items in den Canvas der Komponente oder platziert man "kleine Termin-Controls"?
Das Zeichnen im Canvas scheint die übliche Methode zu sein. Bei einem Terminplaner habe ich aber viele Eigenschaftsänderungen die ich auch per Drag&Drop ausführen möchte (verschieben, verlängern ...). dies müßte beim Zeichnen alles seperat behandelt werden. Ich habe das Gefühl, das das mit den Controls besser klappen kann (vorallem mit weniger Aufwand).
Was die Performance dazu sagt ist für mich bis jetzt aber im dunkeln. Vielleicht hat dazu einer entsprechende Erfahrungen und kann hier mal ne'n tipp lassen.

Dank und gruß oki

oki 18. Okt 2006 16:19

Re: TCollection, TCollectionItem
 
Hi uwewo,

stell dein Demo doch mal hier mit rein. Wenn einige das sehen, dann kommt bestimmt ne Menge positiv zu nutzende Kritik. Ich find die Kompo schon mal cool. Code schau ich mir noch an.

edit: o.k. vorher sollten wir aber noch massiv an den Zeichenroutinen arbeiten. Das funzt alles erst beim scrollen. Für den Rest klappt nichts. edit/

gruß oki

uwewo 19. Okt 2006 06:12

Re: TCollection, TCollectionItem
 
Zitat:

Zitat von oki
o.k. vorher sollten wir aber noch massiv an den Zeichenroutinen arbeiten. Das funzt alles erst beim scrollen. Für den Rest klappt nichts.

Ja das stimmt und daran arbeite ich gerade, habe mich entschieden TControlDateItem nun von TGraphicControl abzuleiten, da ich eigentlich kein Fenster Handle benötige.
Falls es aber doch irgendwann der Fall sein sollte, werde ich TCustomControl verwenden.

Um für alle die vielleicht irgenwann ein ähnliches Problem haben sollten, werde ich spätestens nächste Woche den kompletten Aufbau und das erstellen der Klassen hier als Code reinstellen.

Zitat:

Zitat von oki
stell dein Demo doch mal hier mit rein. Wenn einige das sehen, dann kommt bestimmt ne Menge positiv zu nutzende Kritik. Ich find die Kompo schon mal cool.

Mal schauen wie weit ich heute mit den Zeichenroutinen komme, dann folgt das Demo.


Uwe

oki 19. Okt 2006 08:20

Re: TCollection, TCollectionItem
 
Hi uwewo,

das mit den Zeichenroutine ist eigentlich nicht so schwer. Deine Items werden ja schon richtig gezeichnet. Überschreibe die procedure Paint von TDateLine und schon werden alle Items dem aktuellen DateLine automatisch angepaßt.

Delphi-Quellcode:
    procedure Paint; override;
...

procedure TDateLine.Paint;
begin
  inherited;
  DrawItems;
end;
somit werden deine Items immer mit verändert wenn TDateLine neu gezeichnet wird, egal warum. Dazu must du aber auch die Ermittlung der Dimensionen deines Item dynamisch regeln. Das würde so gehen.

- Alle Datums/Zeitangaben werden als property gehalten und deren Änderung löst ein Item.Redraw aus,
- Im Item.Redraw wird zuerst left, top usw. in Bezug auf das als Eigenschaft gehaltene FDateLine ermittelt,
- das Item wird mit den neuen Koordinaten im DateLine gezeichnet.

Die entscheidende Frage ist dann immer nur wer das Zeichnen übernimmt, DateLine oder das Item selbst.

Unter dem Strich berechnet jedes Item seine Koordinaten in Bezug auf TDateLine zum Zeitpunkt des Neuzeichnens selbst. Von Außen reicht dann lediglich ein Aufruf von Redraw oder Paint oder Invalidate....


Gruß oki

uwewo 19. Okt 2006 09:58

Re: TCollection, TCollectionItem
 
Hi oki,

genau daran sitze ich gerade, allerdings muß man auch auf das StartDatum und EndDatum von TDateLine
eingehen. Also ob Items überhaupt gezeichnet werden sollen oder nicht.

Probleme habe ich nämlich, wenn ein Item z.Bsp. am 19.10.2006 beginnt am 21.10.06 endet und das StartDatum von TDateline am 20.10.06 gesetzt ist. Wie zeichne ich ein halbes Item?

Oder anderes Problem wenn ein Item außerhalb des sichtbaren Bereichs von TDateLine gescrollt wird.
das Item verschwindet zwar, wird aber beim zurückscrollen nicht automatisch neugezeichnet.


Zitat:

Zitat von oki
Überschreibe die procedure Paint von TDateLine und schon werden alle Items dem aktuellen DateLine automatisch angepaßt.

Iglaube da hast Du mich jetzt gerade auf den richtigen Weg gebracht.

uwewo 19. Okt 2006 13:35

Re: TCollection, TCollectionItem
 
Zitat:

Zitat von oki
Überschreibe die procedure Paint von TDateLine und schon werden alle Items dem aktuellen DateLine automatisch angepaßt.

Delphi-Quellcode:
    procedure Paint; override;
...

procedure TDateLine.Paint;
begin
  inherited;
  DrawItems;
end;

Leider funktioniert es so nicht, da sich das DateLine dann in einer Endlosschleife befindet.
Obwohl DrawItems nur die neue Position berechnet habe ich dann eine Prozessorauslastung von 100%.

Reagiere ich auf Veränderungen von TDateLine und rufe dann DrawItems auf, habe ich 0% Prozessorauslastung.

oki 19. Okt 2006 18:28

Re: TCollection, TCollectionItem
 
Hi uwewo,

folgende Bemerkung hat mich etwas grübeln lassen:

Zitat:

Zitat von uwewo
Leider funktioniert es so nicht, da sich das DateLine dann in einer Endlosschleife befindet.
Obwohl DrawItems nur die neue Position berechnet habe ich dann eine Prozessorauslastung von 100%.

Reagiere ich auf Veränderungen von TDateLine und rufe dann DrawItems auf, habe ich 0% Prozessorauslastung.

Das da was recursiv ist scheint klar zu sein. Das ist der normale Weg für das Zeichnen im Canvas.
Dann probier es doch mal andersrum
Delphi-Quellcode:
procedure Paint; override;
...

procedure TDateLine.Paint;
begin
  DrawItems;
  inherited;
end;
Meine Erfahrung ist, dass man einfach an zu vielen Stellen auf Änderungen reagieren muß. Da rutscht einem immer eine mit durch. Dann gibt es auch Aktionen, bei denen sich eigentlich nichts ändert, aber trozdem ein neu zeichnen notwendig wird. Da die DateItem aber nun auch wieder Controls sind müßten die entsprechende Redraw-Botschaften nach einem Verdecken (z.B. durch andere Fenster) ebenfalls erhalten.
Gut, teste mal die obere Methode und wir werden ja sehen was passiert.

Gruß oki

oki 19. Okt 2006 18:53

Re: TCollection, TCollectionItem
 
Hi uwewo,

mir ist noch was aufgefallen. in dieser Procedure
Delphi-Quellcode:
procedure TDateLine.UpdateDateLine;
ein UpdateItems ist nach deinem Verfahren dann auch schon mal die halbe Miete.

Desweiteren mußt du dafür sorgen, dass nach Eigenschaftsänderungen deines Item dieses auch aktualisiert wird.
Delphi-Quellcode:
{-----------------------------------------------------------------------------
  Procedure:  SetStartDate
  Date:       19-Okt-2006
  Arguments:  Value : TDateTime
  Result:     None
  Describtion: bei gleichen Werten ist ein Setzen unnötig und ein neu zeichnen
               (Invalidate) unerwünscht
-----------------------------------------------------------------------------}
procedure TDateItem.SetStartDate(Value : TDateTime);
begin
  if Value = FStartDate then Exit;
  FStartDate := Value;
  Invalidate;
end;
Verschiebe bitte die Function's von published in public!
Überlege, ob du für DateLine eine published-Eigenschaft StartDate anlegst. Das ist dann der erste Tag in der Anzeige.

gruß oki

uwewo 20. Okt 2006 06:41

Re: TCollection, TCollectionItem
 
Zitat:

Zitat von oki
mir ist noch was aufgefallen. in dieser Procedure
Delphi-Quellcode:
procedure TDateLine.UpdateDateLine;
ein UpdateItems ist nach deinem Verfahren dann auch schon mal die halbe Miete.

Genau hier habe ich auch angesetzt und es funktioniert auch soweit "fast" alles.


Zitat:

Zitat von oki
Delphi-Quellcode:
procedure TDateItem.SetStartDate(Value : TDateTime);
begin
  if Value = FStartDate then Exit;
  FStartDate := Value;
  Invalidate;
end;

Diese proceduren existieren bereits siehe hier

Delphi-Quellcode:
procedure TDateItem.SetStartDate(Value : TDateTime);
begin
  if Value <> FStartDate then
     Begin
       FStartDate := Value;
       Invalidate;
     End;
end;

procedure TDateItem.SetStartTime(Value : TTime);
begin
  if Value <> FStartTime then
     begin
       FStartTime := Value;
       Invalidate;
     end;
end;

procedure TDateItem.SetEndDate(Value : TDateTime);
begin
  if Value <> FEndDate then
     Begin
       FEndDate := Value;
       Invalidate;
     End;
end;

procedure TDateItem.SetEndTime(Value : TTime);
begin
  if Value <> FEndTime then
     Begin
       FEndTime := Value;
       Invalidate;
     End;
end;
Werde Dir heute noch den Source per PN schicken, damit Du siehst was ich verändert habe.

Uwe

uwewo 20. Okt 2006 07:36

Re: TCollection, TCollectionItem
 
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:

Zitat von oki
Überlege, ob du für DateLine eine published-Eigenschaft StartDate anlegst. Das ist dann der erste Tag in der Anzeige.

Das gibt es auch schon, allerdings im THeader nennt sich FirstDate, LastDate ansonsten würde mein Demo auch nicht funktionieren.

Hier übrigens mal ein Demo, nur um anderen einen Überblick zu geben über was wir hier reden.
Ich habe noch immer das Problem beim scrollen des Grids muß wohl auf eine Message vom Grid reagieren um es zu beheben.

Also keine Postings weil etwas nicht richtig gezeichnet wird :o

Uwe

uwewo 30. Okt 2006 06:08

Re: TCollection, TCollectionItem
 
Hallo oki,

war die ganze Zeit geschäftlich unterwegs und hatte daher auch keine Änderungen vorgenommen.
Bin nun aber ein bißchen weiter gekommen, Problem war ich hatte die x,y Position mit CellRect ermittelt, diese Funktion gibt aber 0,0 zurück wenn die Zeile,Spalte außerhalb des sichtbaren Bereichs liegt. Habe daher mir eine eigene Funktion geschrieben.

Mausscrollrad, Scrollbars, Tasten fange ich jetzt ab um die Items gegebenenfalls zu zeichnen.

Uwe

oki 30. Okt 2006 21:18

Re: TCollection, TCollectionItem
 
Hi uwewo,

leider ist meine Zeit aktuell etwas knapp, sonst hätte ich es schon ausprobiert. Ich glaube immer noch, dass es über die Paint-Procedure geht. Gut, dass du auch 'ne Zeit unterwegs bist. Vielleicht setz ich mich auch noch mal ran und Check das. Ich würde sagen, dass bei einer Änderung der DateLine Kompo, also neu zeichnen, nur die enthaltenen Kompos (DateItems) neu platziert werden müssen. So macht das doch auch jedes Fenster, dass andere Kompos als Parent hält.

Na mal schauen.

Gruß oki

uwewo 6. Nov 2006 06:24

Re: TCollection, TCollectionItem
 
Zitat:

Zitat von oki
Ich glaube immer noch, dass es über die Paint-Procedure geht.

Dieser Satz ging mir die ganze Woche nicht aus dem Kopf, da es ja eigentlich bei jedem Objekt funktioniert. Deshalb habe ich mich am Wochenende noch einmal daran gesetzt, und folgendes herausgefunden. Meine ersten Tests hatte ich so versucht.

Delphi-Quellcode:
procedure TDateLine.Paint;
begin
  inherited;
  UpdateItems;
end;
Dabei hatte ich eine Prozessorauslastung von ca. 100%

Delphi-Quellcode:
procedure TDateLine.Paint;
begin
  inherited Paint;
  UpdateItems;
end;
bringt den gewünschten Erfolg, was so ein Wort alles ausmachen kann :)

Werde Dir den geänderten Source diese Woche zukommen lassen.

Bis dann

Uwe

oki 6. Nov 2006 14:44

Re: TCollection, TCollectionItem
 
Hi uwewo,

wieder im Land?

Jetzt könnte ich ja gönnerhaft sagen -> "Meine Rede" . Aber ehrlich, wo ist da der Unterschied? Ich geb ja ehrlich zu, dass ich selber manchmal etwas paranoid bin und inherited sehr selte ohne Methodenname und Parameter aufrufe. Aber die Theorie sagt deutlich das ein einfaches inherited ausreicht. Mich würde mal interessieren wo der da hingesprungen ist. Bist du mal da durchgesteppt mit debugging?

son'st freut's mich, dass es funzt :thumb:

Gruß oki


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:46 Uhr.

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