Прозрачность Popup в Swing

16 Апр
2012

Занимаясь разработкой GUI клиентского приложения на Java Swing столкнулся с вроде бы, на первый взгляд, простой задачей, дизайнеры разработали макет на котором должен быть красивый Popup со скругленными краями. Но оказалось все так просто в Swing. Если вам интересно как можно делать красивые JPopupMenu добро пожаловать.


В Swing JPopupMenu квадратное и если нарисовать скругленные края, то в области скругления оставались острые не закрашенные углы.
Попытки найти решение в гугле дали единственное более-менее приемлемое решение — это делать скриншот области на которой будет отрисовано JPopupMenu и рисовать на этом скриншоте скругленный бэкграунд. По ссылке приводится пример того как это должно работать.

Этот метод хорош если JPopupMenu будет рисоваться над статичной областью экрана, но при рисовании поверх изменяющегося объекта, все начинает выглядеть очень плачевно, т. к. скриншот остается неизменным.

Разрабатывать свой компонент слишком сложный путь, а лень и любопытсво это хорошие стимулы. Так вот эти самые стимулы подтолкнули залезть и покопаться в исходниках JDK.
Первым делом было выяснено, что выставляя свойство JPopupMenu.setOpaque(false) можно добиться прозрачного рисования JPopupMenu в том случае когда, оно находится в пределах фрейма, выглядит примерно так:
image

Копание в исходниках показало, что происходит проверка и если меню умещается во фрейм то создается экземпляр LightWeightPopup который строится на базе JComponent и потому прозрачен, в противном случае создается HeavyWeightPopup который строится на базе JWindow, который уже выглядит иначе:
image

После выяснения этих фактов задача упростилась, надо чтобы все Popup были HeavyWeightPopup, для этого в clientProperty owner’а Popup надо положить ключ forceHeavyWeightPopupKey, но он к сожаления напряму недоступен пришлось прибегнуть к помощи reflection и достать его из PopupFactory.

Сделать JWindow прозрачным можно при помощи AWTUtilities.setWindowOpaque(window, false); пришлось опять немного поколдавать с reflection для того, что бы достать из Popup компоненту JWindow и вуаля JPopupMenu по настоящему прозрачен:
image

Можно написать свой красивый UI. переопределив в LookAndFeel PopupMenuUI.

По ссылкам доступны:
пример github.com/engineerdev/RealPopup/tree/master/dist
исходники github.com/engineerdev/RealPopup
При использовании в своих проектах вам всего лишь нужно вызвать RPopupFactory.install();

Работа меню была проверена на Windows, Linux и MacOS.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх