Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  05:57[Войти] | [Зарегистрироваться]
Ответ на вопрос № 71499

30-06-2009 13:26
Здравствуйте, уважаемые рыцари!
  На форме ScrollBox, на нем панели с размещенными на них некоторым (разным) количеством
объектов  следующих классов, это будут: TSpeedButton, TPanel, TEdit, TStringGrid, TScrollBox...
  В run-time, по нажатию на один из SpeedButton'ов на любой из панелей должна быть
  создана точная копия (только, H будет +dH) этой самой панели и всех ее объектов
  (размеры, цвета и т.д.) вместе с их функциональностью. Данные копировать не надо,
  они будут другие.
  Сейчас я делаю так (попробовал сделать - получилось):
  Cначала создаю саму "несущую панель" панель, там где нужно (копирую все параметры
  с исходной).
  Затем в цикле для каждого Control'а на исходной панели проверяю его тип и создаю
  соответсвующий Control на новой панели. Каждое свойство "старого" объекта по
  одному копирую на новый объект:

  if Control is TStringGrid
  then
  begin
    OldStrG:=TStringGrid(Control);
    NewStrG:=TStringGrid.Create(PanelNew);
//    NewStrG.Assign(OldStrG);
    NewStrG.Parent:=PanelNew;
    NewStrG.Top:=OldStrG.Top;
    ... строк 15, наверно, будет ...
  end
  else
  if Control is T... then begin ... end
  else if ...
  ...

  Задумался, что это не есть хорошо и вот я здесь... Есть ли красивый или может
  быть правильный, способ клонирования? Чтоб после этого, новый экземпляр жил
  своей маленькой жизнью и всех радовал?
  Попробовал, Assign, получил: Debugger Exception Notification
---------------------------
Project MejPlan.exe raised exception class EConvertError with message
'Cannot assign a TStringGrid to a TStringGrid'. Process stopped.
Use Step or Run to continue.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

14-07-2009 15:22 | Сообщение от автора вопроса
Фреймы оказались очень кстати, сейчас осваиваюсь. Вопросы есть - решаю как могу, может быть не самыми оптимальными способами, но пока ощущение комфортное. Тупиковых ситуаций еще не было :).

13-07-2009 14:46
Минус небольшой чувствую в том, что везде теперь эти фреймы надо прописывать явно, т.е. так:
var
  aFrame1: TFrame1;
  aFrame2: TFrame2;
  aFrame3: TFrame3;
  aFrame4: TFrame4; // они все разные и
  aFrame5: TFrame5; // приходится делать кучу условий в каждом обработчике,
а раньше было так:
  aPanel: TPanel; // любая панель!


Существует много разных приёмов, о которых вы можете не догадываться, но которые могут сильно облегчить жизнь. Если вы опишите, что именно вам нужно от этих фреймов, как вы их хотите использовать и какие трудности встречаете на своём пути, то, возможно, вам смогут подсказать более оптимальное решение. Например, у меня есть большие сомнения по поводу необходимости использования переменных для обращения к динамически создаваемым фреймам...

13-07-2009 09:19 | Сообщение от автора вопроса
Не стал тянуть - переделал на фреймы :). Насоздавал в design-time каких нужно фреймов (шаблонов), все визуальное оптимизировал - получилось всего 5 "шаблонов". Теперь все экземпляры фреймов создаю только в run-time, когда и там, где это необходимо. Все поля пустые, у StringGrid'ов при Create фрейма заполняются только заголовки. Owner - у всех форма.
Минус небольшой чувствую в том, что везде теперь эти фреймы надо прописывать явно, т.е. так:
var
  aFrame1: TFrame1;
  aFrame2: TFrame2;
  aFrame3: TFrame3;
  aFrame4: TFrame4; // они все разные и
  aFrame5: TFrame5; // приходится делать кучу условий в каждом обработчике,
