Win32: Как сделать так, чтобы тень падала в непрямоугольном многослойном окне?
Я создал многоуровневое окно, добавив расширенный стиль WS_EX_LAYERED:
wndClass.ExStyle = wndClass.ExStyle | WS_EX_LAYERED;
Windows будет использовать черный в качестве значения цвета хроматического ключа. Я собираюсь оставить большую черную границу, чтобы сделать проблему очевидной:
http://i45.tinypic.com/2qs002q.jpg
После того, как окно построено, я говорю ему использовать черный в качестве цвета хроматического ключа:
SetLayeredWindowAttributes(hwnd, 0x00000000, 255, LWA_COLORKEY);
Теперь всплывающее многослойное окно выглядит частично прозрачным:
http://i48.tinypic.com/2cfta3o.jpg
Проблема - последний шаг. я хочу использовать стиль класса CS_DROPSHADOW, доступный начиная с Windows XP, для создания тени:
wndClass.Style = wndClass.Style | CS_DROPSHADOW;
Появляется тень, но тень окружает исходное прямоугольное окно и не учитывает прозрачность окна, обеспечиваемую многослойным окном:
http://i49.tinypic.com/23lnnu9.jpg
Кто-нибудь знает, какую магическую опцию я пропустил где-нибудь, чтобы заставить тень отбрасывать непрямоугольное многослойное окно?
Еще один пример возникновения этой проблемы - это когда вы не добавляете отступы 6px / margin. Окно подсказок, нарисованное темами Windows®, не прямоугольное. Это оставляет небольшой видимый промежуток, где окно прозрачно, но тень не появляется:
http://i47.tinypic.com/30arsxk.png
Microsoft удалось заставить его работать, как вы можете видеть из подсказки Internet Explorer:
http://i46.tinypic.com/f104cj.jpg
Глядя ближе на Windowstooltips
окно подсказки класса. ИспользуяSpyXX- я могу получить прямоугольник окна и стили классов:
http://i49.tinypic.com/f4pued.jpg
SpyXX говорит:
Rectangle: (440, 229)-(544, 249), 104x20
Restored Rect: (440, 229)-(544, 249), 104x20
Client Rect: (0, 0)-(104, 20), 104x20
Таким образом, все указывает на то, что само окно имеет размер 104x20 пикселей, а тень находится за пределами самого окна. (Что согласуется сCS_DROPSHADOW
.)
Далее я могу посмотреть на стилиtooltips
класс окна:
Windows Styles: 94000001
WS_POPUP 80000000
WS_VISIBLE 10000000
WS_CLIPSIBLINGS 4000000
TTS_ALWAYSTIP 1
Extended Styles: 00080088
WS_EX_LAYERED 80000
WS_EX_TOOLWIN 80
WS_EX_TOPMOST 8
Интересно, что он не используетCS_SAVEBITS
(0x800
); что полезно для небольших, недолговечных, окон.
И не использует CS_DROPSHADOW
(0x20000
). Так что теперь мне интересно, как он рисует за пределами своего собственного окна?
Примечание. Прозрачные многослойные окна задокументированы как предпочтительный метод по сравнению с регионами.
Изменить: Многоуровневая Windows была с Windows 2000. CS_DropShadow был добавлен с XP.
3 ответа
Прозрачные многослойные окна задокументированы как предпочтительный метод по регионам.
Тем не мение, CS_DROPSHADOW
обращает внимание на регионы. Если вы обрезаете или иным образом формируете окно, используя область, тень будет следовать за новым контуром.
К счастью, вы можете использовать регионы со слоистыми окнами, и, комбинируя эти два, получите эффект, который вы ищете.
Кстати: tooltips_class32 использует CS_DROPSHADOW - вы не увидите его в стилях окна, потому что это стиль класса, а не стиль окна.
Почему бы вам не использовать LWA_ALPHA и встроить тень в изображение?
Отредактируйте в ответ на ваш комментарий:
А) Не мешает вам использовать альфа-канал PNG только для тени. Blt 2 изображения вместе и использовать как одно изображение.
Б) Нетрудно создать тень. На изображении вы разместили его черный с 3 различными значениями альфа.
C) Но это не работает, не так ли? т.е. время, чтобы стать творческим.
D) Тогда не пытайтесь заставить окна делать то, что вам не подойдет.
E) Совершенно не имеет значения. Многослойные окна справятся с этим за вас.
Я настоятельно рекомендую вам узнать больше о многослойных окнах, потому что они МОГУТ помочь вам достичь вашей цели.
Edit2: у вас есть растровое изображение. Его довольно легко отсканировать по изображению и найти, какие биты будут выделены цветом (самостоятельно идентифицируя черный), и затем изменить его, чтобы иметь альфа 0, где все остальное будет иметь альфа 255 (Нет: возможно, вам придется преобразовать изображение в 32-битное изображение из более низкого цветового формата, вы можете сделать это, создав новый DC и скопировав изображение). Это даст вам тот же эффект с LWA_ALPHA, что и с LWA_COLORKEY. Оттуда довольно легко идентифицировать пиксель на краю, где цвет меняется на (R = 0, G = 0, B = 0, A = 0). Затем вы изменяете этот первый пиксель, чтобы иметь альфа-значение 192, один - до 128, а второй - до 64. Теперь у вас есть альфа-градация под изображением, которая будет выглядеть как тень. Вы можете настроить альфа, чтобы получить желаемый эффект.
CS_DROPSHADOW
работает только со стандартными прямоугольными окнами. WS_EX_LAYERED
окна не поддерживают все Это скорее низкоуровневый метод самообслуживания, позволяющий рисовать именно то, что вы хотите.
Чтобы получить тень, вам нужно сгенерировать ее непосредственно из альфа-канала на изображении.