Delphi Win32: ускорение динамически создаваемых элементов управления (свойство Parent) - PullRequest
6 голосов
/ 15 апреля 2009

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

Однако есть одна большая проблема: она довольно медленная! Создание элементов управления не занимает много времени, но установка свойства Parent кажется очень трудоемкой.

Я пробовал несколько способов ускорить процесс, но безуспешно. Я пробовал Enabled = False, Visible = False, DisableAlign, LockWindowUpdate, WM_SETREDRAW ... но, похоже, ничто не влияет на длительный процесс установки родительского элемента управления.

Даже если мы используем потоки, это займет время, так как функции VCL должны вызываться в Synchronize.

Есть ли другой способ ускорить создание и отображение элементов управления?

С уважением, Magnus

Редактировать: Нет компонентов с данными или каких-либо событий, запускаемых в графическом интерфейсе. Я только создаю элементы управления и отображаю их. Используя таймеры, я определил назначение родительского элемента управления (AControl.Parent: = AOwner) как часть, требующую много времени.

Редактировать 2: Как показано в ответе ниже, проблема скорости заключается не в настройке родителя, а в рисовании элемента управления. Когда я проверил время, контейнер был виден, и установка родительского элемента вызвала немедленное окрашивание элемента управления.

Редактировать 3: Еще одна трудоемкая часть нашего динамического графического интерфейса - назначение элементов в комбинированные списки. ComboBox.Items.Assign (DataItems), где DataItems содержат не более трех-шести элементов.

Спасибо всем, что нашли время помочь мне!

Ответы [ 8 ]

5 голосов
/ 15 апреля 2009

Не пытайтесь использовать несколько потоков для создания элементов управления или для работы с VCL в целом. В любом случае, это не улучшит скорость, но, что более важно, это полное нет-нет с VCL.

Редактировать: Вы должны прочитать другие вопросы и ответы здесь, в StackOverflow, которые касаются VCL и нескольких потоков, но вкратце: VCL не является потокобезопасным, любой доступ к элементам управления должен быть сделано в контексте основного потока. Таким образом, при использовании нескольких потоков вам придется обернуть почти все в вызовы Synchronize () , которые фактически сериализуют все потоки и еще больше замедляют работу.

Лучше всего реструктурировать пользовательский интерфейс, чтобы его не нужно было создавать сразу. Создайте все кадры по требованию, только когда они должны быть показаны впервые.

Редактировать 2: Вот некоторый тестовый код, показывающий, что установка свойства Parent не является реальной проблемой, но, вероятно, создание всех элементов управления (со всей обработкой сообщений).

procedure TForm1.Button1Click(Sender: TObject);
var
  i, j, x, y: integer;
  Edit: TEdit;
  Ticks: LongWord;
begin
  Visible := FALSE;
  DestroyHandle;

  try
    for i := 1 to 20 do begin
      y := 20 + i * 25;
      for j := 1 to 10 do begin
        x := (j - 1) * 100;

        Edit := TEdit.Create(Self);
        Edit.SetBounds(x, y, 98, 23);
        Edit.Parent := Self;
      end;
    end;
  finally
    Ticks := timeGetTime;
    Visible := TRUE;
    Caption := IntToStr(timeGetTime - Ticks);
  end;
end;

Код динамически создает 200 TEdit элементов управления после освобождения дескриптора родительской формы. Создание всех этих элементов управления и установка их свойств занимает в моей системе несколько 10 миллисекунд, но, наконец, отображение формы (которая создаст все окна) занимает несколько 100 миллисекунд. Поскольку это можно сделать только в основном потоке, я сомневаюсь, что использование нескольких потоков поможет вам.

2 голосов
/ 15 апреля 2009

Я обнаружил эту проблему некоторое время назад и значительно улучшил время создания, просто разместив элементы управления во «временном» фрейме (то есть в том, который не присвоен форме). Я считаю, что медлительность сводится к тому, что каждый элемент управления взаимодействует с родительской формой (наконец-то) для множества вызовов, таких как SetBounds, SetVisible и т. Д. Используя плавающий фрейм, вы можете покончить с этим, а затем назначить фрейм форме что вам нужно.

2 голосов
/ 15 апреля 2009

Что вы устанавливаете на DisableAlign? Попробуйте выполнить DisableAlign для каждого элемента управления, который может содержать дочерние элементы управления (например, панели). Ранее я видел, как результат DisableAlign значительно увеличил динамически создаваемые формы.

Редактировать: Думая об этом еще немного, мой ответ был частично умозрительным. Я не знаю, повлияет ли эффект установки DisableAlign на корень дерева элементов управления на его потомков или нет. Я предположил, что это не так, но, возможно, это так. Я должен был бы посмотреть на код VCL. (Однако часть о ускорении была правдой.)

2 голосов
/ 15 апреля 2009

Я не знаю, сработает ли это, но вы пытались создать свои формы в текстовом формате .dfm, а затем с помощью функции ObjectTextToBinary загрузить .dfm прямо в форму. Это может или не может работать, стоит исследовать.

1 голос
/ 15 апреля 2009

Еще одна дикая догадка: попробуйте создать свой контейнер (форму, панель или фрейм) с помощью Visible: = false. Затем прикрепите к нему все динамически созданные элементы управления и установите Visible: = true

1 голос
/ 15 апреля 2009

Если вы используете элементы управления данными, убедитесь, что вы вызываете DisableControls в TDataSet. Это также может вызвать много перекрашиваний.

1 голос
/ 15 апреля 2009

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

Вы пробовали Profiler? Возможно, ваш графический интерфейс слишком подключен, а обновление / подключение вызывает много ненужных событий / побочных эффектов. Используя профилировщик, вы сможете лучше понять, что на самом деле приводит к низкой производительности. Это может, например, сигнализировать, что вы потратили много времени, просто ожидая возврата БД, или может быть, что каждый набор вызывает событие, которое запускает другое событие.

0 голосов
/ 15 апреля 2009

Просто дикая догадка: может быть, это поможет установить родителей элементов управления в обратном иерархическом порядке, то есть сначала установить родительский элемент для элементов с наиболее глубоким вложением, затем родительских элементов и т. может отключить некоторые лишние обновления, потому что Windows еще не «знает» о ваших элементах управления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...