а раньше было так:
  aPanel: TPanel; // любая панель! С тем, что на ней работал через FindControl, а для этого придумал способ именования объектов, используя, так сказать, корни, например, Edit, суффиксы (все одинаковые для объектов одного клона, например 1r1) и окончания (_1p1). Придумать было нелегко:), но, достаточно легко использовать (не напрягаясь, собирал циклами имя любого объекта, например: 'Edit' или 'Label' + '2p3_2r1_2'). Но чтобы что-то изменить в desine - тяжело, "фиг", извиняюсь за французский, запомнишь все это.
Сейчас все очень наглядно: aFrame2.EditDate.Text ... :)))

12-07-2009 19:13
Клонировать и правда можно гораздо проще, чем присваиванием полей, но я так понял, Вам значения потом придется стирать если они должны быть пусты. На всякий случай, привел пример с использованием потоков (TMemoryStream), любой TControl формы клонируется в OnClick. Зато размеры всех клеточек грида сохраняются и т.д. А если копия должна выглядеть так, как разработано в design time и данные не должны сохраняться, лучше TFrame правда не найти.

type
  THackControl = class(TControl)
  end;

procedure TForm1.ControlClick(Sender: TObject);
var
  MemoryStream: TMemoryStream;
  NewControlName, TempName: string;
  OldControl, NewControl: TControl;
  ControlClass: TControlClass;
begin
  if not (Sender is TControl) then
    Exit;
  OldControl := Sender as TControl;
  ControlClass := TControlClass(OldControl.ClassType);
  MemoryStream := TMemoryStream.Create;
  try
    MemoryStream.WriteComponent(OldControl);
    MemoryStream.Position := 0;
    NewControl := ControlClass.Create(Self);
    TempName := OldControl.Name;
    try
      OldControl.Name := '';
      MemoryStream.ReadComponent(NewControl);
      with NewControl do
      begin
        Left := OldControl.Left + 5;
        Top := OldControl.Top + 5;
        Parent := Self;
        Name := Format('Panel%d_%d', [Left, Top]);
        THackControl(NewControl).OnClick := ControlClick;
      end;
    finally
      OldControl.Name := TempName;
    end;
  finally
    MemoryStream.Free;
  end;
end;


04-07-2009 20:07 | Сообщение от автора вопроса
Скажу я, вам, Frame'ы рулез!!! Жаль, что раньше не разобрался с ними. В одной из книжек я встретил такую формулировку (не цитата): "Используйте фрйэймы всегда, когда это необходимо, НЕ ДАРОМ они расположены в стандартных компонентах ПЕРВЫМИ."!!!
Удивительная память человека: "посмотрел" как первокласник на букварь на палитру и вспомнил, как это было 9 лет назад, фразу вспомнил почти дословно, потому-что удивился тогда такой категоричности. Необходимости в них не было, все эти годы занимался программами внешне скромными. Тогда попробовал - не получилось... и все, "осадочек" остался... И знаете что - вот, сейчас жалею себя - столько времени потратил зря :)!!! Теперь сам всем буду говорить: "Пользуйтесь фреймами"! В следующей версии будут фреймы :))). А эту всю свою "шелуху" вычищу начисто! Вот уж действительно, спасибо!

03-07-2009 19:53 | Сообщение от автора вопроса
Да, пожалуй, есть хороший смысл owner'ом делать форму! Сейчас я не уверен, надо ли переделывать, но когда буду писать выгрузку данных станет понятно... На сколько часто панели будут создаваться и уничтожаться, тут вопрос к заказчикам, мне так кажется, что или никогда - все данные сразу грузятся... или два раза в месяц - только одна дополнительная панель, но клиент всегда прав! И пусть ему будет хорошо, и это искренне! И пусть панелей будет столько, сколько надо для его работы. Спасибо за помощь!

02-07-2009 17:33
>>> Бел Амор, Вы не, ту строчку скопировали, создаю объект:  NewStrG:=TStringGrid.Create(PanelNew),

Хм... Действительно... Поторопился... :)

>>> На сколько я понимаю, Owner уничтожит своих подопечных, когда ему самому придет время?... У меня уже сомнение появилось...

