TForm без полей с тенью

Я сделал производную TForm, которая действует как выпадающая часть комбо, или окно подсказки, или всплывающее меню - временная вещь. У него нет заголовка - его BorderStyle установлен в bsNone. Форма отображается немодально с помощью команды Show, установив ее положение.

Чтобы выделить ее, требуется тень от ее границы. Однако следствием установки его границы на bsNone является то, что тень исчезает.

Различные источники Google предлагают варианты этого:

procedure TdlgEditServiceTask.CreateParams(var Params: TCreateParams);
const
  CS_DROPSHADOW = $00020000;
begin
  inherited;
  { Enable drop shadow effect on Windows XP and later }
  if (Win32Platform = VER_PLATFORM_WIN32_NT) and
     ((Win32MajorVersion > 5) or
      ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) then
    Params.WindowClass.Style := Params.WindowClass.Style or
             CS_DROPSHADOW;
end;

, но это не так. t работать - тень не отображается (если только я не установил границу с изменяемым размером с набором WS_THICKFRAME, что выглядит ужасно ). Это всплывающее окно, а не дочернее окно, поэтому я не понимаю, почему оно должно завершиться неудачей.

Предложения, пожалуйста?

Примечание: этот вопрос похож на этот вопрос , который остается без ответа.

NB2: Существует неясный компонент VCL, называемый TShadowWindow , который выглядит так, как будто он будет работать правильно, но оказывается слишком грубо написанным, чтобы быть практичным.

Обновление: После комментариев Андреаса ниже, я исследовал это дальше и нашел некоторые тонкости.

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

Вот простое приложение Delphi, который использует CreateParams во всплывающем окне, чтобы запросить тень, как описано выше.

Windows 7 with shadow only over desktop

Посмотрите, как тень появляется там, где она выходит за пределы основного окна?

Но я хочу использовать окно без полей в качестве всплывающего окна над главным окном. , Падающая тень отличает всплывающее окно от окна под ним. Все мое описание выше относится к этому обстоятельству. Очевидно, что здесь вмешивается какой-то механизм Windows.

Я также пробовал то же самое приложение под Windows XP. Вот как это выглядит.

Same application under XP

Это работает правильно с тенью везде *. Г!

Так что, кажется, это вещь Vista / W7, как предлагает Андреас.

(* В более ранней версии этого текста и screendump предполагалось, что тени не появилось. Однако, это оказалось, потому что у меня была Windows Параметр отображения XP «Тени под меню» отключен. )

14
задан Community 23 May 2017 в 11:53
поделиться

2 ответа

Нашел! Вот доказательство:

alt text

Как видите, тень теперь правильно отображается поверх формы.

Проблема заключалась в Z-порядке. Оказывается, тень сама по себе является отдельным окном, поддерживаемым самой Windows. В Windows 7 кажется, что под главным окном отображается тень. Чтобы он отображался правильно, его нужно переместить вверх.

Гений по имени Лукаш Пломиньский объяснил это в треде в группе новостей Embarcadero. Вот его код, чтобы разобраться в этом:

procedure TForm1.FixSysShadowOrder;

  function FindSysShadowOrderProc(WindowHandle: HWND; // handle to window
    Form: TForm1 // application-defined value, 32-bit
    ): BOOL; stdcall;
  var
    Buffer: array [0 .. 255] of char;
    Rect: TRect;
  begin
    Result := True;
    if IsWindowVisible(WindowHandle) then
    begin
      // this code  search for SysShadow window created for this window.
      GetClassName(WindowHandle, Buffer, 255);
      if 0 <> AnsiStrComp(Buffer, PChar('SysShadow')) then
        Exit;

      GetWindowRect(WindowHandle, Rect);
      if (Rect.Left <> Form.Left) or (Rect.Top <> Form.Top) then
        Exit;

      Form.FSysShadowHandle := WindowHandle;
      // stop enumeration
      Result := False;
    end;
  end;

begin
  if not(csDesigning in ComponentState) and
    ((GetClassLong(Handle, GCL_STYLE) and CS_DROPSHADOW) = CS_DROPSHADOW)
    and IsWindowVisible(Handle) then
  begin
    // for speed, proper SysShadow handle is cached
    if FSysShadowHandle = 0 then
      EnumThreadWindows(GetCurrentThreadID(), @FindSysShadowOrderProc,
        lParam(Self));
    // if SysShadow exists, change its z-order, and place it directly below this window
    if FSysShadowHandle <> 0 then
      SetWindowPos(FSysShadowHandle, Handle, 0, 0, 0, 0,
        SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOSIZE);
  end;
end;

Вы должны решить, когда вызывать FixSysShadowOrder () , потому что Z-порядки меняются, и они не останутся правильными.Лукаш предложил вызывать его в режиме ожидания (например, при обновлении действия) и при получении сообщения WM_WINDOWPOSCHANGED .

8
ответ дан 1 December 2019 в 14:21
поделиться

«Это работает на моем компьютере».


(Высокое разрешение)

Но это довольно забавно, потому что я смутно помню, как делал тот же вывод, что и вы, то есть CS_DROPSHADOW не работает без толстого кадра с изменяемым размером. Возможно, вы все еще используете Windows Vista?

3
ответ дан 1 December 2019 в 14:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: