Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как скопировать компонент в run-time?


Страницы:   1 2

Piter ©   (2006-07-28 17:45:00) 

На форме есть TPanel, она соответствующим образом настроена - на ней находятся другие управляющие элементы, имеются обработчики событий и прочее. Панелей на форме может быть минимум одна, но точное количество неизвестно и выбирается пользователь в соответствии с тем как ему удобно.

Возникает вопрос - как "множить" панельки? Хотелось бы настроить одну панель, а потом ее просто клонировать, то что делается при CTRL+C / CTRL + V если ткнуть на компоненте в design-time.

Есть более-менее простые пути решения вопроса? Думал о сохранении компонента в поток, но ведь на этом компоненте находятся и другие компоненты, их бы тоже надо "проклонировать" :(

Или проще спроектировать панельку на форме, а потом просто ручками описать алгоритм ее создания и задания нужных свойство и обработчиков событий?


jack128   (2006-07-31 23:22:00) [1]

Piter ©   (31.07.06 22:06) [19]
TFrame - компонент для ленивых. Например те нужен компонент - панель, на которой дежит кнопка. ПРи клике на этой кнопке должен появляться MessageBox - c текстом "Кликнули по кнопке". Причем такая панель должна лежать на 20 формах. Это чтож, ты ты должен 20 раз кинуть панель на формы. 20 раз на эту панель кинуть кнопку. 20 прописать обработчик события этой кнопки. Так ?  Нет, на самом деле ты жмешь New/Frame, кидаешь на этот фрейм кнопку. прописываешь обработчик клика по этой кнопке и 20 кидаешь этот фрейм на нужные формы.  В пределе - в 3 раза меньше действий. А если учесть, что кода обычно бывает не один несчастный обработчик, а 20 методов, то экономия на лицо ;-)


tesseract   (2006-07-31 22:26:00) [2]

> [18] Игорь Шевченко ©   (31.07.06 16:26)


Я например использую его для этого оч часто.
С ними ИМХО проще, чем с репозитарием.

+ можно например между формами сохранять функциональность определённых элементов управления.


Piter   (2006-07-31 22:06:00) [3]

Игорь Шевченко ©   (31.07.06 16:26) [18]
Для облегчения повторного использования кода например


не понял. А можно пример?


Игорь Шевченко   (2006-07-31 16:26:00) [4]


> А я всегда думал - нафига нужен TFrame


Для облегчения повторного использования кода например.


Piter   (2006-07-31 16:15:00) [5]

Плохиш ©   (31.07.06 11:23) [15]
Ну фреймы как раз для решения задач из [0] и предназначены :-)


Да? Они могут копировать то, что на них лежит? Круто...
А я всегда думал - нафига нужен TFrame :)

По справке непонятно ничего :)


StriderMan   (2006-07-31 14:13:00) [6]

то что лежит на панельке само в поток не сохранится. ведь у контролов, лежащих на панельке, OWNERом является не панелька, а форма.


Плохиш   (2006-07-31 11:23:00) [7]


> Юрий Зотов ©   (29.07.06 14:48) [12]

Читая 5й пост тоже самое сказать захотелось, но без вопросительного знака :-)

> Piter ©   (29.07.06 16:00) [13]
> а что там с фреймом?

Ну фреймы как раз для решения задач из [0] и предназначены :-)


GrayFace   (2006-07-30 07:19:00) [8]

reonid ©   (29.07.06 0:38) [10]
TDummy

Спасибо, не знал, что можно методы класса так использовать.


Piter   (2006-07-29 16:00:00) [9]

Юрий Зотов ©   (29.07.06 14:48) [12]

а что там с фреймом? Я не в курсе, никогда не использовал :)


Юрий Зотов   (2006-07-29 14:48:00) [10]

Может быть, просто использовать фрейм вместо панели?


Piter   (2006-07-29 02:52:00) [11]

спасибо, буду разбираться.


reonid   (2006-07-29 00:38:00) [12]

procedure TForm1.btnClonePanelClick(Sender: TObject);
var stm: TStream;
begin
 stm := TMemoryStream.Create;
 try
   SaveComponentToStream(Panel1, Self, stm);
   stm.Position := 0;
   LoadComponentFromStream(Self, Self, Self, stm);
 finally
   stm.Free;
 end;
end;

{-----------------------------------------------------------}
unit Comp2Stm;

interface

uses
 Classes, Controls;

function LoadComponentFromStream(ARoot, AOwner: TComponent; AParent: TWinControl;
 SrcTxtStream: TStream; AComp: TComponent = nil): TComponent;

procedure SaveComponentToStream(AComp, ARoot: TComponent; DestTxtStream: TStream);

implementation

type
   TDummy = class
     class procedure ReaderSetName(Reader: TReader; Component: TComponent; var Name: string);
   end;

   class procedure TDummy.ReaderSetName(Reader: TReader; Component: TComponent; var Name: string);
   begin
     if (Reader.Owner <> nil) and
        (Reader.Owner.FindComponent(Name) <> nil) then Name := '';
     // Это самое простое, что можно придумать, чтобы избежать конфликта имён.
     // Всё равно в рантайме имена не слишком важны
   end;

function LoadComponentFromStream(ARoot, AOwner: TComponent; AParent: TWinControl;
 SrcTxtStream: TStream; AComp: TComponent = nil): TComponent;
var
 BinStream: TStream;
 Reader: TReader;
 Comp: TComponent;