Owner - тот, кто будет уничтожать компоненты, находящиеся в его списке Components при своём уничтожении. Все копоненты, которые помещаются на форму в дизайнере, автоматически имеют Owner'ом форму. В список Components формы попадают как визуальные компоненты (TPanel, TEdit и др.), так и невизуальные (TTable, TDataSource и т.д.).
Parent - тот, на ком визуально "лежит" элемент управления. В его списке Controls содержатся уже только наследники TControl, т.е. именно визуальные компоненты вроде TPanel, TEdit и др., находящиеся именно на нём. Невизуальные компоненты вроде TDataSource в этот список входить не могут. К невизуальным также относятся компоненты, которые иногда называют "псевдовизуальными". Они вроде бы иногда становятся видимыми, но они не лежат на каком-либо визуальном компоненте и не имеют координат на нём. Они являются компонентами (наследниками TComponent), но не являются наследниками TControl. К таким "псевдовизуальным" компонентам относятся, например, TPopupMenu, TOpenDialog.

>>> Я рассудил так: если владельцем будет форма - придется все динамическое хранить в списке, и следить за "чистотой его рядов". Если панель не убирает свое хозяйство, когда сама Destroy'ится, буду добавлять и удалять объекты "вручную"

Здесь есть такой момент: своих "подопечных" уничтожает не только Owner, но и Parent. Так что, если вы поместите на панель элемент, для которого Owner - форма, а Parent - соответственно, панель, то при ручном уничтожении панели она уничтожит и этот элемент, поскольку, она для него хоть и не Owner, но всё-таки Parent.
Рекомендация всегда назначать динамически создаваемым элементам Owner'ом форму связана с тем, что в этом случае мы получаем следующее:
1. Однообразие: мы всегда знаем, кто является владельцем любого элемента, находящегося на форме.
2. Расширение возможностей: в лице Components формы мы всегда имеем под рукой список всех компонентов, находящихся на форме, независимо от их визуального расположения. А элементы, расположенные, например, на конкретной панели, мы всегда можем найти через Controls этой панели.
Эта рекомендация не является категоричной, при наличии необходимости можно от неё отходить, но в общем случае лучше придерживаться. В случае, когда панели интенсивно создаются и уничтожаются, наверное, логичнее назначать владельцем именно панель, чтобы лишний раз не дёргать форму, заставляя её каждый раз перестраивать достаточно длинный список Components.

Копирование свойств необходимо, что-бы, внутреннее размещение объектов на новой панели воспроизвести в точности как на "клонируемой", и цвета и шрифты, кстати, теперь это происходит совершенно замечательно!
С фреймами я, как-то, сходу, не разобрался, к сожалению. А панельки разные, "клонируются" все этой одной процедурой - совершенно любая из имеющихся, меньше 200 строк кода получилось.


Я не настаиваю на фреймах, тем более, если у вас уже есть работающий вариант. Но при случае, с фреймами лучше познакомиться - пригодится. Так, пару слов:
1. Создаётся и разрабатывается так-же как и форма:
  File-New-Other-Delphi Projects-Delphi Files-Frame-Ok
2. Используется:
  а) В дизайнере: Палитра-Standard-Frames-клик на форме, выбор из списка.
  б) В рантайм: создаётся и вставляется как обычный элемент, но появляется весь фрейм со всеми находящимися на нём элементами.

При работе с фреймами есть ряд особенностей, со временем разберётесь. А в качестве примера могу предложить »вопрос КС №66089«

P.S. Не совсем по теме, но, возможно, вам будет ещё интересен »вопрос КС №71458«

02-07-2009 12:50 | Сообщение от автора вопроса
Бел Амор, Вы не, ту строчку скопировали, создаю объект:  NewStrG:=TStringGrid.Create(PanelNew),
а этой:  OldStrG:=TStringGrid(Control) - привожу Control к нужному классу, в данном случае это TStringGrid, чтоб его свойства присвоить новому StringGrid'у.

procedure TFormMain.BtAddClick(Sender: TObject);
var
  Control: TControl;
  OldStrG, NewStrG: TStringGrid;
  OldEdit, NewEdit: TEdit;
  OldPanel, NewPanel: TPanel;
  SpBt: TSpeedButton;
