Советы по Delphi

         

Дублирование компонентов и их потомков во время выполнения приложения II


Модуль, клонирующий компонент:

-------------------------------------------------------- модуль Clone;

    interface

uses

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, DBGrids, DB, DBTables, Outline;
function Replicator(C: TComponent): TComponent;

implementation

{ Следующая процедура "клонирует" свойства C1 и записывает их в C2.
C1 и C2 должны иметь один и тот же тип. Используйте данный метод для компонентов, не имеющих метода Assign. }

procedure CloneComponent(C1: TComponent; C2: TComponent); var S: TMemoryStream; begin if C1.ClassType <> C2.ClassType then raise EComponentError.Create('Типы объектов не совместимы'); if C1 is TWinControl then TWinControl(C2).Parent := TWinControl(C1).Parent; S := TMemoryStream.Create;   { создаем поток для работы с памятью } with S do begin WriteComponent(C1);         { пишем свойства C1 в поток } Seek(0, 0);                 { перемещаемся в начало потока } ReadComponent(C2);          { читаем свойства из потока в C2 } Free;                       { освобождаем поток } end; end;

{ Следующая функция "реплицирует" компонент C и возвращает новый компонент типа и со свойствами компонента C. }

function Replicator(C: TComponent): TComponent; begin Result := TComponentClass(C.ClassType).Create(C.Owner);  { создаем компонент } CloneComponent(C, Result);                               { клонируем его } end;
end.

Вот как это использовать это:

    var BitBtn: TBitBtn; begin TComponent(BitBtn) := Replicator(BitBtn1);  { Если BitBtn1 уже существует } end;

-- Xavier [000644]


Приведенный ниже код содержит функцию DuplicateComponents, позволяющую проводить клонирование любых компонентов и их потомков во время выполнения приложения. Действия ее напоминают операцию копирования/вставки (copy/paste) во время разработки приложения. Новые компоненты при создании получают тех же родителей, владельцев (в случае применения контейнеров) и имена (естественно, несколько отличающихся), что и оригиналы. В данной функции есть вероятность багов, но я пока их не обнаружил. Ошибки и недочеты могут возникнуть из-за редко применяемых специфических методов, которые, вместе с тем, могут помочь программистам, столкнувшимися с аналогичными проблемами.

Данная функция может оказаться весьма полезной в случае наличия нескольких одинаковых областей на форме с необходимостью синхронизации изменений в течение некоторого промежутка времени. Процедура создания дубликата проста до безобразия: разместите на TPanel или на другом родительском компоненте необходимые элементы управления и сделайте: "newpanel := DuplicateComponents(designedpanel)".

    uses
SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, IniFiles, TypInfo, Debug;
type
TUniqueReader = Class(TReader) LastRead: TComponent; procedure ComponentRead(Component: TComponent); procedure       SetNameUnique( Reader: TReader; Component: TComponent; var Name: string ); end;
implementation

procedure TUniqueReader.ComponentRead(
Component: TComponent );
begin
LastRead := Component; end;

procedure TUniqueReader.SetNameUnique(  // Задаем уникальное имя считываемому компоненту, например, "Panel2", если "Panel1" уже существует
Reader: TReader; Component: TComponent;              // Считываемый компонент var Name: string                    // Имя компонента для дальнейшей модификации );
var
i: Integer; tempname: string; begin
i := 0; tempname := Name; while Component.Owner.FindComponent(Name) <> nil do begin Inc(i); Name := Format('%s%d', [tempname, i]); end; end;

function DuplicateComponents(
AComponent: TComponent  // исходный компонент ): TComponent;              // возвращаемся к созданию нового компонента
procedure RegisterComponentClasses( AComponent: TComponent ); var i : integer; begin RegisterClass(TPersistentClass(AComponent.ClassType)); if AComponent is TWinControl then if TWinControl(AComponent).ControlCount > 0 then for i := 0 to (TWinControl(AComponent).ControlCount-1) do

RegisterComponentClasses(TWinControl(AComponent).Controls[i]);
end;
var
Stream: TMemoryStream; UniqueReader: TUniqueReader; Writer: TWriter; begin
result := nil; UniqueReader := nil; Writer := nil;
try Stream := TMemoryStream.Create; RegisterComponentClasses(AComponent);
try Writer := TWriter.Create(Stream, 4096); Writer.Root := AComponent.Owner; Writer.WriteSignature; Writer.WriteComponent(AComponent); Writer.WriteListEnd; finally Writer.Free; end;
Stream.Position := 0; try UniqueReader := TUniqueReader.Create(Stream, 4096);     // создаем поток, перемещающий данные о компоненте в конструктор UniqueReader.OnSetName := UniqueReader.SetNameUnique; UniqueReader.LastRead := nil;
if AComponent is TWinControl then
UniqueReader.ReadComponents(
// считываем компоненты и суб-компоненты
TWinControl(AComponent).Owner, TWinControl(AComponent).Parent, UniqueReader.ComponentRead ) else
UniqueReader.ReadComponents(
// читаем компоненты
AComponent.Owner, nil, UniqueReader.ComponentRead ); result := UniqueReader.LastRead; finally UniqueReader.Free; end; finally Stream.Free; end; end;
[000058]



Содержание раздела