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

Build a Colorful Vector-Based Button #62
Chapter 8, Rendering
|
309
HACK
Script font at http://www.free-fonts.com/. Once you have a .ttf file, run the
demo like this:
cadamson% java FontLoadingDemo marriage_script.ttf
Running the demo pops up a window like the one seen in Figure 8-6.
With this technique, and a consistent scheme for bundling your application
resources (i.e., stuffing all your fonts in a JAR file, perhaps with other
resources like images, sounds, and localizations), you have the freedom to
use whatever fonts you like in your GUI, without worrying about what end
users do or don’t have installed.
H A C K
#62
Build a Colorful Vector-Based Button Hack #62
Build a resolution-independent OS X-style button using scalable graphics
code.
The button in this hack is resolution independent, meaning that it can resize
and rescale automatically as the user’s windows and display change, stretch-
ing and tiling the graphics to fill the new space. The button doesn’t depend
on being any particular size to look good. As higher-quality and higher-
resolution monitors become more common, users will start to expect attrac-
tive interfaces that scale and reflow with their increasingly expansive dis-
plays. This hack shows how to create an attractive
JButton that will scale
with both size and resolution, opening the door for a completely vector-
drawn Swing Look and Feel.
Use Scaling to Your Advantage
Since this button must scale with the size of the screen, you can use a vari-
able called
scale. Every piece of drawing code for this button is done rela-
tive to
scale’s value. If the scale value changes, the entire button will change
accordingly. The scale value itself is based on the current font size of the
component. If the component’s font is resized (due to a DPI change, for
example), then the scale value will change accordingly, resizing the entire
button. With a scale value in place, this hack is simply a matter of recreat-
ing the Aqua button look with Java2D calls. The goal is a button that looks
like Figure 8-7.
Figure 8-6. Marriage font loaded on the fly
310
|
Chapter 8, Rendering
#62 Build a Colorful Vector-Based Button
HACK
Not a simple task, but it’s not impossible either. All the work is done in
Example 8-9.
The previous code is the essence of
VectorButton. It is just a subclass of
JButton, overriding getPreferredSize( ) and paintComponent( ) and adding a
mouse listener implementation.
Figure 8-7. A green vector JButton
Example 8-9. Creating liquid buttons
public class VectorButton extends JButton implements MouseListener {
public VectorButton( ) {
this.addMouseListener(this);
}
public Dimension getPreferredSize( ) {
String text = getText( );
FontMetrics fm = this.getFontMetrics(getFont( ));
float scale = (50f/30f)*this.getFont().getSize2D( );
int w = fm.stringWidth(text);
w += (int)(scale*1.4f);
int h = fm.getHeight( );
h += (int)(scale*.3f);
return new Dimension(w,h);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(this.getBackground( ));
g2.fillRect(0,0,this.getWidth(),this.getHeight( ));
float scale = (50f/30f)*this.getFont().getSize2D( );
drawLiquidButton(this.getForeground( ),
this.getWidth(), this.getHeight( ),
getText( ), scale,
g2);
}
Build a Colorful Vector-Based Button #62
Chapter 8, Rendering
|
311
HACK
A custom version of getPreferredSize( ) is required because, by default, a
JButton will size itself based on the current Look and Feel. For this hack, we
want the button sized based on the scale value. You can see that scale is cal-
culated by multiplying the current font size against a scaling factor. I chose
the factor 50/30 by testing different values and simply seeing what looked
right. The actual factor doesn’t matter as long as you’re consistent, which is
why scale is calculated the same way for both
getPreferredSize( ) and
paintComponent( ). The paintComponent( ) method just turns on anti-aliasing,
fills the background, calculates scale, and then calls
drawLiquidButton( )
where the real work is done.
drawLiquidButton( ) is a wrapper for a series of custom drawing functions
that create each part of the liquid button. In order to emulate the Aqua look,
you’ll need to use a series of rounded rectangles and gradient fills.
To make the code more understandable, I broke it up into
functions for the shadow, body, text, highlight, and border.
As you go through the code, you will notice that scale is multiplied by a
small adjustment value like
0.1f or 0.04f. These numbers were chosen
largely through trial and error, just by trying different values to see what
looked good. Finding those values took a long time but really added to the
quality of the finished button. If you decide to build your own vector wid-
get, it will really pay to spend the time tweaking your drawing, too. Here’s
the method implementation:
protected void drawLiquidButton(Color base,
int width, int height,
String text, float scale,
Graphics2D g2) {
// calculate inset
int inset = (int)(scale*0.04f);
int w = width - inset*2 - 1;
int h = height - (int)(scale*0.1f) - 1;
g2.translate(inset,0);
drawDropShadow(w,h,scale,g2);
if(pressed) {
g2.translate(0, 0.04f*scale);
}

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