Entfernen und Ersetzen eine visuelle Komponente zur Laufzeit
Frage
Ist es möglich, zum Beispiel ersetzen und eine TEdit mit einer Unterklasse Komponente frei zur Laufzeit instanziiert (bedingt)? Wenn ja, wie und wann es getan werden sollte? Ich habe versucht, die Eltern zu null gesetzt und ich habe Fehler einen Runtime free () in Form Konstruktor und Methoden Afterconstruction aber in beiden Fällen zu nennen.
Als spezifischere, bekam ich eine Zugriffsverletzung (EAccessViolation). Es scheint, François recht, wenn er sagt, dass Komponenten im Rahmen costruction Verwirrungen mit Formular steuert Housekeeping zu befreien.
Lösung
Diese generische Routine arbeitet entweder mit einem Formular oder Frame (aktualisiert, um eine Unterklasse für die neue Steuerung zu verwenden):
function ReplaceControlEx(AControl: TControl; const AControlClass: TControlClass; const ANewName: string; const IsFreed : Boolean = True): TControl;
begin
if AControl = nil then
begin
Result := nil;
Exit;
end;
Result := AControlClass.Create(AControl.Owner);
CloneProperties(AControl, Result);// copy all properties to new control
// Result.Left := AControl.Left; // or copy some properties manually...
// Result.Top := AControl.Top;
Result.Name := ANewName;
Result.Parent := AControl.Parent; // needed for the InsertControl & RemoveControl magic
if IsFreed then
FreeAndNil(AControl);
end;
function ReplaceControl(AControl: TControl; const ANewName: string; const IsFreed : Boolean = True): TControl;
begin
if AControl = nil then
Result := nil
else
Result := ReplaceControlEx(AControl, TControlClass(AControl.ClassType), ANewName, IsFreed);
end;
diese Routine mit den Eigenschaften der neuen Steuerung zu übergeben
procedure CloneProperties(const Source: TControl; const Dest: TControl);
var
ms: TMemoryStream;
OldName: string;
begin
OldName := Source.Name;
Source.Name := ''; // needed to avoid Name collision
try
ms := TMemoryStream.Create;
try
ms.WriteComponent(Source);
ms.Position := 0;
ms.ReadComponent(Dest);
finally
ms.Free;
end;
finally
Source.Name := OldName;
end;
end;
verwenden Sie es wie:
procedure TFrame1.AfterConstruction;
var
I: Integer;
NewEdit: TMyEdit;
begin
inherited;
NewEdit := ReplaceControlEx(Edit1, TMyEdit, 'Edit2') as TMyEdit;
if Assigned(NewEdit) then
begin
NewEdit.Text := 'My Brand New Edit';
NewEdit.Author := 'Myself';
end;
for I:=0 to ControlCount-1 do
begin
ShowMessage(Controls[I].Name);
end;
end;
ACHTUNG: . Wenn Sie dies innerhalb des Afterconstruction des Rahmens tun, passen sie, dass die Hosting-Formular Bau noch nicht abgeschlossen ist
Befreit dort Controls, könnte eine Menge Probleme verursachen, wie Sie mit Formular-Steuerelemente Housekeeping sind vermasselt.
Sehen Sie, was Sie bekommen, wenn Sie versuchen, die neue Beschriftung bearbeiten lesen in der Showmessage anzuzeigen ...
In diesem Fall würde die Sie verwenden möchten
... ReplaceControl (Edit1, 'EDIT2', false )
und dann eine
... FreeAndNil (Edit1)
später.
Andere Tipps
Sie haben RemoveControl der TEdit der Eltern rufen Sie die Kontrolle zu entfernen. Verwenden Sie Insert das neue Steuerelement hinzuzufügen.
var Edit2: TEdit;
begin
Edit2 := TEdit.Create(self);
Edit2.Left := Edit1.Left;
Edit2.Top := Edit2.Top;
Edit1.Parent.Insertcontrol(Edit2);
TWinControl(Edit1.parent).RemoveControl(Edit1);
Edit1.Free;
end;
Ersetzen TEdit.Create auf die Klasse, die Sie verwenden möchten, und kopieren Sie alle Eigenschaften, die Sie brauchen, wie ich mit Links und Oben hat.
Sie können tatsächlich nutzen RTTI (Blick in die Typinfo-Einheit), um alle passende Objekte zu klonen. Ich schrieb Code für diese eine Weile zurück, aber ich kann es jetzt nicht finden. Ich werde Augen offen halten.