![]() |
Komponentenentwicklung Problem mit Run- und DesignTime
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo und nochmal guten Tag,
noch ein kleines Problem, hab mir eine kleine Komponente geschrieben, die ich eigentlich mal wieder spassishalber (man kann sie ja eventuell noch mal in der Form verwenden) in mein Delphi 2007 Pro in der Toolpalette installieren wollte. Wenn ich dynamisch über die Unit diese verwende gibt es keine Probleme. Nach Installation kann man sie problemlos auf die Form ziehen und wenn man sie startet (ohne etwas zu verändern) klappt alles (man sieht die Trackbar auf der Form). Jetzt war aber der Sinn, der Komponente, dass über dem Pin für die Trackbar ein Label läuft, welches die Position mit einen vorgegebenen Skalierungsfaktor verrechnet und anzeigt. Wenn ich also die published Property "Labeled" im Objektinspektor von false (default-Einstellung) auf true setze, dann zeigt er das Label auch an (DesignTime) aber beim Starten (RunTime) kommt dann eine Fehlermeldung. Klar ist mir dabei, dass es anscheinend ein Problem damit gibt, dass zu dem Zeitpunkt, wo ein paar der Setter für das Label aufgerufen werden, die Trackbar (aufwelche diese teilweise zugreifen) noch nicht erzeugt wurde. Aber wie kann ich diese zwingen dies nicht zu tun? hab schon alles mit
Delphi-Quellcode:
versucht abzufangen, führt aber auch nur zu Problemen.
if assigned(Komponente) then ...
Hoffe jemand kann mir sagen, was ich da noch falsch mache. Vielen Dank im Voraus BAMatze Package zum Testen im Anhang |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Hi Matze,
Pack_eigene_Standartkomponenten fehlt leider im Archiv Gruß Marco |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Einige grundsätzliche Empfehlungen für den Komponentenbau:
- trenne Runtime und Designtime Package - erzeuge die eingebetteten Controls einmal im Konstructor deiner Komponente und benutze dies Visible Eigenschaft um die Sichtbarkeit zu regeln - arbeite an einigen Stellen mit der Eigenschaft ComponentState, welche dir angibt, ob du gerade im Design Modus bist oder obs das laufende Programm ist (und einiges mehr) wenn du unterschiedliches Verhalten während Run- und Designtime möchtest. |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Liste der Anhänge anzeigen (Anzahl: 1)
@Stevie: Das mit dem Trennen hab ich auch schon öfters gelesen, nur leider hab ich noch kein wirklich gutes Beispiel mal gesehen, wo dies konsequenter Weise dargestellt ist. Deswegen ist es für mich auch relativ schwer nachzuvollziehen, wie ich das adequat selber so programmiere. Meist hab ich das immer nach dem Prinzip "try and error" in einem einzigen Package programmiert. Ab und zu sind dort schon an der ein oder anderen Stellen die Componentstate´s zum Tragen gekommen. Nur wie dort jetzt eine "Trennung" stattfinden könnte, das ist für jemanden, der sowas noch nicht gemacht hat, meist schwer selber heraus zu finden.
@MarcoWarm Package ist im Anhang. |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Die Trennung in Designtime- und Runtime-packages ist immer dann sinnvoll, wenn die Komponente in beiden Umgebungen unterschiedliche Ressourcen verwendet. Wenn du beispielsweise zur Entwurfszeit selbsterstellte PropertyEditors verwendest (z.B. so etwas wie der Feldeditor von TTable), sollten die auch nur im Runtime-package drin sein.
|
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Im Setter führe ich Aktioneneigentlich immer nur dann aus, wenn der Wert sich auch verändert hat. Dadurch läßt sich hier z.B. ein zirkulärer Aufruf von SetValue und TrckChange stoppen.
Delphi-Quellcode:
Grüsse, Dirk
procedure TLabTrackBar.TrckBarAnpassung(TrackBar: TMouseTrackBar);
begin TrackBar.Width := Width - 20; TrackBar.Height := Height - 15; TrackBar.Left := 10; TrackBar.Top := 12; if Assigned(FLblTrckBar) and Assigned(FTrckBar) then begin FLblTrckBar.Caption := floattostr(FTrckBar.Position * FScaleFactor) + FsLabelAdd; LblAnpassung(FLblTrckBar); end; end; procedure TLabTrackBar.LblAnpassung(FLabel: TLabel); begin if Assigned(FLblTrckBar) and Assigned(FTrckBar) then FLblTrckBar.Left := Round((FTrckBar.Left + 11 - FLblTrckBar.Width / 2) + (FTrckBar.Position / (FTrckBar.Max - FTrckBar.Min) * (FTrckBar.Width - 22))); end; procedure TLabTrackBar.Resize; begin inherited Resize; TrckBarAnpassung(FTrckBar); // LblAnpassung(FLblTrckBar); unnötig, geschieht in TrckBarAnpassung. // warum werden überhaupt die eigenen Felder übergeben? end; procedure TLabTrackBar.SetValue(dValue: Double); begin if dValue <> FdValue then begin FdValue := dValue; if Assigned(FTrckBar) then FTrckBar.Position := Round(FdValue / FScaleFactor); LblAnpassung(FLblTrckBar); end; end; procedure TLabTrackBar.TrckChange(Sender: TObject); begin SetValue(FTrckBar.Position * FScaleFactor); end; |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Hallo an euch und danke für eure Posts, bin leider erst jetzt wieder dazu gekommen, hieran weiter zu arbeiten, da ich an einem 2. Projekt gerade arbeite un zusätzlich noch eine Abschlussarbeit in meinem Studium habe. Also Fulltime geplagt :D. Also @Dirk, werde ich gleich mal umsetzen, was du dort geschrieben hast. zu deiner Frage, wegen der Übergabe des eigenen Feldes: Habe ich mir deswegen so angewöhnt und umgesetzt, wenn ich mal mehr als eine gleiche Komponente (z.B. TTrackbar habe), damit ich alle dann in einer Procedure abhandeln kann und damit die Procedure dann weiß, welche der Komponenten es bearbeiten soll, übergebe ich sie dieser. Sicherlich ist es Ansichtssache/ Geschmackssache, ob dies gut oder schlecht ist, im Endeffekt teste ich einfach bestimmte Vorgehensweisen und versuche den für mich verständlichsten Weg zu finden. In dem Fall (ist ja nur ein Trackbar) ist es sicherlich unangebracht.
Falls jemand nochmal ein gutes (klein und verständliches) Beispiel kennt, für Trennung von Run- und DesignTime wäre ich dankbar, wenn ihr dies posten könntet. Vielen Dank BAMatze [Edit] Problem bleibt leider bestehen, dass ich ein Problem habe beim Zugriff bei den Settern anscheinend allgemein. Trotz Änderung gemäß Dirk:
Delphi-Quellcode:
[/Edit]
procedure TLabTrackBar.SetLabeled(bWert: Boolean);
begin if bWert <> FbLabeled then begin case bWert of true: begin FLblTrckBar := CreateLabel(floattostr(FtrckBar.Position*FScaleFactor) + FsLabelAdd); LblAnpassung(FLblTrckBar); end; false: FreeandNil(FLblTrckBar); end; FbLabeled := bWert; end; end; |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Hi,
irgendwie scheint es, ohne Nahe zu treten zu wohlen, das du mit get und set ganz allgemein ein Problem hast. Beispiel: Zitat:
Delphi-Quellcode:
sollte dann wohl so aussehen:
...
property Labeled: boolean read GetLabeled write SetLabeled; ...
Delphi-Quellcode:
Weiter geht es mit GetLabeled, statt so:
...
property Labeled: boolean read GetLabeled write SetLabeled default false; ...
Delphi-Quellcode:
lieber so:
function TLabTrackBar.GetLabeled;
begin result := FbLabeled; end;
Delphi-Quellcode:
Und bei SetLabeled, statt so:
function TLabTrackBar.GetLabeled;
begin if Assigned(FLblTrckBar) then result := FbLabeled else Result := false; end;
Delphi-Quellcode:
doch wohl eher so:
procedure TLabTrackBar.SetLabeled(bWert: Boolean);
begin case bWert of true: begin FLblTrckBar := CreateLabel(floattostr(FtrckBar.Position*FScaleFactor) + FsLabelAdd); LblAnpassung(FLblTrckBar); end; false: FreeandNil(FLblTrckBar); end; FbLabeled := bWert; end;
Delphi-Quellcode:
Nun zu Design- und Runtime:
procedure TLabTrackBar.SetLabeled(bWert: Boolean);
begin if FbLabeled <> bWert then begin FbLabeled := bWert; if FbLabeled then begin FLblTrckBar := CreateLabel(floattostr(FtrckBar.Position*FScaleFactor) + FsLabelAdd); LblAnpassung(FLblTrckBar); end else FLblTrckBar.Free; end; end; Ich persönlich nutze den kleinen Unterschied ganz gerne, wenn ich in einer Komponentensammlung intern wiederholt von gleichen Komponenten ableite, aber trotzdem einzelne Komponenten nutzen/veröffentlichen möchte. Auch hierzu ein Beispiel: Benötigt wird die Möglichkeit ein TPanel sichtbar/unsichtbar machen und darauf reagieren zu können. Daraus folgt:
Delphi-Quellcode:
Da ich innerhalb der Unit noch andere Objekte davon ableiten möchte, sind die properties nur public.
...
TVisibleChangeEvent = procedure (Value : Boolean) of object; ... TCustomPanel = class (TPanel) private FOnChangeVisible: TVisibleChangeEvent; function GetVisible: Boolean; procedure SetVisible(Value: Boolean); public property OnChangeVisible: TVisibleChangeEvent read FOnChangeVisible write FOnChangeVisible; property Visible: Boolean read GetVisible write SetVisible; end; ... implementation ... function TCustomPanel.GetVisible: Boolean; begin Result := TControl(Self).Visible; end; procedure TCustomPanel.SetVisible(Value: Boolean); begin TControl(Self).Visible := Value; if Assigned(FOnChangeVisible) then FOnChangeVisible(Value); end; ... Das Sichtbar machen für den User und damit für den Objektinspector erfolgt gesondert, und zwar in der Art, das ich ein weiteres Objekt im Interface-Teil deklariere:
Delphi-Quellcode:
Welchen Vorteil habe ich dadurch?
TVisblePanel = class (TCustomPanel)
published property OnChangeVisible; property Visible; end; Ganz Einfach, ich kann innerhalb der Unit bzw. der Komponentensammlung auf die deklarierten Eigenschaften der Objekte zugreifen. Innerhalb einer Unit, also mehrere Objekte mit dem gleichen Vorfahren kein Problem:
Delphi-Quellcode:
.
...
TCustomPanel = class(TGraphicControl) private FsLabelAdd: TLabel; ... end; TButtonPanel = class(TCustomPanel) ... end; ... implementation ... procedure TButtonPanel.SetVisible(Value: Boolean); begin TControl(Self).Visible := Value; FsLabelAdd := 'XX'; end; ... Und wenn beide Objekte in verschiedenen Units sind? Zugriff nicht möglich! Daher also, eher so:
Delphi-Quellcode:
Was erreiche ich dadurch?
...
TACustomPanel = class(TCustomPanel) private FsLabelAdd: TLabel; procedure SetLabelAdd(Value : String); function GetLabelAdd : String; ... protected property LabelAdd: string read GetLabelAdd write SetLabelAdd; end; TButtonPanel = class(TACustomPanel) ... end; ... implementation ... procedure TButtonPanel.SetLabelAdd(Value: String); begin if Assigned(TControl(Self).LabelAdd) then TControl(Self).LabelAdd := Value; end; ... procedure TButtonPanel.GetLabelAdd : String; begin if Assigned(TControl(Self).LabelAdd) then Result := TControl(Self).LabelAdd.Visible else Result := ''; end; procedure TButtonPanel.SetButtonVisible(Value : Boolean); begin if Assigned(FButton) then begin FButton.Visible := Value; if FButton.Visible then if Assigned(TControl(Self).LabelAdd) then TControl(Self).LabelAdd := 'mm'; end else if Assigned(TControl(Self).LabelAdd) then TControl(Self).LabelAdd.Free; end; Ich stelle in den Komponenten/Objekten nur die Eigenschaften in dem Sichtbarkeitsbereich zur Verfügung die ich als Entwickler auch wünsche und unterbinde auf alle anderen den Zugriff von außen. Qualitativ stelle ich so mit das zu erwartende Verhalten der Komponenten/Objekte sicher, nicht nur für mich, sondern auch für andere. Der Code für den Zugriff innerhalb einer Unit ist das schlechtere Beispiel, da die Owner-Komponente nicht mitbekommt das sich die Sichtbarkeit des Labels geändert hat, daher immer das Beispiel verwenden, dass die Möglichkeit der Nutzung in verschiedenen Units ermöglicht! Registriert werden im Abschluss nur die Komponenten/Objekte deren Eigenschaften auch published sind. Alles klar? viele Grüße Alter Mann PS Der Code dient nur zur Veranschaulichung und ist nicht getestet!!! |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Also @Alter Mann danke dir schonmal für diese ausführliche Erklärung. Muss das sicherlich noch 2 bis 3 mal durchlesen, damit ich alles auch 100% verstehe aber echt Klasse, habe sowas in der Art noch nirgendswo gesehen. Werde es morgen auf Arbeit umsetzen.
:dp: |
Re: Komponentenentwicklung Problem mit Run- und DesignTime
Zitat:
Kann hier jemand deshalb eine Empfehlung abgeben wann was sinnvoll erscheint? Ach ja, dann kenn ich noch die Sammlung mit den Windows 7 Komponenten, die ebenfalls nur als Designtime(?) ausgeliefert werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz