Question

Est-il possible, par exemple, de remplacer et de libérer un TEdit par un composant sous-classé instancié (sous condition) au moment de l'exécution? Si oui, comment et quand cela devrait-il être fait? J'ai essayé de définir le parent sur nil et d'appeler free () dans le constructeur de formulaire et les méthodes AfterConstruction, mais dans les deux cas, une erreur d'exécution s'est produite.

Étant plus spécifique, une erreur de violation d'accès (EAccessViolation) s'est produite. Il semblerait que François ait raison quand il dit que la libération de composants lors de la reconstruction de trames entraîne des problèmes avec la gestion des commandes de formulaire.

Était-ce utile?

La solution

Cette routine plus générique fonctionne avec un formulaire ou un cadre (mis à jour pour utiliser une sous-classe pour le nouveau contrôle):

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;

utilisant cette routine pour transmettre les propriétés au nouveau contrôle

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;

utilisez-le comme:

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;

ATTENTION : si vous effectuez cette opération dans AfterConstruction du cadre, prenez garde que la construction du formulaire d'hébergement n'est pas encore terminée.
Libérer les contrôles là-bas pourrait causer beaucoup de problèmes pendant que vous bousiller avec l'entretien des contrôles de formulaires.
Découvrez ce que vous obtenez si vous essayez de lire la nouvelle légende de modification à afficher dans ShowMessage ...
Dans ce cas, vous voudriez utiliser
  ... ReplaceControl (Edit1, 'Edit2', False )

et ensuite faire un
  ... FreeAndNil (Edit1)
plus tard.

Autres conseils

Vous devez appeler RemoveControl du parent du TEdit pour supprimer le contrôle. Utilisez InsertControl pour ajouter le nouveau contrôle.

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;

Remplacez TEdit.Create dans la classe que vous souhaitez utiliser et copiez toutes les propriétés dont vous avez besoin, comme je l'avais fait avec Left et Top.

Vous pouvez réellement utiliser RTTI (regardez dans l'unité TypInfo) pour cloner toutes les propriétés correspondantes. J'ai écrit du code pour cela il y a quelque temps, mais je ne le trouve pas maintenant. Je vais continuer à chercher.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top