begin
BinStream := TMemoryStream.Create;
try
  Reader := TReader.Create(BinStream, 4096);

  //SrcTxtStream.Position := 0;
  ObjectTextToBinary(SrcTxtStream, BinStream);
  try
    Reader.Position := 0;

    Reader.Owner := AOwner;
    Reader.Parent := AParent;
    Reader.Root := ARoot;
    // Владелец, родитель для создаваемого из потока
    // компонента и корневой компонент (в РТТИ-таблицах
    // которого ридер будет искать обработчики событий,
    // классы и т.д.)

    Reader.OnSetName := TDummy.ReaderSetName;
    // Для разрешения конфликтов имён

    //Reader.OnFindMethod := ;
    //Reader.OnFindComponentClass := ;

    Reader.BeginReferences;
    try
      Reader.ReadSignature;
      Comp := Reader.ReadComponent(AComp);
      Result := Comp;

      Reader.FixupReferences;
      // инициализирует свойства-ссылки на другие
      // компоненты, хранящиеся в ДФМ как имена

    finally
      Reader.EndReferences;
    end;
  finally
    Reader.Free;
  end;
finally
  BinStream.Free;
end;
end;

procedure SaveComponentToStream(AComp, ARoot: TComponent; DestTxtStream: TStream);
var BinStream: TStream;
   Writer: TWriter;
begin
 BinStream := TMemoryStream.Create();
 try
   Writer := TWriter.Create(BinStream, 4096);
   try
     Writer.Root := ARoot;
     Writer.WriteSignature;
     Writer.WriteComponent(AComp);
     Writer.WriteListEnd;

   finally
     Writer.Free;
   end;

   BinStream.Position := 0;
   ObjectBinaryToText(BinStream, DestTxtStream);
 finally
   BinStream.Free;
 end;
end;

end.


Мефисто   (2006-07-28 22:23:00) [13]

Piter  ©   (28.07.06 21:23) [8]

В поток сохраняются все published свойства. Все что доступно через RTTI. А Events - это указатель на код метода. Т.е. смысл сохранять указатель если при следующем запуске ПО он изменится. Можешь попытаться сделать парсер :) Просмотри форму ввиде ресурса и обрати внимание: OnClick = Button1Click.

Самое наверно простое поискать опенсорц компонет для свойств компонента в файл. А на его основе создать тебе клоноклепатель объектов ;) В ином случае, изучение TypInfo.pas не избежать.


Piter   (2006-07-28 21:23:00) [14]

Мефисто   (28.07.06 19:37) [6]
Ссылки на события (Events) не копируются


а вот это странно.


Piter   (2006-07-28 21:23:00) [15]

Хм... То есть, в потоке сохраняются и все сведения о компонентах, которые принадлежат нужному компоненту?

Странно... Он при считывании из потока создает что ли их всех...


Мефисто   (2006-07-28 19:37:00) [16]


> Мефисто   (28.07.06 19:22) [5]


Да, есть один офигенный минус. Ссылки на события (Events) не копируются. Надо вручную их навешивать. Еще помнится, в сети можно найти опенсорц компоненты которые сохроняют компоненты или форму в файл т.е. сохраняются все published свойства и события. Поищи и посмотри реализацию в них и можешь применить к своему копированию компонентов.

По событиям: теоритически. В клонированном объекте я так думаю индексы: TControl.Components[I]
TControl.Controls[I]
как и у оригинала (ского клонировали).

Т.е. пробежаться по этому массиву и через RTTI проверить есть ли событие на интересующем тебя событии. Если событие не пустое, то навешать его на клон.

uses TypInfo;

GetMethodProp()
SetMethodProp()


Мефисто   (2006-07-28 19:22:00) [17]


> Piter ©   (28.07.06 18:54) [4]


Сохранять контрол со всеми компонентами на нем можно. Но нужно учесть Мефисто    (28.07.06 17:53) [1].

Здесь сохраняется TPageControl со всеми TTabShet-ами и тем что лежит на TTabShet. А вот крутится с именами компонентов тебе придется в зависимости как и чего у тебя устроено. Можешь имена компонетов сразу в DesignTime удалить.

Procedure SaveProject(AFileName: TFileName);
 var
   FS: TFileStream;
begin
 FS := TFileStream.Create(AFileName, fmCreate or fmShareDenyRead);
 try
   FS.WriteComponent(Edit_FC.PageProject);
 finally
   FS.Free;
 end;
End;

Procedure LoadProject(AFileName: TFileName);
var
 FS: TFileStream;
 I: Integer;
begin
 FS := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyRead);
 try
   Edit_FC.PageProject := TPageControl(FS.ReadComponent(Edit_FC.PageProject));
 finally
   FS.Free;
 end;
End;


Piter   (2006-07-28 18:54:00) [18]

Мефисто   (28.07.06 18:47) [3]
А разве нельзя сохранять компонент с дочерними компонентами на нем?


вообще то в этом вопрос тоика заключается. Ты решил мой вопрос мне же переадресовать? :)


Мефисто   (2006-07-28 18:47:00) [19]


> на этом компоненте находятся и другие компоненты.


А разве нельзя сохранять компонент с дочерними компонентами на нем?
В этом плане проблем не должно быть.

P.S. или я тебя не верно понимаю?


Piter   (2006-07-28 18:30:00) [20]

понятно. Но я обозначил проблему - на этом компоненте находятся и другие компоненты.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо