Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Проблемы с замедлением FMX UI в Windows приложениях после обновления до Delphi 12: поиск решений

Delphi , Программа и Интерфейс , MDI приложения

Замедление FMX UI в Delphi 12: Анализ и решения

После обновления до Delphi 12 многие разработчики столкнулись с проблемой значительного замедления интерфейса FireMonkey (FMX) в Windows-приложениях. В этой статье мы рассмотрим возможные причины этой проблемы и предложим решения, основанные на опыте сообщества Delphi.

Описание проблемы:

Пользователи сообщают о снижении производительности, особенно при работе с графическими элементами, такими как TImage и TRectangle. Операции, которые ранее выполнялись быстро, теперь занимают неприемлемо много времени, делая приложения практически неюзабельными.

Первоначальное предположение и его опровержение:

Первоначально проблема была связана с отрисовкой TImage, но дальнейшее исследование показало, что виновником является процедура BringToFront, которая стала значительно медленнее в Delphi 12.1 по сравнению с Delphi 11.

Решение 1: Использование TLayout в качестве родительского элемента:

Один из пользователей обнаружил, что перенос элементов управления (например, TRectangle) с формы (TForm) на TLayout значительно повышает производительность. Это связано с тем, как TForm обрабатывает обновление и Z-порядок своих компонентов.

Пример кода:

var
  i, x, y: Integer;
  l: TLayout;
begin
  SetLength(arrRect,961);
  l := TLayout.Create(Self);
  l.Parent := Self;
  l.Align := TAlignLayout.Client;

  i := 0;
  for x := 0 to 30 do begin
    for y := 0 to 30 do begin
      arrRect[i] := TRectangle.Create(Self);
      arrRect[i].Parent := l; // Parent to TLayout instead of TForm
      arrRect[i].SetBounds(x * 30,y * 30,20,20);
      Inc(i)
    end
  end;

  for j := 0 to 1000 do begin
    l.BeginUpdate;
    for i := 0 to 960 do begin
      arrRect[i].Position.X := arrRect[i].Position.X + 1
    end;
    l.EndUpdate;
    Application.ProcessMessages
  end
end;

Альтернативное решение 1: Избегайте прямого изменения Position.X:

Вместо прямого изменения свойства Position.X, используйте метод SetBounds для обновления позиции и размеров элемента.

arrRect[i].SetBounds(arrRect[i].Position.X + 1,arrRect[i].Position.Y,arrRect[i].Width,arrRect[i].Height);

Это может значительно повысить производительность по сравнению с прямым изменением Position.X.

Решение 2: Оптимизация отрисовки с использованием Skia и других графических библиотек:

Хотя изначально сообщалось о замедлении при использовании Skia, правильная настройка может улучшить производительность. Если вы используете Skia, рассмотрите возможность включения других графических библиотек на других платформах и отключения растризации Skia:

GlobalUseSkia := True;
{$IF Defined(OSX) or Defined(IOS)}
GlobalUseMetal := true;
{$ENDIF}
{$IFDEF ANDROID}
GlobalUseVulkan := true;
GlobalUseSkiaRasterWhenAvailable:=false;
{$ENDIF}
{$IFDEF MSWINDOWS}
GlobalUseSkiaRasterWhenAvailable:=false;
{$ENDIF}

Решение 3: Использование многопоточности (Parallel.For) для обновления UI:

Хотя работа с визуальными компонентами в потоках обычно не рекомендуется, в данном случае, когда обновление UI приостановлено с помощью BeginUpdate/EndUpdate, можно использовать Parallel.For из модуля System.Threading для параллельного обновления позиций элементов.

Пример кода:

uses
  System.Threading;

...

for j := 0 to 1000 do
begin
  BeginUpdate;
  try
    TParallel.For(0, 960,
      procedure(i: Integer)
      begin
        arrRect[i].Position.x := arrRect[i].Position.x + 1
      end);
  finally
    EndUpdate;
  end;
  Application.ProcessMessages;
end;

Важно: Использование Application.ProcessMessages может быть нежелательным. Рассмотрите альтернативные способы обработки событий, например, использование TThread.ForceQueue для асинхронного обновления UI.

Альтернативное решение 3: Асинхронное обновление UI с использованием TThread.ForceQueue:

unit Unit1;

interface

uses
  System.SysUtils,
  System.Types,
  System.UITypes,
  System.Classes,
  System.Variants,
  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.Controls.Presentation,
  FMX.StdCtrls,
  FMX.Objects;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    arrRect: TArray<TRectangle>;
    Counter: integer;
    procedure DoMove;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses
  System.Threading;

procedure TForm1.Button1Click(Sender: TObject);
var
  i, j, x, y: integer;
begin
  Button1.Enabled := false;
  SetLength(arrRect, 961);
  BeginUpdate;
  try
    i := 0;
    for x := 0 to 30 do
    begin
      for y := 0 to 30 do
      begin
        arrRect := TRectangle.Create(Self);
        arrRect.Parent := Self;
        arrRect.SetBounds(x * 30, y * 30, 20, 20);
        Inc(i)
      end
    end;
  finally
    EndUpdate;
  end;
  Counter := 1000;
  DoMove;
end;

procedure TForm1.DoMove;
begin
  BeginUpdate;
  try
    TParallel.For(0, 960,
      procedure(i: integer)
      begin
        arrRect[i].Position.x := arrRect[i].Position.x + 1
      end);
  finally
    EndUpdate;
  end;
  dec(Counter);
  if (Counter > 0) then
    TThread.ForceQueue(nil,
      procedure
      begin
        DoMove;
      end);
end;

end.

Решение 4: Избегайте частого использования BringToFront:

Процедура BringToFront может быть ресурсоемкой, особенно при большом количестве компонентов. По возможности, избегайте ее частого использования или оптимизируйте логику, чтобы минимизировать количество вызовов.

Анализ проблемы с использованием профилировщика:

Использование профилировщика (например, VTune) может помочь выявить узкие места в коде. В данном случае было обнаружено, что функция FMX.Types.AlignObjects занимает большую часть времени при обновлении UI, особенно когда элементы управления расположены непосредственно на форме (TForm).

Причина замедления: TCustomForm.Realign и AlignObjects:

Когда прямоугольники находятся на форме, AlignObjects вызывается из TCustomForm.Realign, что приводит к значительным задержкам. AlignObjects().DoAlign() перечисляет все дочерние элементы формы (Form.Children), что может быть медленным при большом количестве компонентов.

Вывод:

Замедление FMX UI в Delphi 12 может быть вызвано несколькими факторами, включая неоптимальное использование BringToFront, прямое изменение Position.X, и особенности обработки компонентов на форме (TForm). Использование TLayout в качестве родительского элемента, оптимизация отрисовки с помощью Skia и других графических библиотек, а также использование многопоточности могут помочь повысить производительность. Также важно анализировать код с помощью профилировщика для выявления узких мест и оптимизации критических участков. Важно помнить, что каждое приложение уникально, и оптимальное решение может зависеть от конкретной структуры и логики вашего кода.

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

В статье рассматриваются причины замедления интерфейса FireMonkey (FMX) в Delphi 12 и предлагаются решения для повышения производительности, включая использование TLayout, оптимизацию отрисовки, многопоточность и избежание частого использования BringToFr


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: MDI приложения ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-09-22 22:53:30/0.0043060779571533/0