Перейти к содержанию
Fire Monkey от А до Я
  • 0

Динамическое создание и уничтожение компонентов


NesDmitrijj

Вопрос

Здравствуйте!

 

Имею некую структуру типа record

type
  TMyRecord = record
    Rect:TRectangle;
    Text:TLabel;
  end;

и переменную

 m:array of TMyRecord;

По нажатию на одну кнопку выполняю код

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
  t1,t2:TDateTime;
  L:TLabel;
  R:TRectangle;
begin
  t1:=Now;
  SetLength(m,1000);
  BeginUpdate;
  for I := Low(m) to High(m) do
  begin
    R:=TRectangle.Create(ScrollBox1);
    R.Parent:=ScrollBox1;
    R.ClipChildren:=true;

    L:=TLabel.Create(R);
    L.Text:='Это строка №'+IntToStr(i);
    L.Parent:=R;

    m[i].Rect:=R;
    m[i].Text:=L;

    R:=nil;
    L:=nil;
  end;
  EndUpdate;
  Application.ProcessMessages;
  t2:=Now;

  ShowMessage('Начало в: '+DateTimeToStr(t1)+#13+
              'Завершение в: '+DateTimeToStr(t2)+#13+
              'Прошло:'+IntToStr(MilliSecondsBetween(t2,t1))+'мс');
end;

по нажатию на вторую кнопку - очищаю

procedure TForm1.Button2Click(Sender: TObject);
var
  i:integer;
begin
  for I := Low(m) to High(m) do
  begin
    m[i].Rect.Free;
    m[i].Rect:=nil;
    m[i].Text:=nil;
  end;
  SetLength(m,0);
end;

Вопрос:

При первом нажатии на первую кнопку процесс может занимать 400мс, при втором нажатии (после очистки) 1200мс и так по возрастающей. Почему повторное создание всегда дольше первого?

 

P.S. Приведенный код создан специально для примера (по аналогии с реально используемым). В реально мною используемом коде первое создание 300мс а последующие могут достигать и 3000мс (что в 10 раз дольше). Может чтото нужно сделать дополнительно после очистки?

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

1. Использование
t1:=Now;
t2:=Now;
и
MilliSecondsBetween(t2,t1)
не даст в Вашем случае точного результата. Подозреваю, что он всегда будет разным, и разница может быть очень существенной.

Однозначно, лучше использовать
TThread.GetTickCount для того чтобы "засечь время".

2.
BeginUpdate;
...
EndUpdate;
Application.ProcessMessages;

Это тоже не "выход из положения".
Если хотите точно засечь именно время "отрисовки", то нужно использовать
TThread.Synchronize(TThread.CurrentThread, .........

3. Для чего Вы используете BeginUpdate и, соответственно, EndUpdate?
Ведь в вашем случае они относятся к объекту Self, т.е. - к самой форме.

4. И самое главное. Простите за откровенность - как-то все очень "криво"... Все очень и очень НЕ "правильно" )

Может со мной не согласятся наши уважаемые гуру и кто-то захочет точно пояснить - почему у Вас происходит описанный Вами баг, но так не делается.
Не поймите меня не правильно - я не хочу никого обидеть (когда-то мы все такими были, и я в том числе))).

P.S. И еще возник сразу вопрос - это FMX-проект? Если да, то почему Вы не используете стили? Думаю, что зто Вам сильно упростило бы Ваши задачи, а заодно, и создали бы более удобный вариант (я бы даже сказал - более правильный с точки зрения ООП).
Динамические массивы и "записи" - без них часто не обойтись, либо можно, но проще с ними. Но это не в Вашем случае.

Ссылка на комментарий
  • 0

AlexG, это FMX-проект.

 

Данный пример набросан на скорую руку, чтобы желающие убедиться вооче в существовании проблемы, могли быстро вставить приведенный код у себя в проекте. Application.ProcessMessages используется для того, чтобы дождаться отрисовки компонентов, прежде чем зафиксировать время завершения и показать сообщение.

 

>3. Для чего Вы используете BeginUpdate и, соответственно, EndUpdate?

>Ведь в вашем случае они относятся к объекту Self, т.е. - к самой форме.

Верно, к форме, конечно можно было и ScrollBox1.BeginUpdate, но форма сама вызываем BeginUpdate у ScrollBox1.

 

>4. И самое главное. Простите за откровенность - как-то все очень "криво"... Все очень и очень НЕ "правильно" )

Согласен! Повторюсь, пример образный. Для бастрого достяжения требуемого эффекта.

 

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

Ссылка на комментарий
  • 0

Эксперементальным путем было выявлено, что проблема в скорости отрисовки компонентов. Если у ScrollBox1 свойство Visible установить в False, то создание и пересоздание компонентов происходит примерно за одно и тоже время (в первый раз 47мс против 868мс, в последующие 60-63 мс против 1200-1700мс). Но это, повторюсь, если родительский компонент (ScrollBox1) не виден. может кто знает как ускорить отрисовку?

Ссылка на комментарий
  • 0

1. Только-что попробовал именно Ваш код - он дает один и тот же результат по скорости, не зависимо от того - сколько раз нажимать...

Вывод: Вы либо что-то не дописали в своем примере, либо не точно описали последовательность. Даже не знаю...

 

2. Ну действительно - просто так не делается. Думаю, что не ошибусь если скажу - Вам не пишут потому, что Ваш "пример" плохой с точки зрения и ООП и вообще.

 

Зачем Вы используете TScrollBox? Насколько я понимаю Вам нужен некий список. Единственное его отличие от стандартного TListBox может быть в том, что Вам нужны какие-то "свои" элементы.

Ну так используйте в этом случае, предназначенный для "списков" TListBox, только с TListBoxItem со своим стилем... Это позволит Вам оперировать объектами (любыми!) "закрепленными" за каждым элементом списка, используя свой стиль (внешний вид элементов может быть таким, на что способна Ваша фантазия вообще (благо FMX позволяет в этом смысле вообще не иметь границ). Кроме того - работа TListBox оптимизирована по скорости, на мой взгляд, отлично, и избавит Вас от необходимости ковыряться со сложностями типа динамических массивов и записей.

 

P.S. Если я в чем-то не прав, и Вы не хотите здесь писать Ваш код, то напиши более точно - какие задачи перед Вами стоят и что в итоге Вы хотите получить.

Ссылка на комментарий
  • 0

AlexG, Ваше сообщение "Только-что попробовал именно Ваш код - он дает один и тот же результат по скорости, не зависимо от того - сколько раз нажимать..." побудило меня продолжить эксперимент. В итоге выяснилось, что разница во времени отрисовки компонентов наблюдается только если запустить программу в режиме отладки (по F9). Если запустить программу без отладки (через проводник или shift+ctrl+f9), то ситуация в коре меняется. Мало того, что первое создание компонентов быстрее чем раньше (в режиме отладки), так все последующие пересоздания еще быстрее чем в первый раз, и, соответственно разницы во времени практически нет, сколько не пересоздавай.

 

Так что вопрос можно считать решенным.

Ответ: подобное поведение наблюдается только в режиме отладки.

Ссылка на комментарий
Гость
Эта тема закрыта для публикации ответов.
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...