Советы по 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);varS: TMemoryStream;beginif C1.ClassType <> C2.ClassType thenraise EComponentError.Create('Типы объектов не совместимы');if C1 is TWinControl thenTWinControl(C2).Parent := TWinControl(C1).Parent;S := TMemoryStream.Create; { создаем поток для работы с памятью }with S do beginWriteComponent(C1); { пишем свойства C1 в поток }Seek(0, 0); { перемещаемся в начало потока }ReadComponent(C2); { читаем свойства из потока в C2 }Free; { освобождаем поток }end;end;

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

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

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



varBitBtn: TBitBtn;beginTComponent(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 beginInc(i);Name := Format('%s%d', [tempname, i]);end;end;

function DuplicateComponents(
AComponent: TComponent // исходный компонент): TComponent; // возвращаемся к созданию нового компонента
procedure RegisterComponentClasses(AComponent: TComponent);vari : integer;beginRegisterClass(TPersistentClass(AComponent.ClassType));if AComponent is TWinControl thenif TWinControl(AComponent).ControlCount > 0 thenfor 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;
tryStream := TMemoryStream.Create;RegisterComponentClasses(AComponent);
tryWriter := TWriter.Create(Stream, 4096);Writer.Root := AComponent.Owner;Writer.WriteSignature;Writer.WriteComponent(AComponent);Writer.WriteListEnd;finallyWriter.Free;end;
Stream.Position := 0;tryUniqueReader := 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;finallyUniqueReader.Free;end;finallyStream.Free;end;end;
[000058]



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