Einzelnen Beitrag anzeigen

Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
947 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

Re: Komponentenentwicklung Problem mit Run- und DesignTime

  Alt 27. Okt 2009, 19:52
Hi,

irgendwie scheint es, ohne Nahe zu treten zu wohlen, das du mit get und set ganz allgemein
ein Problem hast.

Beispiel:
Zitat:
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.
Davon ist aber im Code nichts zu sehen:
Delphi-Quellcode:
...
property Labeled: boolean read GetLabeled write SetLabeled;
...
sollte dann wohl so aussehen:
Delphi-Quellcode:
...
property Labeled: boolean read GetLabeled write SetLabeled default false;
...
Weiter geht es mit GetLabeled, statt so:
Delphi-Quellcode:
function TLabTrackBar.GetLabeled;
begin
  result := FbLabeled;
end;
lieber so:
Delphi-Quellcode:
function TLabTrackBar.GetLabeled;
begin
  if Assigned(FLblTrckBar) then result := FbLabeled
                           else Result := false;
end;
Und bei SetLabeled, statt so:
Delphi-Quellcode:
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;
doch wohl eher so:
Delphi-Quellcode:
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;
Nun zu Design- und Runtime:

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:
...
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;
...
Da ich innerhalb der Unit noch andere Objekte davon ableiten möchte, sind die properties nur public.
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:
TVisblePanel = class (TCustomPanel)
published
  property OnChangeVisible;
  property Visible;
end;
Welchen Vorteil habe ich dadurch?

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:
...
   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;
Was erreiche ich dadurch?

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!!!
  Mit Zitat antworten Zitat