Я сделал производную 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.
Я также пробовал то же самое приложение под Windows XP. Вот как это выглядит.
Это работает правильно с тенью везде *. Г!
Так что, кажется, это вещь Vista / W7, как предлагает Андреас.
(* В более ранней версии этого текста и screendump предполагалось, что тени не появилось. Однако, это оказалось, потому что у меня была Windows Параметр отображения XP «Тени под меню» отключен. )
Нашел! Вот доказательство:
Как видите, тень теперь правильно отображается поверх формы.
Проблема заключалась в 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
.
«Это работает на моем компьютере».
Но это довольно забавно, потому что я смутно помню, как делал тот же вывод, что и вы, то есть CS_DROPSHADOW
не работает без толстого кадра с изменяемым размером. Возможно, вы все еще используете Windows Vista?