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

Проблема с отображением тени у Borderless формы (без границ) в Delphi 11 после создания обычной формы

Delphi , Программа и Интерфейс , Размеры и Положение

 

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

Многие разработчики Delphi сталкиваются с интересной проблемой при работе с формами без границ (borderless forms), которые должны отображать тень. В частности, в Delphi 11 на Windows 10 наблюдается следующее поведение:

  1. Если сначала создать форму без границ с тенью (Borderless Shadowed form), а затем обычную форму (Normal form), тень отображается корректно
  2. Если же сначала создать обычную форму, а затем форму без границ, тень не появляется

Это неожиданное поведение, так как логично предположить, что форма без границ должна всегда отображать тень, независимо от порядка создания форм.

Анализ кода

Рассмотрим исходный код, который демонстрирует проблему:

type
  TFormPopup = class(TForm)
    Panel1: TPanel;
    ButtonClose: TButton;
    procedure ButtonCloseClick(Sender: TObject);
  private
    FIsBorderlessPopup: Boolean;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(AIsBorderlessPopup: Boolean); reintroduce;
  end;

procedure TFormPopup.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);

  If FIsBorderlessPopup then
  begin
    Params.Style := WS_POPUP;
    Params.WindowClass.style := Params.WindowClass.style or CS_DROPSHADOW;
    Params.ExStyle := WS_EX_TOPMOST;
  end;
end;

Причины проблемы

Как выяснилось в обсуждении, проблема связана с механизмом регистрации классов окон в Windows:

  1. Delphi регистрирует классы окон как через RTL, так и через Windows API
  2. При создании формы сначала вызывается CreateParams, затем Windows создает окно с указанными параметрами
  3. Проблема возникает из-за того, что VCL не всегда корректно обрабатывает UnregisterClass при уничтожении формы
  4. В результате, при повторном создании формы, Windows использует кешированные параметры класса окна

Решения проблемы

1. Использование RecreateWnd (не всегда работает)

Первоначально было предложено вызывать RecreateWnd после установки параметров:

procedure TFormPopup.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);

  If FIsBorderlessPopup then
  begin
    Params.Style := WS_POPUP;
    Params.WindowClass.style := Params.WindowClass.style or CS_DROPSHADOW;
    Params.ExStyle := WS_EX_TOPMOST;
  end;
  RecreateWnd; // Попытка решения
end;

Однако, как показала практика, это решение не всегда работает надежно, особенно в разных версиях Delphi.

2. Разделение на два разных класса форм (рекомендуемое решение)

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

type
  TBasePopupForm = class(TForm)
    Panel1: TPanel;
    ButtonClose: TButton;
    procedure ButtonCloseClick(Sender: TObject);
  end;

  TNormalPopupForm = class(TBasePopupForm)
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TBorderlessPopupForm = class(TBasePopupForm)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

implementation

constructor TNormalPopupForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Panel1.BorderStyle := bsNone;
  Panel1.Caption := 'Normal Form';
end;

procedure TBorderlessPopupForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.Style := WS_POPUP;
  Params.WindowClass.style := Params.WindowClass.style or CS_DROPSHADOW;
  Params.ExStyle := WS_EX_TOPMOST;
end;

constructor TBorderlessPopupForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Panel1.BorderStyle := bsSingle;
  Panel1.Caption := 'Borderless Shadowed';
end;

Теперь в основном окне можно создавать формы следующим образом:

procedure TFormMain.ButtonCreateBorderlessClick(Sender: TObject);
begin
  TBorderlessPopupForm.Create(nil).Show;
end;

procedure TFormMain.ButtonCreateNormalClick(Sender: TObject);
begin
  TNormalPopupForm.Create(nil).Show;
end;

3. Принудительная отмена регистрации класса (не рекомендуется)

Некоторые разработчики предлагают явно вызывать UnregisterClass, но это решение не рекомендуется из-за потенциальных проблем:

procedure TFormPopup.CreateParams(var Params: TCreateParams);
var 
  ClassRegistered: Boolean;
  TempClass: TWndClass;
begin
  inherited CreateParams(Params);

  ClassRegistered := GetClassInfo(Params.WindowClass.hInstance, 
    Params.WinClassName, TempClass);
  if ClassRegistered then
  begin
    Winapi.Windows.UnregisterClass(Params.WinClassName, 
      Params.WindowClass.hInstance);
  end;

  If FIsBorderlessPopup then
  begin
    Params.Style := WS_POPUP;
    Params.WindowClass.style := Params.WindowClass.style or CS_DROPSHADOW;
    Params.ExStyle := WS_EX_TOPMOST;
  end;
end;

Почему это плохое решение:
1. UnregisterClass может завершиться ошибкой, если существуют окна этого класса
2. Может вызвать проблемы с программным обеспечением, которое кэширует классы окон (например, программы для доступности)
3. Нарушает стандартный поток работы VCL

Дополнительные рекомендации

  1. Не используйте FreeAndNil для Self: Вместо FreeAndNil(FormPopup) в обработчике кнопки закрытия лучше использовать Release, который обеспечит корректное освобождение формы.

  2. Создание форм без глобальных переменных: Вместо хранения ссылки на форму в глобальной переменной, лучше создавать форму следующим образом: pascal with TFormPopup.Create(True) do Show;

Заключение

Проблема с отображением тени у borderless форм в Delphi после создания обычных форм связана с особенностями регистрации классов окон в Windows и VCL. Наиболее надежное решение - разделить функциональность на два разных класса форм. Это обеспечит стабильное поведение приложения и корректное отображение теней независимо от порядка создания форм.

Разделение на разные классы - это не только решение конкретной проблемы с тенями, но и хорошая практика проектирования, которая делает код более понятным и поддерживаемым.

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

Проблема с некорректным отображением тени у borderless-форм в Delphi 11 при определенном порядке создания форм, связанная с особенностями регистрации классов окон в Windows и VCL.


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

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




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


:: Главная :: Размеры и Положение ::


реклама


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

Время компиляции файла: 2024-12-22 20:14:06
2025-07-19 00:22:57/0.0046520233154297/0