Win32: Как сделать так, чтобы тень падала в непрямоугольном многослойном окне? - PullRequest
17 голосов
/ 08 февраля 2010

Я создал многослойное окно , добавив WS_EX_LAYERED расширенный стиль:

wndClass.ExStyle = wndClass.ExStyle | WS_EX_LAYERED;

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

alt text


После того, как окно построено, я говорю ему использовать черный в качестве цвета хроматического ключа :

SetLayeredWindowAttributes(hwnd, 0x00000000, 255, LWA_COLORKEY);

Теперь всплывающее многослойное окно выглядит частично прозрачным:

alt text


Проблема - последний шаг. я хочу использовать CS_DROPSHADOW стиль класса, доступный начиная с Windows XP, для создания тени:

wndClass.Style = wndClass.Style | CS_DROPSHADOW;

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

image

Кто-нибудь знает, какую магическую опцию я где-то упустил, которая заставит тень отбросить непрямоугольное многослойное окно?


Еще один пример возникновения этой проблемы - отсутствие отступа / поля 6px. Окно подсказок, нарисованное Windows & reg; темы не прямоугольные. Это оставляет небольшой видимый промежуток, где окно прозрачно, но тень не появляется:

alt text

Microsoft удалось заставить его работать, как вы можете видеть из этой подсказки из Internet Explorer:

alt text


Присмотревшись к окну подсказки класса Windows tooltips. Используя SpyXX - я могу получить его окно прямоугольным и стили классов:

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 ]

6 голосов
/ 10 февраля 2010

Прозрачные многослойные окна задокументированы как предпочтительный метод по регионам.

Однако CS_DROPSHADOW обращает внимание на регионы. Если вы обрезаете или иным образом формируете окно, используя область, тень будет следовать за новым контуром.

К счастью, вы можете использовать регионы со слоистыми окнами и, комбинируя эти два, получите нужный эффект.

Кстати: tooltips_class32 использует использование CS_DROPSHADOW - вы не увидите его в стилях окна, поскольку это стиль класса, а не стиль окна.

1 голос
/ 10 февраля 2010

CS_DROPSHADOW работает только со стандартными прямоугольными окнами. WS_EX_LAYERED окна не поддерживают все. Это скорее низкоуровневый метод самообслуживания для рисования именно того, что вы хотите.

Чтобы получить тень, вам нужно сгенерировать ее самостоятельно из альфа-канала на изображении.

1 голос
/ 08 февраля 2010

Почему бы вам не использовать LWA_ALPHA и не встраивать тень в изображение?

Отредактируйте в ответ на ваш комментарий:

А) Не мешает вам использовать альфа-канал PNG только для тени. Blt 2 изображения вместе и использовать как одно изображение.
Б) Нетрудно создать тень. На изображении вы разместили его черный с 3 различными значениями альфа.
C) Но это не работает, не так ли? т.е. время проявить творческий подход.
D) Тогда не пытайтесь заставить Windows делать то, что оно не сделает для вас.
E) Совершенно не имеет значения. Многослойные окна справятся с этим за вас.

Я настоятельно рекомендую вам больше узнать о многослойных окнах, потому что они МОГУТ помочь вам достичь вашей цели.

Edit2: у вас есть растровое изображение. Его довольно легко отсканировать по изображению и найти, какие биты будут выделены цветом (самостоятельно идентифицируя черный), и затем изменить его, чтобы иметь альфа 0, где все остальное будет иметь альфа 255 (Нет: возможно, вам придется преобразовать изображение в 32-битное изображение из более низкого цветового формата, вы можете сделать это, создав новый DC и скопировав изображение). Это даст вам тот же эффект с LWA_ALPHA, что и с LWA_COLORKEY. Оттуда довольно легко идентифицировать пиксель на краю, где цвет меняется на (R = 0, G = 0, B = 0, A = 0). Затем вы изменяете этот первый пиксель, чтобы n-альфа равнялся 192, один сдул его до 128, а второй снизу до 64. Теперь у вас есть альфа-градация под изображением, которая будет выглядеть как тень. Вы можете настроить альфа, чтобы получить желаемый эффект.

...