O'Reilly logo

Swing Hacks by Chris Adamson, Joshua Marinacci

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Create Menus with Drop Shadows #11
Chapter 1, Basic JComponents
|
49
HACK
One nice thing about assembling the drop-down from standard compo-
nents is that it will still look good when used with a different Look and Feel.
Everything the user sees on the screen is some subclass of the standard
JButton, but it is just presented in a non-traditional manner. If you switch to
another theme where standard buttons are shaped differently, the custom
component adapts automatically.
H A C K
#11
Create Menus with Drop Shadows Hack #11
This hack explores a simple way to create drop shadows on menus
throughout an entire application with minimal code changes.
Many modern operating systems provide menus with interesting effects to
make them jump off the screen. One of the most common is the drop
shadow. Some programs even provide shadows themselves when the host
operating system does not. For years, a lack of low-level graphics support
has denied Swing programs access to these kinds of cool effects. But not any
more! Most of the effects can be duplicated with Swing’s robust theming
ability.
Most custom effects require either subclassing a component or messing with
graphics overlays. I tried a variety of techniques to create this hack, but I
kept coming across the same problem over and over. If I wanted to draw a
shadow, I had to change the sizing of each menu item, plus its background,
plus the pop-up frame itself. That is a lot of components to manage. It
would be a lot simpler if I could tell the components to make themselves a
little bit bigger and give me the extra slice of screen real estate to draw in.
The solution was right under my nose: the border. Every Swing component
can use a custom border, without subclassing, and the border will automati-
cally resize the component to fit. If the border is lopsided, then it will create
a kind of shadow effect. Perfect!
Figure 1-28. A drop-down color chooser in a test JFrame
50
|
Chapter 1, Basic JComponents
#11 Create Menus with Drop Shadows
HACK
Every standard Swing component is actually drawn by a UI helper class, and
pop-up menus are no exception. I took the
BasicPopupMenuUI in the javax.
swing.plaf.basic
package and created a subclass called
CustomPopupMenuUI
(shown in Example 1-25). It only does two things special: adds a custom
border to the pop up’s parent panel and sets the panel to be transparent.
The
getPopup( ) method generates the actual menu object in the superclass.
This version grabs the pop up’s parent—a
JPanel—and adds the custom
ShadowBorder with offsets of 3 pixels, both horizontally and vertically. It also
calls
setOpaque(false). This tells the component that it does not have to
completely fill its boundaries and that the parent component may show
through. For most components, this turns off its background, which is the
desired effect here.
With the custom pop-up class done, it’s time to create the border.
ShadowBorder, shown in Example 1-26, is a subclass of AbstractBorder,
which handles all of the messy details of border management and lets the
developer get down to the actual drawing code pretty quickly.
Example 1-25. Extending the pop-up menu’s UI
public class CustomPopupMenuUI extends BasicPopupMenuUI {
public static ComponentUI createUI(JComponent c) {
return new CustomPopupMenuUI( );
}
public Popup getPopup(JPopupMenu popup, int x, int y) {
Popup pp = super.getPopup(popup,x,y);
JPanel panel = (JPanel)popup.getParent( );
panel.setBorder(new ShadowBorder(3,3));
panel.setOpaque(false);
return pp;
}
}
Example 1-26. Adding a shadowed border
class ShadowBorder extends AbstractBorder {
int xoff, yoff;
Insets insets;
public ShadowBorder(int x, int y) {
this.xoff = x;
this.yoff = y;
insets = new Insets(0,0,xoff,yoff);
}
public Insets getBorderInsets( Component c ) {
return insets;
}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required