2.5 Making Things Look Good
Using JavaFX features that enhance the appearance of graphical objects will help your application look professionally designed. Here are some simple additions you can apply.
Gradients
Gradients lend a depth to surfaces and backgrounds by gradually varying the color of the object’s fill property. In general, use linear gradients with rectangular shapes and radial gradients with circles and ovals. In GuitarTuner, the background is a linear gradient that transitions from Color.LIGHTGRAY (at the top) to the darker Color.GRAY (at the bottom) as shown in Figure 2.5. The guitar fret board also uses a linear gradient.
Here is the LinearGradient for the background scene in GuitarTuner, defined for property fill. Note that specifying gradients is declarative; you identify the look you want and the system figures out how to achieve it, independent of screen resolution, color depth, etc.
fill: LinearGradient { startX: 0.0 startY: 0.0 endX: 0.0 endY: 1.0 proportional: true stops: [ Stop { offset: 0.0 color: Color.LIGHTGRAY }, Stop { offset: 1.0 color: Color.GRAY } ] }
The background gradient changes color along the y axis and the color is constant along the x axis (properties startX and endX are the same). Property stops is a sequence of Stop objects containing an offset and a color. The offset is a value between 0 and 1 inclusive; each succeeding offset must have a higher value than the preceding one.
Property proportional indicates whether start and end values are proportional (defined between [0..1] if true) or absolute (absolute coordinates if false).
Radial gradients work well for circular shapes, as shown in Figure 2.6. Here you see three Circle shapes, all with radial gradients. The first circle defines a gradient with its center in the lower left quadrant (centerX is 0.25 and centerY is 0.75). The second circle’s gradient is centered (centerX and centerY are both 0.5), and the third circle’s gradient appears in the upper right quadrant (centerX is 0.75 and centerY is 0.25).
Here is the radial gradient for the middle circle.
fill: RadialGradient { centerX: 0.5 // x center of gradient centerY: 0.5 // y center of gradient radius: 0.5 // radius of gradient stops: [ Stop { offset: 0 color: Color.WHITE }, Stop { offset: 1 color: Color.DODGERBLUE } ] }
Note that the gradient is half the size of the circle (radius is 0.5). Making the gradient less than the full size lets the last stop color appear more prominent (the dark color predominates).
Color
You specify a shape’s color with property fill. JavaFX has many predefined colors ranging alphabetically from Color.ALICEBLUE to Color.YELLOWGREEN. (In the NetBeans IDE, press Ctrl+Space when the cursor is after the dot in Color to see a complete list, as shown in Figure 2.7.)
You can also specify arbitrary colors with Color.rgb (each RGB value ranges from 0 to 255), Color.color (each RGB value ranges from 0 to 1), and Color.web (a String corresponding to the traditional hexadecimal-based triad). An optional final argument sets the opacity, where 1 is fully opaque and 0 is fully translucent. You can also make a shape transparent by setting its fill property to Color.TRANSPARENT.
Here are several examples of color settings. Each example sets the opacity to .5, which allows some of the background color to show through.
def c1 = Color.rgb(10, 255, 15, .5); // bright lime green def c2 = Color.color(0.5, 0.1, 0.1, .5); // dark red def c3 = Color.web("#546270", .5); // dark blue-gray
Numeric-based color values (rather than hexadecimal strings or predefined colors) let you write functions and animations that numerically manipulate gradients, colors, or opacity. For example, the following fill property gets its Color.rgb values from a for loop’s changing value i. The loop produces three different shades of green, depending on the value of i.
def rectangleSequence = for (i in [0..2]) Rectangle { x: 60 * i y: 50 height: 50 width: 40 fill: Color.rgb(10 + (i*50), 100 + (i*40), i*50) }
Figure 2.8 shows the resulting set of rectangles with different fill values.
Rectangles with Arcs
You can soften the corners of Rectangles by specifying properties arcWidth and arcHeight, as shown in Figure 2.9. The first Rectangle has regular, square corners. The second Rectangle sets arcHeight and arcWidth to 15, and the third one uses value 30 for both. Here’s the object literal for the third Rectangle.
Rectangle { x: 180 y: 0 height: 70 width: 60 arcHeight: 30 arcWidth: 30 fill: LinearGradient { . . . } }
DropShadows
One of the many effects you can specify is DropShadow (effects are declarative). Effect DropShadow applies a shadow to its node, giving the node a three-dimensional look. In project GuitarTuner, the fret board (guitar neck) uses a default drop shadow, as follows.
effect: DropShadow { }
The default object literal provides a drop shadow with these values.
effect: DropShadow { offsetX: 0.0 offsetY: 0.0 radius: 10.0 color: Color.BLACK spread: 0.0 }
You can manipulate the location of the shadow by changing offsetX and offsetY. Negative values for offsetY set the shadow above the object and negative values for offsetX set the shadow to the left. Positive values for offsetX and offsetY place the shadow to the right and below, respectively. You can also change a shadow’s size (radius), color, and spread (how “sharp” the shadow appears). A spread value of 1 means the shadow is sharply delineated. A value of 0 provides a “fuzzy” appearance. Figure 2.10 shows three rectangles with drop shadows that fall below and to the right of the rectangles, using these offsets.
effect: DropShadow { // shadow appears below and to the right of object offsetX: 5.0 offsetY: 5.0 }