...
begin
  SpBt:=Sender as TSpeedButton;  // где-то нажата кнопка '+'...
  OldPanel:=(SpBt.Parent as TPanel); // на этой панели!

  NewPanel:=TPanel.Create(OldPanel.Parent as TPanel);
// на самом деле все немного по другому, но думаю, так тоже будет работать.
// Текст этот набираю здесь (не копирую), чтоб имена были как в вопросе.
...
// Выставляю свойства у новой панели - это не интересно.
...
  for i:=0 to OldPanel.ControlCount-1 do
  begin
    Control:=OldPanel.Controls[i];
    if Control is TEdit
    then
    begin
      OldEdit:=TEdit(Control);
      NewEdit:=TEdit.Create(NewPanel);
      NewEdit.Parent:=NewPanel;
      NewEdit.Font:=OldEdit.Font;
      ...// копирую свойства Edit'а
    end
    else
      if Control is TStringGrid
      then
      begin
        ...// фсе повторяется опять...
      end
      else
        if Control is TSpeedButton
        then
        begin
          ...// вот, такая лестница из классов...
        end
          ...


Old'ы - никогда не будут самостоятельными объектами - только указывать на существующие,
а создаваемые New'сы - будут храниться, у Owner'а.

На сколько я понимаю, Owner уничтожит своих подопечных, когда ему самому придет время?... У меня уже сомнение появилось... Здесь я надеюсь на комментарии, пока не поздно :))). До этого ничего визуального в Run-Time не Create'ил.

Я рассудил так: если владельцем будет форма - придется все динамическое хранить в списке, и следить за "чистотой его рядов". Если панель не убирает свое хозяйство, когда сама Destroy'ится, буду добавлять и удалять объекты "вручную" :) - как иногда здесь пишут. Чуть раньше такой список был - потом, вот, "озарило". Если что все верну - легко!

Копирование свойств необходимо, что-бы, внутреннее размещение объектов на новой панели воспроизвести в точности как на "клонируемой", и цвета и шрифты, кстати, теперь это происходит совершенно замечательно!

С фреймами я, как-то, сходу, не разобрался, к сожалению. А панельки разные, "клонируются" все этой одной процедурой - совершенно любая из имеющихся, меньше 200 строк кода получилось. Думаю, сюда её не надо - адаптировать много придется.
Сейчас работаю в Delphi 6.

30-06-2009 15:21
Хотя мне сложно представить необходимость такого клонирования, как вы описали в вопросе, хотел бы всё-таки обратить внимание на несколько моментов в вашем коде.

>>> OldStrG:=TStringGrid(Control);

Владельцем лучше всегда назначать форму, если нет веских оснований поступать иначе:
OldStrG:=TStringGrid(Self);

  if Control is TStringGrid
  then
  begin
    OldStrG:=TStringGrid(Control);
    NewStrG:=TStringGrid.Create(PanelNew);
//    NewStrG.Assign(OldStrG);
    NewStrG.Parent:=PanelNew;
    NewStrG.Top:=OldStrG.Top;
    ... строк 15, наверно, будет ...
  end


Многие свойства, в частности, координаты и размеры, объявляются в TControl, соответственно, нет совершенно никакой необходимости дублировать присваивание Left, Top, Width, Height для каждого конкретного типа.

на любой из панелей должна быть
  создана точная копия (только, H будет +dH)


Если вы используете Delphi выше 7 версии, возможно, вам будет небезынтересна TFlowPanel: »вопрос КС №70414«

30-06-2009 14:30
В run-time, по нажатию на один из SpeedButton'ов на любой из панелей должна быть
  создана точная копия (только, H будет +dH) этой самой панели и всех ее объектов
  (размеры, цвета и т.д.) вместе с их функциональностью.


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

30-06-2009 13:45 | Сообщение от автора вопроса
Ясно... Я уже насобирал всех свойств и методов в "лестницу". Спасибо!
P.S. Глаза боятся, а руки делают :)

30-06-2009 13:33
Assign точно не сработает - для визуальных компонентов он не реализуется. Разве что вы напишете наследников, реализуете там Assign сами и будете использовать только их.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Какой месяц идет после марта?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования