JClass Elements

PreviousNextIndex

3

Circular and Linear Gauges

Circular and Linear Gauges  Features of JCCircularGauge  Features of JCLinearGauge  JCGauge

JCCircularGauge  JCLinearGauge  Headers, Footers, and Legends  JCScale

JCAbstractScale  The Circular Scale Object  The Linear Scale Object  Tick Objects

The Range Object  The Indicator and Needle Objects  The Center Object

The Constraint Mechanism in JCGauge  Labels  Events and Listeners in JCGauge

Utility Functions for JCGauge  JCCircularGaugeBean and JCLinearGaugeBean

Adding Other Components to a Gauge  JClass 4 to JClass 5: A Mini-porting Guide


3.1 Circular and Linear Gauges

The JCGauge components in JClass Elements provide you with realistic-looking instruments for your application's GUI design. End users can interact with colorful, easy-to-read meters on which they may view or set values. There are two basic types: circular and linear. Circular gauges may be used to give your application the flavor of an automobile instrument cluster, or alternatively an airline cockpit, control room, old time radio, or numerous other designs. Similarly, linear gauges may be made to look like thermometers (for hot and not-so-hot stock opportunities as well as temperature measurement), jazzed-up progress meters, and a variety of level and volume indicators. Your GUI design possibilities have been expanded, and you have the potential to make your GUIs even more visually appealing and user friendly.

Figure 3 :  Sample circular (left) and linear (right) gauges.

3.1.1 Parts of a Gauge

Gauges, whether circular or linear, consist of visible objects and objects whose purpose is functional. The visible objects are:

The diagram shows the various visible components of a gauge. Note that the gauge area (JCGaugeArea) contains the scale and its objects, but not the header, footer, or legend.

Figure 4 :  Objects within a gauge.

The non visible parts of a gauge are:

Gauge appearance and interactivity

Because the gauge and many of its constituents are subclassed from JComponent, you have considerable flexibility in designing its appearance. Interfaces for indicators, needles, ranges, scales, and ticks let you replace the built-in objects with those you design yourself. As well, it is easy to add additional items like numerical counters, images, and such to the gauge.

Gauges behave like analog devices whose readings are only approximate. If a more precise digital readout is desired, the needle's getValue() method, or the component's pick listener is employed to extract numeric values from the gauge. Figure 5 shows a circular gauge functioning as a speedometer. The needle points to the car's current speed. A numeric counter has been added to function as an odometer, and another counter displays a digital readout of the speed. This reading is more precise than the indication of the speed given by the needle.

Interactions between mouse and needle may be turned on or off. When an interaction is enabled, an end user can control the placement of the needle. If you wish, interactions can be turned off and the component can be used simply as a display device.

Figure 5 :  The odometer is a label positioned at the bottom of the speedometer.

You control the order in which objects are rendered to achieve your desired layering effect. See Rendering order for an explanation.

Caution: When setting a scale on a gauge, a center on a circular gauge, or adding indicators, needles, ranges, and ticks to a gauge, use the special set() and add() methods provided in JCGauge. Using standard java.awt.Container's add() methods does not take into account the gauge's special requirements. When using the gauge's special add() methods you are still able to include an optional index that specifies the rendering order.

A gauge may have multiple instances of indicators, needles, ranges, and tick marks. In this case, the gauge maintains a collection for each of the object groups. The gauge has indicator and needle lists for keeping track of scale pointers, a range list for keeping track of the bands, called ranges, that can be used to mark various regions around the scale, and a tick list to keep track of the different tick objects.

Labels, which may be any JComponent, not just a JLabel, are created and manipulated individually rather than being stored in a list. There are special-purpose methods called addLabel(label, radialConstraint) and addLabel(label, linearConstraint) for placing labels at a specified location on the gauge.

Gauges may be added to other gauges. They may or may not share the same origin. See Section 3.21, Adding Other Components to a Gauge for a discussion on how to place components on a gauge and for an example of placing a smaller circular gauge on top of a larger one.

A gauge's size is determined by the size of its container. The container's layout manager, along with its preferred size setting, determine the gauge's initial size. Gauges may be resized as long as the layout manager permits it.

Rendering order

A render list, which in Java is often called the z-order of the components, is effectively created by the order in which components are added at execution time. This list determines in what order child objects are to be drawn. Components added last are drawn first. In a circular scale for example, by adding a needle and then a center, the center object is drawn first, then a needle, so that the needle is fully visible from center to tip instead of being partially covered by the center object. There are ways of manipulating the list so that a different drawing order can be specified. By drawing a needle first, it can appear to be attached to the edge of the center object rather than beginning at the center of the circle.

Inner and outer extents

The size of indicators, needles, ticks, and ranges is specified in part by two parameters called their inner and outer extents. These extents are defined as ratios based on the underlying scale. In the circular case, inner and outer extents refer to locations in a radial direction, with the center defined as 0.0. Thus, an object with an inner extent of 0.0 means that it is drawn from the center outwards to the position defined by the outer extent. If this outer extent is 0.8, the object extends out from the center a distance equal to 80% of the radius of the circular scale. Inner and outer extents on a circular scale are diagrammed in Figure 18.

In the linear case, how extents are measured depends on whether the orientation of the scale is horizontal or vertical. Since extents are measured in the direction transverse to the direction in which scale values increase, they are measured from the top edge of a horizontal scale, and from the left edge of a vertical scale. For example, an indicator on a vertical linear scale whose inner extent is 0.15 and whose outer extent is 0.75 is drawn beginning at 15% of the gauge's width from the left edge to 75% of the gauge's width.

3.1.2 Switches

A switch is the software equivalent to its electrical counterpart, a device that has a set of discrete, selectable positions. A simple switch may have only two states, on and off, or it may possess a number of selectable states. Figure 6 shows a switch shaped like a pointer that has six discrete states.

Switches may be implemented by having your code control the way that the gauge reacts to user input, but the easiest way to implement a switch is to choose a scale with integer values that correspond to switch positions, then set the gauge's snapToValue() property to true:

// make it discrete
gauge.setSnapToValue(true);

By default, snapToValue is false.

See GaugeSwitchExample.java in the examples/elements/switchdemo directory for an example of a switch with six positions.

Figure 6 :  A switch with six discrete states.

If you require a switch with irregularly spaced stops you will need to add a pick listener and place the needle yourself in response to an end user's actions.

3.1.3 Organization of the Gauge Classes

In keeping with the goal of making the gauges as configurable as possible, all gauge classes inherit from an abstract class JCGauge, which is itself a JComponent. JCGauge implements MouseListener and MouseMotionListener so that it may respond to mouse clicks and drags. This allows an end user to set a value by dragging a needle to a desired location on a scale, or by clicking on the scale and having the needle jump to the value determined by the position of the mouse pointer.

The diagram shows where you'll find the components and sub-objects that make up the gauge. Objects are designated by their class names.


3.2 Features of JCCircularGauge

JCCircularGauge is a subclass of JComponent whose on-screen representation looks like an analog circular measuring instrument. JCCircularGaugeBean in the com/klg/jclass/swing/gaugebeans directory is a JavaBean. It wraps properties found in JCLinearGauge's contained objects so that they are easily accessible in an IDE.

JCCircularGauges are containers for interactive circular meters that use a needle to point to a value and allow it to be measured on a scale. Circular gauges are constructed using an assortment of objects that provide structured functionality to the component as a whole.

Figure 7 shows the components that may be used in a gauge. The central element is a circular scale, which resides in a JCGaugeArea. The only way that a scale indicates its presence is if its foreground color is different from that of the gauge. The visible objects are a center, and collections of indicators, needles, ticks, and ranges. A center object, as its name implies, marks the center of a circular gauge. It may be a disk or an image. Needles perform measurement functions by pointing at scale values. Ticks provide visible scale markings with optional value labels so that scale values may be read. Ranges are bands that mark part or all of the scale to distinguish one part from another, like the red-line area of a tachometer. The range shown in Figure 7 runs along the circumference of the circular scale, thus marking its location. Outside the gauge area there is room for a header, footer, and legend. Header and footer elements are JComponents, typically JLabels, but the choice is yours. The legend is a JCLegend, a special type of JComponent that makes it easy to provide a legend that itemizes each component of a chosen type that the scale contains. Ranges are the default items for a legend, and may be itemized simply by naming the ranges and calling gauge.getLegend().setVisible(true).

Alternatively, needles or other objects may be the items referred to in the legend list. If you do decide to place items other than ranges in the legend you will have to write your own legend populator. See Custom legends for details.

Also, through its inner class GaugeType, JCCircularGauge defines a set of configurations for circular gauges, such as LOWER_RIGHT_QUARTER_CIRCLE or TOP_HALF_CIRCLE, allowing you to confine the gauge to a quadrant or a semicircle. There are nine choices in all. See Section 3.5.3, Properties, for the list of constants for GaugeType.


Figure 7 :  The major components in a circular gauge.


3.3 Features of JCLinearGauge

JCLinearGauge is a subclass of JComponent whose on-screen representation looks like an analog linear measuring instrument. JCLinearGaugeBean is a JavaBean. It wraps properties found in JCLinearGauge's contained objects so that they are easily accessible in an IDE.

JCLinearGauges are containers for interactive linear meters that use needles to point to values and allow these values to be measured on a scale. Linear gauges are constructed using an assortment of objects that provide structured functionality to the component as a whole.

Figure 8 shows the components that may be used in a linear gauge. The central element is a linear scale, which resides in a JCGaugeArea. The only way that a scale indicates its presence is if its foreground color is different from that of the gauge. The visible objects are collections of indicators, needles, ticks, and ranges. There is no center object in a linear gauge. Needles perform measurement functions by pointing at scale values. Ticks provide visible scale markings with optional value labels so that scale values may be read. Ranges are bands that mark part or all of the scale to distinguish one part from another, like range shown in Figure 8, which is the small rectangle that runs between 85 and 100. Outside the gauge area there is room for a header, footer, and legend. Header and footer elements may be any JComponent, typically a JLabel. The legend is a JCLegend, a special type of JComponent that makes it easy to provide a legend that itemizes each component of a chosen type that the scale contains. Ranges are the default items for a legend, and may be itemized simply by naming the ranges and calling gauge.getLegend().setVisible(true).

Figure 8 :  The major components of a linear gauge.

Note: Place a border around a linear gauge to ensure tick labels at the scale's extremities are fully visible.


3.4 JCGauge

JCGauge is the abstract superclass for JCCircularGauge and JCLinearGauge. JCGauge creates a header, footer, and legend whenever a circular or linear gauge is instantiated, and it has methods for adding or removing indicators, needles, ranges, and ticks.

Use the gauge's add() methods rather than the add() methods in JComponent. The addLabel() methods in JCCircularGauge and JCLinearGauge are there because these objects depend on LinearConstraint and RadialConstraint classes to position labels based on a linear extent and a pixel value, or a specified angle and radial distance. (See Section 3.16.1, RadialConstraint and RadialLayout, for more information.)

At any given time, each gauge contains one scale. A scale holds information about the minimum and maximum values for the scale, and the direction, forward or backward, in which scale values increase. The circular scale has start and stop angles that determine the portion of a full circle occupied by the scale. A needle object provides the visual indication of a particular value on the scale. Its length is specified by setting its inner extent and its outer extent. If the scale changes its size, the needle adjusts itself accordingly, maintaining a proper position and proportional length relative to the size of the scale. See Section 3.14, The Indicator and Needle Objects, for details.

3.4.1 Constructor

JCGauge has an abstract no-argument constructor that is called when a circular or linear gauge is instantiated. It creates a default header and footer as JLabels, and a default legend as a JCGridLegend.

3.4.2 Methods and Properties for JCGauge

JCGauge has these methods and properties:

Methods

JCGauge Method

Description

addIndicator
removeIndicator

Adds or removes an indicator to the indicator collection for this gauge. Both take an indicator as a parameter, and an optional second parameter, an index, specifying its position in the Vector of needles.

addNeedle()

removeNeedle()

Adds or removes a needle to the needle collection for this gauge. Both take a needle as a parameter, and an optional second parameter, an index, specifying its position in the Vector of needles.

addPickListener()

removePickListener()

Adds or removes a pick listener for this needle. See Section 3.18, Events and Listeners in JCGauge.

addRange()

removeRange()

A gauge maintains a list of ranges associated with it. These methods add or remove a specified range from the collection. They take the range as a parameter and an optional second parameter, an index, for its position in the Vector of ranges.

addTick()

removeTick()

A gauge maintains a list of ticks associated with it. These methods add or remove a specified tick from the collection. They take the tick as a parameter and an optional second parameter, an index, for its position in the Vector of ticks.

getComponentArea()

Returns the JClass component's subcomponent on which the gauge will be drawn.

getDrawingAreaHeight()

Gets the height of the drawing area represented by this gauge.

getDrawingAreaWidth()

Gets the width of the drawing area represented by this gauge.

getIndicators()

Returns the list of indicators associated with this gauge.

getNeedles()

Returns the list of needles associated with this gauge.

getRanges()

Returns the list of ranges associated with this gauge.

getScale()

Returns the scale associated with this gauge.

getTicks()

Returns the tick objects for this gauge.

mouseClicked()
mouseDragged()
mouseEntered()
mouseExited()
mouseMoved()
mousePressed()
mouseReleased()

mouseClicked and mouseDragged send pick events to listeners. The other methods are empty, and must be overridden in a subclass if you wish to use them for your own purposes.

pick()

Given a screen location in pixels, returns the closest scale value as a JCGaugePickEvent.

sendPickEvent()

Broadcasts the pick event to interested listeners.

Properties

JCGauge Property

Description

getFooter()

setFooter()

Returns or sets the footer for this gauge, a JComponent.

getGaugeArea()

setGaugeArea()

Returns or sets the JCGaugeArea for this gauge, a JCGaugeArea. These methods, although declared public, are internal to JClass. There should be no need to obtain a reference to a JCGaugeArea.

getHeader()

setHeader()

Returns or sets the header for this gauge, a JComponent.

getLegend()

setLegend()

Returns or sets the legend for this gauge, a JCLegend.

getRepaintEnabled()
setRepaintEnabled()

Disables or enables repaints of the gauge and its components.

getSnapToValue()

setSnapToValue()

Returns or sets the snapToValue property that controls whether the needle should snap to the closest discrete integral scale value (true) or to any scale value (false).


3.5 JCCircularGauge

3.5.1 Constructors

Of the three constructors for JCCircularGauge, the default no-argument one supplies its own scale, then populates it with a center (a disk or an image), a needle, and a set of tick marks. The constructor that takes a Boolean value creates a gauge with an associated circular scale if the Boolean parameter is true, or an empty gauge otherwise. In either case, the center, indicators, needles, and ticks must be added separately. The third constructor takes a gauge type as a parameter. It too creates an empty gauge of the specified type. The scale, center, indicators, needles, and ticks must be added separately.

3.5.2 Methods for JCCircularGauge

JCCircularGauge subclasses from JComponent, making it a JComponent with special capabilities for laying out subcomponents radially.

JCCircularGauge Method

Description

addLabel()
removeLabel()

Adds or removes a label on the gauge. This is a general-purpose method, suitable for laying out any JComponent it is given.

getClosestNeedle()

Returns the closest needle to the clicked/dragged point. Returns closest needle of type CLICK/DRAG/CLICK_DRAG, or if there are none of these, the closest needle of type NONE.

getScale()
setScale()

Gets or sets the scale used by the gauge. A scale contains the measurement parameters associated with a circular gauge. The getScale() method is inherited from JCGauge, but the setScale() method is overridden so that its argument must be a JCCircularScale. An optional second parameter to setScale() allows you to suppress the addition of the scale to the gauge area, but it is not expected that you will need to use this option.

mouseClicked()

Sends pick events to listeners and moves the closest needle with a CLICK interaction enabled to the value indicated by the mouse click.

mouseDragged()

Called during mouse drag events in the gauge to move the needle closest to the mouse.

3.5.3 Properties

A JCCircularGauge has the same properties as a JComponent and these additional ones:

JCCircularGauge Property

Description

getCenter()

setCenter()

Returns or sets the center for this gauge.

getGaugeType()

setGaugeType()

Returns or sets the gauge type, one of the JCCircularGauge.GaugeType enums.

For a full listing of the properties, see the API for com.klg.jclass.swing.gauge.JCCircularGauge.

Type constants for JCCircularGauge

The inner class JCCircularGauge.GaugeType has these constants and methods:

Circular GaugeType Constant

Angular Span of the Circle, Semicircle, or Quadrant

BOTTOM_HALF_CIRCLE

180-0 degrees. See Section 3.10.3, Angles In a Circular Scale for a discussion of angular measurement in JCCircularGauge.

FULL_CIRCLE

0-360 degrees

LEFT_HALF_CIRCLE

90-180 degrees

LOWER_LEFT_QUARTER_CIRCLE

180-270 degrees

LOWER_RIGHT_QUARTER_CIRCLE

270-0 degrees

RIGHT_HALF_CIRCLE

270-90 degrees

TOP_HALF_CIRCLE

0-180 degrees

UPPER_LEFT_QUARTER_CIRCLE

90-180 degrees

UPPER_RIGHT_QUARTER_CIRCLE

0-90 degrees

getStartAngle()

A method that returns the start angle as an integer.

getSweepAngle()

A method that returns the sweep angle as an integer.


3.6 JCLinearGauge

3.6.1 Constructors

JCLinearGauge has a no-argument constructor that supplies its own scale, then populates it with a needle and a set of tick marks. The constructor that takes a Boolean value creates a gauge with an associated linear scale if the Boolean parameter is true, or an empty gauge otherwise. In either case, indicators, needles, and ticks must be added separately.

3.6.2 Methods for JCLinearGauge

A linear gauge has methods for adding and removing labels, getting or setting its associated linear scale, and finding the needle closest to the point where a mouse click or drag occurred.

JCLinearGauge Method

Description

addLabel()
removeLabel()

Adds or removes a label on the gauge. This is a general-purpose method, suitable for laying out any JComponent it is given.

getClosestNeedle()

Returns the closest needle to the clicked/dragged point.

getScale()
setScale()

Gets or sets the scale used by the gauge. A scale contains the measurement parameters associated with a linear gauge. The getScale() method is inherited from JCGauge, but the setScale() method is overridden so that its argument must be a JCLinearScale. An optional second parameter to setScale() allows you to suppress the addition of the scale to the gauge area, but it is not expected that you will need to use this option.

mouseClicked()

Sends pick events to listeners and moves the closest needle with a CLICK interaction enabled to the value indicated by the mouse click.

mouseDragged()

Called during mouse drag events in the gauge to move the needle closest to the mouse.

3.6.3 Properties

A JCLinearGauge has the same properties as a JCGauge.


3.7 Headers, Footers, and Legends

Both JCCircularGauge and JCLinearGauge create a header and footer, which by default is a JLabel, but may be any JComponent. If you wish to choose some other header or footer than the default, methods setHeader() and setFooter() in JCGauge specify which JComponents, typically JLabels, to use. By default, the header, footer, and legend do not show. To display a header, use:

// gauge is a reference to either type of JCGauge
gauge.getHeader().setVisible(true);

A gauge's legend is an instance of com.klg.jclass.util.JCLegend, an abstract class that requires a subclass to provide a specific layout. By default, a gauge uses JCGridLegend to provide a default implementation of JCLegend and delegates DefaultLegendPopulatorRenderer to populate and render the legend. In the default case, range names are the items in the legend. If you wish to itemize ranges in a legend, simply show the gauge's default legend and DefaultLegendPopulatorRenderer does the rest.

// gauge is a reference to either type of JCGauge
gauge.getLegend().setVisible(true);

A legend's built-in behavior is to use range names for its items. Ranges have default names like range0, range1, and so on. Give a range a name of your own choosing as follows:

// range is a reference to either type of range
range.setRangeName("Danger zone");

Custom legends

If you need a legend that itemizes other things like needles or ticks then you can subclass DefaultLegendPopulatorRenderer and override getLegendItems() to provide your chosen item list with instances of JCLegendItem. The method in DefaultLegendPopulatorRenderer called createLegendItem() is used both for items and for the legend's title, the difference being that a null Color specification (the constructor's last parameter) indicates a title. Alternatively, you can use setLegendTitle() to set a title on an existing JCLegend. Note that getLegendItems() returns a list of items. See GaugeInteractionExample.java, which creates a legend that lists the needles used in the gauge.

3.7.1 JCLegend

Interfaces

There are two interfaces associated with JCLegend. JCLegendPopulator is an interface implemented by classes that wish to populate a legend with data, and JCLegendRenderer is an interface implemented by a class that wishes to help render the legend.

DefaultLegendPopulatorRenderer implements both interfaces and provides a built-in mechanism for itemizing range objects in a legend.

Methods in JCLegend

Method

Description

getLegendPopulator()

setLegendPopulator()

Returns or sets the JCLegendPopulator instance used to populate this legend.

getLegendRenderer()

setLegendRenderer()

Returns or sets the legend renderer class that is used to help draw the legend.

getOrientation()

setOrientation()

Returns or sets the Orientation property that determines how the legend information is laid out. Possible values are JCLegend.HORIZONTAL or JCLegend.VERTICAL.


3.8 JCScale

JCScale is the interface that represents a graduated scale. A scale has a minimum value, a maximum value, and a direction. Lists of other objects like JCTick and JCRange objects are associated with the scale. These associated objects use the scale to get information that they need to render themselves.

Both circular and linear scale objects implement the JCScale interface, whose methods are as follows.

Interface JCScale Method

Description

addRange()
removeRange()

Adds or removes a scale's range object. By supplying an optional index you can control where this range is placed in the list of range objects.

addTick()
removeTick()

Adds or removes a scale's tick object. By supplying an optional index you can control where this group of ticks is placed in the list of tick objects.

getDirection()

Returns the JCAbstractScale.Direction for this scale, FORWARD or BACKWARD, giving the direction in which scale values increase.

getExtent()

Returns the zoomFactor for this scale. (This method is retained for backwards compatibility. Its use is deprecated.)

getGauge()

Returns the gauge associated with this scale.

getMax()

Returns the maximum value for this scale.

getMin()

Returns the minimum value for this scale.

getRanges()

Returns the Vector of range objects for this scale.

getTicks()

Returns the Vector of tick objects for this scale.

getZoomFactor()

Returns the zoomFactor for this scale.

inBounds()

Returns true if the value is within the scale's minimum and maximum.

pick()

Given a screen position in pixels, returns the closest scale value.

setBorder()

Sets a Border on the scale.

setDirection()

Sets the JCAbstractScale.Direction for this scale, FORWARD or BACKWARD, giving the direction in which scale values increase.

setExtent()

Sets the double that represents the zoomFactor for this scale.

(This method is retained for backwards compatibility. Its use is deprecated.)

setMax()

The double that represents the maximum value for this scale.

setMin()

The double that represents the minimum value for this scale.

setZoomFactor()

The double that represents the zoomFactor value for this scale.

Those wishing to use their own type of scale should implement this interface.


3.9 JCAbstractScale

JCAbstractScale implements JCScale. It is the superclass of both JCCircularScale and JCLinearScale, and it encapsulates the common properties of both these concrete classes. It does not add any methods beyond those in the interface it implements.

3.9.1 JCAbstractScale Properties

A JCAbstractScale holds the following information: the minimum and maximum values for the quantity being measured, a direction setting, and a zoom factor. Its pick() method is used for processing a scale value corresponding to the point at which a mouse click occurred. Here, it is declared abstract because circular and linear scales have differing implementations.

Min, max

These JCScale properties specify the beginning and ending values for the scale. Note that multi-turn functionality (multiple turns required to move from min to max) is not supported. Example:

scale.setMax(25.0); // Maximum value for the scale
scale.setMin(5.0); // Minimum value for the scale

Specifying the direction of travel

By default, a circular scale increases in a counterclockwise direction. A linear scale increases from left to right if its orientation is horizontal or from bottom to top if its orientation is vertical. In these cases this is called the forward direction. To set this direction explicitly, call setDirection(JCAbstractScale.Direction direction) on the scale. The two field values are:

JCAbstractScale.
Direction.FORWARD

Values increase clockwise, or from left to right.

JCAbstractScale.
Direction.BACKWARD

Values increase counterclockwise, or from right to left.

The default value for JCScale.Direction is FORWARD.

See Deprecated way of specifying the direction of travel for a circular gauge for the pre-JClass 5 constants for setting a direction. These have been retained for backwards compatibility, but their use is deprecated.

Zoom factor

By default, the scale is drawn so that it fills the gauge area. If labels, ticks, or other components need to be placed outside the scale they may be cropped. To prevent this, use the zoomFactor property.

A circular scale has a zoomFactor property (called an extent before JClass 5) whose purpose is to avoid scaling problems when you want to have objects extend past the circumference of the scale. Objects exterior to the circumference may not resize properly because the border remains a fixed number of pixels no matter how greatly the window is resized, therefore there is a chance that the exterior objects may be clipped. By setting a scale's zoom factor to be less than 1.0 you can place objects outside the scale yet keep them on the interior of the gauge area, thus avoiding clipping problems if the scale is magnified.

For example, the code that places tick marks and their labels seemingly well outside a circular scale's boundary is:

// Sets the scale factor
scale.setZoomFactor(0.4);
// Places the tick marks and labels

tick.setInnerExtent(1.85);
tick.setOuterExtent(2.0);
tick.setLabelExtent(1.75);

These settings produce the scale shown in Figure 9 on the left.

Figure 9 :  Placing ticks and their labels well outside the scale.

The left-hand figure is labeled "ZF = 0.4," which indicates the zoom factor setting. No border was used to pad the gauge's exterior. The effect has been accomplished just by setting the zoom factor.

The right-hand gauge in Figure 9 has a zoom factor of 1.0. If nothing else were done, the tick marks would lie outside the gauge area (the white rectangle), but by adding a border (the gray area enclosing the gauge), the tick marks are visible within it. If you are allowing end users to resize the gauge, use a zoom factor rather than a border.

Borders are required for linear gauges. Setting a zoom factor on a linear gauge does not remove the necessity of setting a border to avoid the clipping of tick labels at the extremities of the scale. Figure 10 shows that setting a zoom factor on a linear scale compresses it in the direction perpendicular to the scale, but leaves the length of the scale unaffected.

Figure 10 :  Comparison of a zoom factor (left) and a border (right) for a linear gauge.

On the other hand, setting a border around the scale allows room for the tick labels to be properly drawn. You can adjust the individual border thicknesses to suit your application. For more on setting a zoom factor for a linear gauge, see Setting a zoom factor, in Chapter 3.


3.10 The Circular Scale Object

The JCCircularScale object and its superclass JCAbstractScale form the basis of all the quantifiable elements of the circular gauge1. Since a circular scale belongs to a circular gauge, the constructor for a JCCircularScale requires an argument of type JCCircularGauge. One circular scale object at a time may belong to a JCCircularGauge component. Also, the gauge keeps a reference to its circular scale in JCGauge.

3.10.1 Circular Scales

A JCCircularScale inherits its direction, minimum and maximum values, lists of ranges and ticks, and zoom factor from JCAbstractScale. In addition it defines a start angle and stop angle, and a radius.

Other than being able to specify its foreground color, the circular scale contains no other visual information. Tick objects use the scale to determine what values to assign to tick labels, and needles have a value based on their location on a scale.

3.10.2 Notes on Circular Scale's Properties

The circular scale object's job is to hold the required numerical information for the construction of a circular gauge, but not any visual information except for the scale's foreground color. Displaying the information is the responsibility of indicators, needles, tick marks, ranges, and so on. Some of these are shown in Figure 11, along with the circular scale's property values that define the direction, set the numerical range values, determine the part of the circle that is to be displayed, and set the scale's start and stop angles.

Figure 11 :  A circular scale showing representative values for its properties.

It is also possible to provide a foreground color such as the one shown in Figure 11.

3.10.3 Angles In a Circular Scale

The convention for angular measurement in a circular scale defines due east as the zero degree line. Angles increase in a counterclockwise direction, so that 90° is due north, 180° is due west, and 270° is due south. This is the direction specified by the constant

JCAbstractScale.Direction.FORWARD

Figure 12 illustrates the way that angular measurement is done in the circular scale, showing the X-axis, Y-axis, and location of the zero degree line.

The start angle is usually less than the stop angle but it is not a requirement. In the default situation, the direction is counterclockwise and the scale's min value is attached to the scale's start angle.

Once the start and stop angles of a circular scale have been chosen along with the maximum and minimum numerical values to be associated with them, one additional parameter, direction, sets whether the start angle corresponds to the minimum value or the maximum value. A maximum value may be attached to the scale's start angle by setting the direction parameter to backward.

For example, if the start and stop angles are chosen as 90° and 270°, and the values being measured begin at 100 and end at 200, setting the direction to JCAbstractScale.BACKWARD causes the value 200 to be located at 90°. The values decrease around the scale in a clockwise direction, ending at 270° where a value of 100 is located. Thus, while the coordinate system for angular measurement never changes, the direction in which the scale's value parameter increases can be reversed.

Figure 12 :  Diagram of a circular scale's reference plane with direction set to `forward'.

Deprecated way of specifying the direction of travel for a circular gauge

Previously, before the release of JClass 5, the direction of travel for circular scales was defined as:

JCAbstractScale.Direction.CLOCKWISE

Values increase clockwise.

JCAbstractScale.Direction.COUNTERCLOCKWISE

Values increase counterclockwise.

The default value for JCScale.Direction is COUNTERCLOCKWISE.

These constants have been retained. However, if you use the new constants defined in Specifying the direction of travel you will be able to switch between circular and linear gauge types without causing confusion over inappropriate direction names.

Start and stop angles

The start and stop angles specify where measurements begin and end on the circular scale. These two angles, defined in JCCircularScale, specify the compass positions at which the min and max values are located. A circular scale positions zero degrees at due east. Angles increase in the counterclockwise direction no matter what the value of JCAbstractScale.Direction is. A start angle may be greater than a stop angle, which would be the case if a scale's min value begins at the twelve o'clock position and its max value is at the three o'clock position. In this case, the start angle is 90° and the stop angle is zero degrees.

These angles may be set in JCCircularScale's constructor. Alternatively, start and stop angles may be set using setStartAngle() and setStopAngle(). For instance:

JCCircularScale scale = new JCCircularScale();
scale.setStartAngle(15);

sets the scale's start angle at 15°.

Figure 13 :  A case where the start angle is greater than the stop angle.

Radius

JCCircularScale has a getRadius() method that returns the size of the circular scale. Initially, the size of the gauge may be set using JComponent's setPreferredSize() method. Also, the size of the scale relative to its container is controlled by the zoomFactor property.

Assigning a color

A scale's color may be assigned in a JCCircularScale's constructor, or you may use JComponent's setForeground() method. By default, only the portion of the scale between its start and stop angles is colored. Any remaining portion retains the color of the gauge. If you wish to assign the color to the full scale, set the scale's paintCompleteBackground property to true:

  (JCCircularScale)
gauge.getScale().setPaintCompleteBackground(true);

Figure 14 :  Using paintCompleteBackground to determine how much of the scale is colored.

If you want to color only the portion of the scale between the start and stop angles, use setPaintCompleteBackground(false).

Labels in a circular gauge

Labels in a circular gauge work similarly to the way they do in a linear gauge except that they use CircularConstraints. See Labels in a linear gauge for information.


3.11 The Linear Scale Object

JCLinearScale provides a graduated scale drawn in a linear fashion. Figure 15 shows a simple linear scale. In addition to the scale, the gauge in the figure has two triangularly-shaped indicators, a needle, two ranges, a set of labeled tick marks, and a collection of labels. There is a border around the scale. It has the same color as the scale's background, but its presence is important to scale's layout. See the section on Borders.

Setting a linear scale's direction and orientation

By default, scale values increase from left to right, as shown in Figure 15. The direction may be controlled by setting either one of:

scale.setDirection(JCAbstractScale.Direction.BACKWARD);
scale.setDirection(JCAbstractScale.Direction.FORWARD);

A linear scale is oriented either horizontally or vertically. The default orientation is horizontal, and the setting is controlled by JCLinearScale.Orientation, whose values are:

JCLinearScale.Orientation.HORIZONTAL
JCLinearScale.Orientation.VERTICAL

A typical call is:

JCLinearScale scale = new JCLinearScale();
scale.setOrientation(JCLinearScale.Orientation.VERTICAL);

Borders

You will likely want to place a border around each of your linear gauges. If you don't, the tick label numbers may appear to be clipped by the sides of the container. The linear gauge in Figure 15 has a 20-pixel-wide border that was constructed as follows:

Border border = BorderFactory.createLineBorder(new Color(247, 255, 206), 20);
scale.setBorder(border);

In this case, the scale's border has the same color as the scale's background color, so the viewer is not aware of its presence. The visible dark border is part of the gauge, not the scale. Note that it's possible to write into the border area. Parts of the Direction, Orientation, Min, Max, and Ranges labels are actually in the scale's border area.

You can use createEmptyBorder() to assign different widths to all four sides.

Figure 15 :  All elements shown, including the dark border, are parts of a linear gauge.

Labels in a linear gauge

Place labels using a LinearConstraint. Its constructor takes a reference to the parent gauge, an extent, and an int representing a position along the scale. The extent parameter is the distance from the top-left corner of the scale2. This distance is vertical for horizontal scales and horizontal for vertical scales, and is specified as a ratio of the required distance to the height of the scale when its orientation is horizontal, or to the width of the scale when its orientation is vertical. The position parameter measures the distance in pixels from the left-hand side when the gauge's orientation is horizontal, or from the top of the scale when its orientation is vertical.

JLabel l1 = new JLabel("<html><font color=black>Indicator One");
l1.setToolTipText("Indicator One");
gauge.getGaugeArea().add(l1, new LinearConstraint(gauge, 0.15, 75));

Setting a zoom factor

Your design may require that indicators, labels, and the like should appear on the outside of the scale. You may be able to use a border to accomplish this task; however, a linear scale provides a more flexible mechanism called a zoomFactor. In a linear scale, a zoom factor less than one compresses the height of the scale (if the orientation is horizontal) while leaving the width (the scale direction) unchanged. In general, the zoom factor compresses the dimension at 90° to the scale no matter what the orientation is. Thus, setting

scale.setZoomFactor(0.6);

compresses the scale to 60% of its size and leaves room totalling 40% of the scale height evenly above and below the scale. Needles or ticks with inner extents less than one or with outer extents greater than one will display nicely even when the component is resized.

For even more control, two Boolean properties, useZoomFactorForMin and useZoomFactorForMax are available. By default, both of these are true, but if one of these is set to false, the zoom factor will not be applied to the appropriate min and max extent portions of the scale. If both useZoomFactorForMin and useZoomFactorForMax are set to false, the zoom factor is ignored.

Pick: getting values from the scale by user interaction

The pick() method returns the scale value corresponding to an end user's mouse click.

3.11.1 Methods in JCLinearScale

The table lists the commonly used methods for a JCLinearScale:

JCLinearScale Method

Description

add()

Overrides add to pass in a linear constraint. The first parameter is the component to be added and the optional second component is an index denoting the order among the other components that have been added to the parent.

getLinearGauge()

Returns the linear gauge associated with this scale.

getOrientation()
setOrientation()

Returns or sets the JCLinearScale.Orientation for this linear scale. Values are: JCLinearScale.Orientation.HORIZONTAL or JCLinearScale.Orientation.VERTICAL, specifying the orientation in which scale values are rendered.

getScaleSize()

Calculates the rectangle that defines the position and dimensions of the linear scale.

getUseZoomFactorForMax
setUseZoomFactorForMax

Determines whether to apply the zoom factor to the max extents portion of the scale. Default: true.

getUseZoomFactorForMin
setUseZoomFactorForMin

Determines whether to apply the zoom factor to the min extents portion of the scale. Default: true.


3.12 Tick Objects

Tick objects provide annotation marks on the circular or linear scale. They provide the usual graduations that are often found on measuring devices. It is possible to have many different tick objects associated with a scale; for instance, two tick objects can provide major and minor graduations. Typically, major tick marks have associated labels displaying numerical values, or you may supply your own definition for tick labels using the JCLabelGenerator interface.

Both tick marks and tick labels may be turned on and off independently for each tick object. A property called drawTicks controls whether tick labels are drawn, and another called drawLabels controls whether the associated labels are drawn. Examples are given later in this section.

You can set the start value, stop value, the tick increment value, and the inner and outer extents for the tick marks. These extent parameters control the length of the tick line in the radial direction in the case of a circular gauge, or the height/width in the case of a linear gauge. They are specified as decimal fraction of the scale's radius in the circular case, or the scale's height/width in the linear case. If you wish, you may specify a color and a width for the tick object. If you do not set a particular property, the object chooses a default value.

You can set the precision for values displayed on tick mark labels, but be aware that reducing the precision may introduce rounding issues that may make the scale markings confusing. See A note on precision for an explanation.

The following diagrams illustrate both circular and linear ticks.

Figure 16 :  Some circular gauge tick objects and their associated labels.

Figure 17 :  Linear gauge tick objects and their associated labels.

You specify where the tick marks are to begin and where they are to end. This allows you to place tick marks over a portion of the scale as shown in the bottom left scale in Figure 16 and Figure 17. Note the different tick styles in the figures. There are custom tick style set for the scales in the lower right of Figure 16 and Figure 17. See Defining your own tick style for details.

Since you can control the visibility of tick marks and tick labels independently, you may choose to have only the labels showing. This may be useful if you wish to have a single style of tick mark but label every second one.

3.12.1 Notes on the Tick Object

Associating a tick object with a scale

Tick objects need to know the scale for which they are to provide graduations. One of the parameters in the tick object's constructor is the scale associated with the tick object. Thus, a tick object cannot be instantiated without specifying its associated scale. Once you have a tick object, you still need to add it:

JCLinearTick tickMark;
// Instantiate the tick...
gauge.getScale().addTick(tickMark);

Setting the tick type

There are six built-in types: circle, diamond, line, rectangle, reverse triangle, and triangle. The types are held in the JCTickStyle class. Example:

JCTick tick = new JCCircularTick(...);
tick.setTickStyle(JCTickStyle.TRIANGLE);

Defining your own tick style

You can define your own tick style by defining its shape using two arrays, one for the X-coordinates and one for the Y-coordinates. Pass these arrays and an int specifying the number of points to JCTickStyle's constructor. Alternatively you could subclass JCTickStyle and define your new styles as constants. In either case, define a shape as an array of X- and Y-coordinate points as you would for any Rectangle:

import com.klg.jclass.swing.gauge.JCTickStyle;
public class MyTickStyle extends JCTickStyle {
public static final JCTickStyle NOTCHED_RECTANGLE = new JCTickStyle(
new int[] {-10, -2, 0, 2, 10, 10, 2, 0, -2, -10},
new int[] { 3, 3, 1, 3, 3, -3, -3, -1, -2, -2},
10);

}

Use your newly defined tick style by calling

tick.setTickStyle(MyTickStyle.NOTCHED_RECTANGLE);

Alternatively, you can use the JCTickStyle constructor that allows you to define your own (x, y) coordinate pairs. This example can be seen in the lower right of Figure 17:

int xpoints[] = {-100, 0, 100, 100, 0, -100};
int ypoints[] = { 0, 100, 100, -100, -100, 0};
int numpoints = 6;
tick.setTickStyle(new JCTickStyle(ypoints, xpoints, numpoints));

Note: The layout algorithm assumes that the center of the tick mark's bounding rectangle is at (0, 0).

Setting the tick object's placement

Tick marks are normally required at constant increments along a scale. The tick object accomplishes this objective by using the associated scale's min and max values, and the precision value, to determine appropriate values for the tick object's start, stop, and increment values. Alternatively, you can control the spacing by setting automatic to False. You still control where the tick marks are to begin with startValue and where they are to end with stopValue, but you set how many tick marks there are with incrementValue.

Setting a tick object's dimensions

The placement of a tick mark is controlled with innerExtent and outerExtent. The values for both of these properties are numbers representing a proportion relative to the size of the associated circular or linear scale. For instance, if the value set on innerExtent is 1.0, tick marks begin right at the circumference of a circular scale, or at the edge3 of a linear scale. For circular scales, tick marks are drawn radially outward to the value set in outerExtent, which is also given as a ratio based on the radius of the associated circular scale. For linear scales, the outer extent of 1.1 causes the tick mark to terminate 10% of the scale's vertical dimension below the bottom edge of the scale when the orientation is horizontal, or 10% of the scale's horizontal dimension to the right of the right edge of the scale when the orientation is vertical.

Note: If your tick marks extend outside the scale, that is, at extents less than 0 or greater than 1.0, and you allow the scale to be resized, you may have to increase the dimensions of the scale's borders to ensure that there is enough space to hold the tick marks, otherwise their outer extents may be clipped. Alternatively, set the scale's zoomFactor property to a value less than 1.0 and the tick's outer extent to 1.0 to give the appearance of tick marks lying outside the scale. In fact, they are within the scale's boundary, but they appear to lie outside the colored portion of the scale. See GaugeOutsideExample.java in the examples directory for an illustration of this technique.

If the inner extent is equal to the outer extent, no ticks are drawn, but the preferred way of hiding tick marks is to set drawTicks to false.

The width in pixels of the tick marks is specified in the tickWidth property. This property must be set for any tick style other than JCTickStyle.LINE.

Labeling tick increments

Labeling may be on or off, depending on the value of drawLabels. In automatic mode, one of the ways the object manages the span between labeled tick marks is by using the precision property's value. If you are controlling the placement of labeled tick marks (tick.setAutomatic(false)), make sure you have set precision properly, as explained in A note on precision.

Note: If you do place labels outside the scale and you allow the scale to be resized, you may have to increase the dimensions of the scale's borders to ensure that there is enough space to hold the labels. Rather than using borders, the recommended method is to adjust the scale's zoomFactor property. See the previous note in Setting a tick object's dimensions.

Custom tick labels

Tick labels are drawn with the help of the JCLabelGenerator interface. It contains a single method, makeLabel(), which takes three parameters: a JCTick, a scale value, and a GaugeConstraint4. Use the method in JCAbstractTick called setLabelGenerator() to tell the gauge to use your custom labeling mechanism.

The following code snippet uses an anonymous inner class to add an implementation of JCLabelGenerator to a tick object. The makeLabel() method is passed a reference to the tick object in question, the scale value for the tick mark in question, and a reference to the tick's RadialConstraint. Only the value parameter is used in this example. Since the tick marks are supposed to display temperature values, the custom labels are coded to produce temperature values along with their units of measurement, for example, 20° C.

// create a label generator to mark
// the temperature values with their units
tick.setLabelGenerator(new JCLabelGenerator() {
public JComponent makeLabel(JCTick tick, double value, RadialConstraint constraint) {

String s = (value != 0) ? String.valueOf((int)value)
: "zero";
JLabel label = new JLabel(s + "\u00B0 C");
label.setToolTipText(s + "\u00B0 C");
return label;
}
});

The code adds "° C" to each value except 0°, where it supplies the word "zero" instead.

For an example of a custom label in a user-defined class, see GaugeSwitchExample.java.

Another reason for using custom tick labels is to provide an offset between a label and its associated tick mark. Normally a label lines up with its tick mark so that a line joining the center of the scale and a tick mark also goes through the center of the tick mark's label. You can use JCLabelGenerator to offset the label, since a GaugeConstraint is passed as one of the parameters of makeLabel().

A note on precision

If precisionUseDefault() is true, a default value for precision is determined. This value should be sufficient for most situations. However, you can specify your own precision using setPrecision(). This has the side effect of setting precisionUseDefault to false. The precision setting affects the width of the label and therefore the number of labels that may be used without overlapping. The effect is quite noticeable if automatic is true. The number of labels changes as the scale is zoomed, becoming fewer during contraction so that the label on one number does not overlap adjacent labels, or becoming more numerous during expansion so that labeled marks do not become too widely separated. Wider labels will be fewer in number compared to the same scale with shorter tick labels. All this happens because the tick object automatically calculates the number of tick labels. Note that drawLabels must be true or the labels won't show.

The value of the precision property controls how tick labels are interpreted. There are three cases to consider:

Failure to set the precision property may be the source of a misleading scale. As an example, setting the start value of a tick object at -25, the stop value at 160, and allowing the default precision sets the precision to -1. In this case the first tick mark is where the scale starts, that is, at -20, which is probably not what was desired. Setting the precision to 0 rectifies the problem because this specifies that digits in the units column must not be rounded.

3.12.2 Methods

The tick object has the following get/set methods:

JCAbstractTick Method

Description

getAutomatic()

setAutomatic()

Controls whether the tick object is functioning in automatic mode or in manual mode. If it is in automatic mode, the associated scale's min and max values and the value of precision are used to determine "pleasing" tick start, stop, and increment values. Tick spacing is calculated by the gauge and any settings to these properties will be ignored, that is, the values reset to the automatic values. If the tick object is in manual mode, whatever values you set in startValue, stopValue, and incrementValue are honored provided they are legal.

getDrawLabels()

setDrawLabels()

Returns the Boolean controlling the drawing of labels. If true, use the value of precision to place a numeric label on each tick value.

getDrawTicks()

setDrawTicks()

Returns the Boolean controlling the drawing of tick marks. If true, use the value of precision or incrementValue to determine how many tick marks to draw.

getFont()

Returns the Font used for tick mark labels (java.awt.Component).

getFontColor()

setFontColor()

Returns or sets the Color used for tick mark labels.

getIncrementValue()

setIncrementValue()

The tick increment value. In automatic mode, this value is read-only. In non automatic mode, this value can be changed.

getInnerExtent()

setInnerExtent()

The inner (towards the center of a circular scale) extent of each tick drawn. This value is related to the radius of an associated circular or linear scale. For example, a value of 0.9 means each tick's inner extent is 0.9 times the radius value of the scale away from the center, or a 0.9 times the scale's height/width away from the top left of the scale.

getLabelExtent()

setLabelExtent()

The location of the center of each label. This value is related to the radius of the associated circular or the height/width of the associated linear scale; a value of 1.1 means each label's extent is 1.1 times the radius value of a circular scale away from the origin, or 1.1 times the height of a linear scale away from its top edge, or 1.1 times the width away from the left edge, depending on its direction.

 

Note: extending the label outside the scale may require adjustment of the borders.

getLabelGenerator()

setLabelGenerator()

Returns the label generator associated with this tick. Consult the API for interface JCLabelGenerator and its makeLabel() method for information on defining your own labels. A minimal example is given in the section on Labeling tick increments in this chapter.

getOuterExtent()

setOuterExtent()

The outer extent of each tick drawn. Outer extent values increase towards the component's boundary. This value is related to the radius of the associated circular scale, or the width/height of the associated linear scale. For example, a value of 1.1 means each tick's outer extent is 1.1 times the radius value of the scale in a direction away from the center, or 1.1 times the height of a linear scale away from its top edge or 1.1 times the width away from its left edge, depending on its orientation.

 

Note: extending the tick mark outside the scale may require adjustment of the borders.

getPrecision()

setPrecision()

Affects the format of the tick label. This property defines the number of digits of precision after the decimal point to be used for labels. If its value is zero or less, the labels will all be integers.

Positive values denote the number of places after the decimal point (for example, 3 means multiples of 0.001); negative values indicate the number of zeros to be used before the decimal place (for example, -3 means numbering will be in multiples of 1000).

A side effect of setting this property is to set the corresponding precisionUseDefault property to false.

getPrecision
  UseDefault()

setPrecision
  UseDefault()

If true, use the gauge-determined precision for tick labels, otherwise use startValue, stopValue and incrementValue to place ticks along the scale. If you set this property to false you should set a value for precision as well (unless a value has been calculated previously).

getScale()

Returns the scale associated with this tick. Tick marks must be associated with a scale (this is enforced by the Tick object's constructor).

getStartValue()

setStartValue()

In non automatic mode use this value as the start value. The value must be between the associated scale's min and max values, including end points.

getStopValue()

setStopValue()

In non-automatic mode use this value as the stop value. The value must be between the associated scale's min and max values, including end points.

getTickColor()

setTickColor()

The Color of the tick mark.

getTickStyle()

setTickStyle()

Predefined tick styles are JCTickStyle.CIRCLE, JCTickStyle.DIAMOND, JCTickStyle.LINE, JCTickStyle.RECTANGLE, JCTickStyle.REVERSE_TRIANGLE, and JCTickStyle.TRIANGLE. Extend JCTickStyle to define your own shape for tick marks, or define one by passing X- and Y-coordinate points to JCTickStyle's constructor.

getTickWidth()

setTickWidth()

The width in pixels of the widest part of the object. Ticks whose style is circle or line ignore this property.

isReversed()

setReversed()

The reversed property is used to choose a mirror image of a tick mark. If the default mark is <, the reversed tick mark is >.

3.12.3 Sample Code

The following example illustrates using the tick object's constructor. If you create a gauge using one of the convenience constructors you already have a tick object associated with the scale that you can access using code; for example:

JCCircularTick tick = (JCCircularTick)
gauge.getScale().getTicks().elementAt(0);

Then simply set the properties you wish to change from their default values. Nonetheless, it is often useful to create tick objects from scratch and set properties in the constructor. This way you inspect each property and determine its appropriateness for your application. Here's an example:

// create a Tick object and set its properties
JCTick tick = new JCCircularTick(
scale, // the associated circular scale
false, // automatic tick generation
0, // start
300, // stop
25, // increment
false, // precisionUseDefault
0, // precision
2, // width
true, // draw labels
true, // draw ticks
0.75, // label extent
0.85, // inner extent
1.0, // outer extent
Color.white,
JCTickStyle.LINE,
new Font("Helvetica", Font.BOLD, 18),
Color.white);


3.13 The Range Object

On circular scales, ranges are rings or partial rings used to emphasize certain sections of the scale by coloring them. By using range objects, an implementor can draw arcs (which may be full circles) and provide differently colored subdivisions on the scale.

On linear scales, ranges are rectangular bars running along the direction of the scale.

Ranges may be either colored bands or images.

If the range is narrow enough it has the appearance of a tick mark. This effect may be of use if you wish to provide special tick marks, such as those marking the dynamically changing maximum and minimum values on a temperature scale. See the demo TemperatureFluctuationExample.java.

Ranges are associated with a scale. There may be multiple ranges for the same scale.

You can control the inner and outer radii (and thus the thickness) of the range. As well, you set start-stop values (and thus the breadth), and the color. Figure 18 shows two range objects on a circular scale. The thinner one spans the entire scale and appears as the circumference of the scale. The thicker one spans the region between tick marks 20 and 80. The diagram shows how a start value, stop value, inner extent, and outer extent determine the shape of a range.

Figure 18 :  Two range objects for a Circular Scale object.

Figure 19 shows a Circular Gauge component in which one range object covers another, partially obscuring it. The drawing order in Figure 19 is first the semicircular range, followed in succession by the 20-80 range, the tick marks, the needle, and finally the center. If the objective is to show the semicircular range, draw the 20-80 range first. This topic is discussed in more detail in the next section.

Figure 19 :  A range object that is the same size as its associated scale.

3.13.1 Notes on the Range Object's Properties

Coloring a range

A range object's color is set by the first parameter in its constructor. Use the setForeground() method on a JCCircularRange or JCLinearRange object to change the color of a range once it has been instantiated.

Associating a range with a circular or linear scale

A range object has to be associated with a parent scale by providing a reference to it in the constructor, or by using the setScale() method once a range has been instantiated.

A range spans a region of its associated scale, but to be visible it must have a thickness as well as a span. Properties innerExtent and outerExtent control the inner and outer limits of its thickness. Values for these properties are given as ratios based on the size of its associated scale. For example, in a circular gauge an inner extent of 0.75 and an outer extent of 1.25 mean that the thickness is half the radius of the associated circular scale and is placed symmetrically over the circumference.

Extending past the scale

If you wish to use an offset to shift a range beyond the end of the tick marks, create a circular scale spanning all the values you need to display but supply tick marks for one portion of the scale and a range for another portion.

Figure 20 :  An offset is applied to the outer range of Figure 18.

As shown in Figure 20, an offset appears to begin before the start of the scale. The scale's settings are max = 120, min = -20, startAngle = -36°, stopAngle = 216°. These were calculated to be consistent with the offset given to the range, and to maintain a semicircular appearance for the labeled part of the scale.

3.13.2 Constructors for JCCircularRange and JCLinearRange

The constructors are:

JCCircularRange(java.awt.Color foreground,
JCCircularScale scale,
double innerExtent,
double outerExtent,
double startValue,
double stopValue)

public JCLinearRange(java.awt.Color foreground,
JCLinearScale scale,
double innerExtent,
double outerExtent,
double startValue,
double stopValue)

All range properties are set in the constructor, along with associating a range with a circular scale. Range properties are listed next.

3.13.3 Methods and Properties for JCRange and JCAbstractRange

JCAbstractRange Method

Description

getInnerExtent()

setInnerExtent()

Returns or sets the ratio of the radius' length at which to start drawing this range from the center outwards for circular scales, or the distance away from the inner edge for linear scales. For example, a value of 0.5 means the inner extent should begin one-half the distance between the scale's origin and the scale's circumference or outer edge.

getOuterExtent()

setOuterExtent()

Returns or sets the value at which the outer boundary of the range is drawn. The value is expressed as a ratio of the radius' length. For example, a value of 1.5 means the outer extent lies 1.5 times the scale's radius away from the center, or 1.5 times the linear scale's height away from the inner edge.

getScale()

Returns the scale associated with this range.

getScaleImage()
setScaleImage()

Returns or sets the flag that controls whether to scale the image within the dimensions of the range.

getStartValue()

setStartValue()

Returns or sets the scale value (not the angle) where the range is to begin. This value should be between the associated scale's min and max values.

getStopValue()

setStopValue()

Returns or sets the scale value (not the angle) where the range ends. This value should be between the associated scale's min and max values.

Additional Methods

Description

setForeground()

Method inherited from class javax.swing.JComponent. Used to dynamically color the range after it has been instantiated.

setVisible()

Method inherited from class javax.swing.JComponent. Used to dynamically show or hide a range.

3.13.4 Sample Code

Set the property values for the range object in its constructor using the sample below as a guide.

// create a range that marks the circumference of the scale
circumference = new JCCircularRange(
Color.black, // range color
gauge.getScale(), // one way of referencing a scale
0.95, // range inner extent
1.00, // outer extent is at the radius
0, // start value for the range
100); // stop value for the range


3.14 The Indicator and Needle Objects

Indicators are a general mechanism for placing static5 markers on a scale. Needles are meant for user interaction, so the JCAbstractNeedle subclass of JCAbstractIndicator has built-in capabilities for control by end users. If you permit it, an end user can reposition a needle by clicking, dragging, or both.

Indicator and needle objects are the visible pointers on a scale object in a JCGauge component. Any number of indicators may be displayed on the same scale. Each indicator has its own value and this value determines where on the scale it is positioned. The gauge manages its list of indicators by keeping them in a Vector.

You can control the indicator's color, length, width, and shape. The shape scales itself by using its length and width parameters.

The needle is drawn using its shape attribute. Basic constants exist for drawing triangles, pointers, and arrows, or you may provide your own shape.

The position of an indicator, and therefore its associated value on a scale may be controlled programmatically, and the needle subclass may be controlled via an end user action. A needle can be positioned by either clicking or dragging on the scale so long as a needle interaction is enabled. You can add a ChangeListener to a needle to respond to mouse actions. Additionally, the gauge has a JCGaugePickListener interface that permits retrieval of the scale value corresponding to the spot where a mouse click occurs. You can enable click and drag interactions with a needle via the inner class called JCNeedle.InteractionType, which contains constants that specify the possible types of interactions between mouse actions and needles.

These are:

Interaction Type

Description

CLICK

The needle snaps to a mouse click.

CLICK_DRAG

The needle snaps to the mouse click, or follows a mouse drag.

DRAG

The needle snaps to the position of the mouse when the drag operation begins, then follows it until the mouse button is released.

NONE

Default case: neither clicking nor dragging affects the needle.

When a needle's value changes, a value changed callback is called to allow the program to disable or limit the change. Use sendEvents() to control whether an event is generated as a result of an action taken in the callback.

3.14.1 Notes on the Indicator's Properties

Indicator shapes

An indicator has seven possible built-shapes: arrow, tailed arrow, circle, pointer, rectangle, tailed pointer, or triangle, as shown in Figure 21. These shapes are controlled by the constants in JCIndicatorStyle. They are ARROW, CIRCLE, POINTER, RECTANGLE, TAILED_ARROW, TAILED_POINTER, and TRIANGLE.

Setting an indicator's length

The indicator's length is based on the associated scale and is set as a decimal fraction of the scale's dimensions using its innerExtent and outerExtent properties. In the circular case, an indicator begins at the center of the circular scale and extends outwards. For example, if its outerExtent property is set to 1.0, the indicator's tip lies on the circumference of the associated circular scale. In the linear case, an indicator's extents are measured from the top of the gauge area when the orientation is horizontal, or from the left-hand edge when the scale is vertical.

Setting a needle's length

As a subclass of JCAbstractIndicator, a needle has inner and outer extents, and because it is a subclass of JCAbstractNeedle, it has a length property as well. Setting the needle's length is equivalent to setting its outer extent. If you want to have the needle begin away from the center of a circular gauge, set its inner extent to some positive value. The value is expressed as a ratio based on the radius. Likewise, a linear needle may be offset from the top of a linear horizontal scale by setting its inner extent. In this case, the inner extent may be positive or negative, but you will have to set a border on the scale to prevent the needle from being clipped. Example:

((JCLinearNeedle)
gauge.getNeedles().firstElement()).setInnerExtent(0.3);

Figure 21 :  The seven built-in indicator shapes.

Setting an indicator's width

An indicator's width is set using the indicatorWidth property, or the needleWidth property in the case of a needle.

Defining a custom indicator style

It is possible to provide your own indicator style if you require a custom shape. The method is the same as in Defining your own tick style. The simplest way is to use the JCIndicatorStyle constructor that allows you to define a new shape. If you wish to keep your new indicator styles for general reuse as class constants, extend JCIndicatorStyle and define a shape as arrays of coordinate points using the same format as you would for java.awt.Rectangle. Here is an example:

import com.klg.jclass.swing.gauge.JCIndicatorStyle;

public class MyIndicatorStyle extends JCIndicatorStyle {
/**
* A needle in the form of a diamond using these array values
*/

public static final JCIndicatorStyle DIAMOND = new JCIndicatorStyle(
new int[] { -100, 0, 100, 0},
new int[] { 0, 100, 0, -100},
4);

The JCIndicatorStyle constructor that allows you to define a new shape has been used here to define the class constant.

Often an indicator style is defined so that the shape starts at the center of a circular scale. A shape defined this way also starts at the inner edge of a linear scale. Since the DIAMOND defined above starts at -100, it does not start at the scale's center or edge when it is drawn. Instead, this DIAMOND straddles the center. You'll need to test your design to see that it scales properly if you begin your needle away from the center and you intend to allow scaling.

Indicators may be sized however you wish, but if the inner or outer extent specification causes the indicator to be drawn outside the component's boundary the indicator will be clipped. You may increase the border size to compensate, but borders are not scaled when components are resized. Since the indicator's length is defined as a fraction of its associated scale's radius, it may still elongate past the border if the component is expanded too much. An alternative approach is to use the scale's zoomFactor property, set to some value less than one. This has the effect of shrinking the scale so that its boundary is less than its true radius. An indicator whose length is greater than 1.0 appears to extend beyond the scale. Because it is really inside the scale's actual boundary it can be resized without clipping.

Coloring an indicator object

An indicator's color is set in its constructor or by using javax.swing.JComponent.setForeground().

Controlling a indicator's visibility

You can show or hide an indicator by setting its java.awt.Component.setVisible() method to true or false respectively. Test the visibility with java.awt.Component.isShowing().

Positioning an indicator with the mouse

Use the JCAbstractNeedle.InteractionType constants to determine how the needle responds to mouse clicks within the Circular Gauge component. To stop the needle from responding to the mouse, use InteractionType.NONE. Other possible values are CLICK, DRAG, or CLICK_DRAG.

3.14.2 Constructors

Both JCAbstractIndicator and JCAbstractNeedle have two constructors. The first takes a JCScale object and creates an indicator or needle with default settings. The following ones allow you to set properties, associate it with its parent scale, and, in the case of a needle, specify an interaction type:

public JCAbstractIndicator(
Color foreground, // foreground color
double indicatorWidth, // indicatorWidth
JCScale scale, // associated scale
boolean visible, // true: indicator is visible
double inner_extent, // inner extent
double outer_extent, // outer extent
JCIndicatorStyle indicatorStyle, // indicator style
double value // where to place this indicator
)

public JCAbstractNeedle(
java.awt.Color, // foreground color
double width, // needleWidth

JCScale scale, // associated scale
JCAbstractNeedle.InteractionType, // needle interactionType
boolean visible, // true: needle is visible
double, // length
JCIndicatorStyle, // needleStyle
double value, // where to place this needle
)

3.14.3 Methods and Properties

JCAbstractIndicator is the super class for JCCircularIndicator, JCLinearIndicator, and JCAbstractNeedle. Indicators are used to point to zero or more selected values on a scale.

Indicator methods and properties

Indicator Properties

Description

getForeground()

setForeground()

In java.awt.Component, returns or sets the needle's color, a java.awt.Color.

getIndicatorStyle()

setIndicatorStyle()

Returns or sets the shape of the indicator. Possible values are:

JCIndicatorStyle.ARROW

JCIndicatorStyle.POINTER

JCIndicatorStyle.TAILED_ARROW

JCIndicatorStyle.TAILED_POINTER

JCIndicatorStyle.TRIANGLE

 

It is possible to define your own indicator style by extending JCIndicatorStyle or by using its constructor.

getIndicatorWidth()

setIndicatorWidth()

Returns or sets the width of the indicator in pixels.

getInnerExtent()

setInnerExtent()

Returns or sets the inner extent of this indicator as a ratio of the scale's width, height, or radius (depending on the scale's type and orientation).

getOuterExtent()

setOuterExtent()

Returns the outer extent of this indicator as a ratio of the scale's width, height, or radius (depending on the scale's type and orientation).

getPreferredSize()

Overridden so that the indicator scales with the gauge.

getScale()

Returns the JCScale associated with this indicator.

getValue()

setValue()

Returns or sets the scale value (not the scale angle) to which the indicator points. When setting this value care should be taken to ensure it is between the scale's min and max values. An indicator may not be dragged outside the scale's range, that is, before its startValue or after its stopValue.

isReversed()

setReversed()

An indicator that lacks longitudinal symmetry may be reversed. For example, the default JCIndicatorStyle.ARROW points outwards on a circular scale. By setting the reversed property to true the arrow points toward the center rather than at the circumference.

Needle methods and properties

Needle properties allow you to control most aspects of the needle's appearance save for its drawing order (z order) with respect to the other gauge components. By managing the order in which gauge.addNeedle() is called relative to the other gauge.addComponent methods you achieve your intended layering effect. For instance, by adding a center and then a needle, the part of the needle under the center is obscured.

JCAbstract Needle inherits all the methods of:

Needle Methods

Description

addChangeListener()

removeChangeListener()

Adds or removes a listener interested in needle movements.

Needle Properties

Description

getForeground()

setForeground()

In java.awt.Component, returns or sets the needle's color, a java.awt.Color.

getGauge()

setGauge()

Returns or sets the circular gauge associated with the needle.

getInteractionType()

setInteractionType()

The type of allowed mouse interaction. Possible values are:

JCAbstractNeedle.InteractionType.NONE

JCAbstractNeedle.InteractionType.CLICK

JCAbstractNeedle.InteractionType.DRAG

JCAbstractNeedle.InteractionType.CLICK_DRAG

getLength()

setLength()

Returns or sets the needle's length, expressed as a decimal fraction based on the circular scale's radius. Setting a needle's length is the same as setting its outer extent.

getNeedleStyle()

setNeedleStyle()

Returns or sets the shape of the needle. Possible values are:

JCIndicatorStyle.ARROW

JCIndicatorStyle.POINTER

JCIndicatorStyle.TAILED_ARROW

JCIndicatorStyle.TAILED_POINTER

JCIndicatorStyle.TRIANGLE

 

It is possible to define your own needle style by extending JCIndicatorStyle or by using its constructor.

getNeedleWidth()

setNeedleWidth()

Returns or sets the width of the needle in pixels.

getPreferredSize()

Overridden so that the needle scales with the gauge.

getSendEvents()

setSendEvents()

Returns or sets a sendEvents flag; true means events will be sent when the needle's value changes, false means don't send the events. Use this method if your code might otherwise trigger a non-terminating sequence of events, such as setting a needle to its value plus one.

getValue()

setValue()

Returns or sets the scale value (not the scale angle) to which the needle points. When setting this value care should be taken to ensure it is between the scale's min and max values. A needle may not be dragged outside the scale's range, that is, before its startValue or after its stopValue.

 

3.14.4 Code Sample

If you have used the default gauge constructor, a needle is supplied. You can obtain a handle to it as follows:

  JCNeedle needle = ((JCNeedle)gauge.getNeedles().firstElement());

You can completely configure a needle at the time it is created. The following code sample shows how:

JCNeedle needleOne =
    new JCCircularNeedle(
      Color.red,            // needle's color
      10,            // needle width
      cscale,            // associated circular scale

      true,             // visible?
      0.0,            // inner extent
      1.0,             // outer extent

      JCNeedleStyle.POINTER,            // needle style
      25.0            // needle value
      );

The remaining step is to add the needle to the gauge:

  gauge.addNeedle(needleOne, 0); // Ensure the needle is on top

Adding a change listener for needle movements

If you wish to take some action when a needle is moved you can use the fact that a needle movement generates a change event. You may add a change listener to the needle, for example:

  needleOne.addChangeListener(this); // For needle movements

The class (referenced by the this pointer in our example here) that is to respond to needle movements defines a stateChanged(ChangeEvent e) method to handle whatever action needs to be taken.


3.15 The Center Object

Center object

A center object is associated with a gauge. You can set the center's radius and its color, then add it using the gauge's setCenter() method. Alternatively, you can specify an image for the center object.

A center object is used to mark the position of the center of a circular scale in a JCCircularGauge component. It can be a colored circle or a user-supplied image. If an image is specified, the circular disk will not be drawn.

A center object must be associated with a circular scale. Each of its three constructors demands a scale as one of its parameters.

Figure 22 :  An image used as a center object.

3.15.1 Notes on the Center Object

Setting the center's color

Set the color of the center object using the setForeground() method, or in the center object's constructor. The result is a circular disk of this color at the center of the scale. The size of the disk is controlled by the center's radius property.

Associating a center with a circular scale

Each circular gauge may have zero or one center objects. A center is associated with the gauge through its circular scale object. Specify the circular scale using the scale parameter in the center object's constructor. The center object may be replaced with an image if desired. The image does not rotate.

Sizing the disk

Set the size of the disk using the radius property. The value you pass it is a fraction based on the size of the radius of its associated circular scale. For instance, if you set a value of 0.2, the circular disk marking the center has a radius 20% as long as the radius of the circular scale.

Using an image as the visual

If you require anything other than a circular disk to mark the center of your scale, you can supply an Image. The image is scaled to the radius of the center object if setScaleImage() is true. In this case resizing the gauge causes a proportionate change in the image. See Section 3.15.3, Sample Code, for an example.

The center image can be sized to fill the entire scale. In this case it can be made to appear as a background image on which needles, ranges, and extra tick marks may be placed as desired.

Figure 23 :  Using a center image as a background.

In Figure 23 the parameters for the circular scale have been chosen so that they match the scale markings on the image, which fills the entire circular scale area. The result is an interactive dial with a distinctive look.

Controlling visibility

Use the visible parameter in the constructor to control whether the Center object is visible initially. After the object is created, control its visibility using the setVisible() method.

3.15.2 Constructors, Properties, and Methods

Constructors

JCCenter has three constructors. The one-parameter version requires a reference to the parent JCCircularGauge. The other two require a color parameter and either a size parameter in the case of a circular disk, or an image parameter if an image is to be used.

JCCenter(JCCircularScale scale)
// Creates a drawn, black center disk using a default radius
// that is 10% of the scale's radius.

JCCenter(JCCircularScale scale,
java.awt.Color foreground, // color of the disk
double radius) // Center is a disk

JCCenter(JCCircularScale scale,
java.awt.Color foreground,
java.awt.Image image) // Center is an image

Properties

Property

Description

getImage()

setImage()

Determines the java.awt.Image that is to be drawn at the center of the scale.

getRadius()

setRadius()

Gets or sets the size parameter for the center object when it is a circular disk.

getScaleImage()

setScaleImage()

Boolean that controls whether or not to scale the image when the gauge is resized.

Methods

Protected methods drawDisc() and drawImage() are used to draw the Center, and are used by paintComponent() to actually draw the center object on the screen. getPreferredSize() is overridden so that the center object's proportional size relative to the circular scale can be maintained. These methods are only of concern to those who wish to subclass the center for custom purposes.

3.15.3 Sample Code

Follow these examples if you want to provide a center in your circular scale.

To use a colored disk as the center of circular scale, use this code:

// create a center
JCCenter center = new JCCenter(circularScale, Color.white, 0.1);
gauge.setCenter(center);

To provide an image, use this code:

// use an image
Image image;
image = Toolkit.getDefaultToolkit().getImage("arrow.gif");
JCCenter center = new JCCenter(circularScale, Color.white, image);
gauge.setCenter(center);


3.16 The Constraint Mechanism in JCGauge

3.16.1 RadialConstraint and RadialLayout

The RadialLayout class uses an instance of RadialConstraint to position a component at a given angle and at a specified proportional distance from the center of the associated circular gauge. Thus, the gauge employs RadialConstraint classes to facilitate laying out gauge objects in such a way that the objects' angular positions are maintained as the gauge is resized, as well as maintaining their proper radial proportions.

It supports the placement of any component on the gauge area, not just indicators, needles, ranges, and ticks. Usually these are labels used to annotate a Circular Gauge, but they may be any JComponent, even another gauge.

Constructors

RadialConstraint has a single constructor which is passed a gauge, an extent, and an angle. The extent parameter specifies the radial distance for the placement of the component. The angle parameter specifies the angle. The center of component's bounding rectangle is placed on the gauge at the point defined by the two parameters. Typically an instance of RadialConstraint is passed via the addLabel() method in JCCircularGauge, which passes it to an add() method that knows how to use RadialLayout to position the component.

Here's an example:

JCCircularGauge gauge = new JCCircularGauge();
JLabel label = new JLabel("<html>Pressure (lbs/in&sup2;)");
gauge.addLabel(label, new RadialConstraint(gauge, 0.35, 90));

3.16.2 Linear Constraint and Linear Layout

The LinearLayout class uses an instance of LinearConstraint to position a component at a given extent and at a specified pixel distance from the origin of the associated circular gauge. Thus, the gauge employs LinearConstraint classes to facilitate laying out gauge objects in such a way that the objects' relative positions are maintained as the gauge is resized.

It supports the placement of any component on the gauge area, not just indicators, needles, ranges, and ticks. Usually these are labels used to annotate a linear gauge, but they may be any JComponent, even another gauge.

Constructors

LinearConstraint has a single constructor which is passed a gauge, an extent, and a position. The extent parameter specifies the proportional distance from the top left of the rectangle enclosing the gauge. The distance is vertical for horizontal scales and horizontal for vertical scales, and is specified as a ratio of this distance to the height or width of the scale. The position parameter specifies the distance as an integer representing a percentage of the height or width from the top or left of the scale. The center of the positioned component's bounding rectangle is placed on the gauge at the point defined by these two parameters. Typically an instance of LinearConstraint is passed via the addLabel() method in JCLinearGauge, which passes it on an add() method that knows how to use LinearLayout to position the component.

Here's an example:

JCLinearGauge gauge = new JCLinearGauge();
JLabel label = new JLabel("Pressure Point");
gauge.addLabel(label, new LinearConstraint(gauge, 0.35, 90));


3.17 Labels

Labels are used to annotate a gauge. Any number of them may be placed anywhere within the boundaries of the gauge area using a gauge's addLabel() method, which in turn uses a RadialConstraint or a LinearConstraint. Because it is a JLabel, it has user-controllable text, position, background and foreground color, images, and borders.

The RadialConstraint class, whose constructor is RadialConstraint(JCGauge gauge, double extent, double angle), lets you specify a label's position by giving a distance from the center of the scale and an angle. The constructor for a linear constraint is LinearConstraint(JCGauge gauge, double extent, int position), which lets you specify a label's position by giving the extent in the transverse direction to the scale and a position along the scale in pixels.

Note that there is an automatic mechanism for providing numeric labels on tick objects or for specifying labeled ticks in user-specified formats. See Section 3.12, Tick Objects, for a discussion of tick labels.

3.17.1 Notes on the Using Labels

You can choose a location within the gauge area by specifying the location of the center of the rectangle containing the RadialConstraint or LinearConstraint class.

You can choose a border type using setBorder and adjust its appearance using the various border factory methods.

One way of setting the font is by using a JLabel's ability to process HTML tags. Set a font using the <font> tag and the color using color = HTMLcolorValue within the tag. If you are adding text to a circular gauge, you can do the following:

JLabel l1 = new JLabel("<html><font color=black>Start Angle = 90\u00B0");
l1.setToolTipText("Start Angle = 90\u00B0");
gauge.addLabel(l1, new RadialConstraint(gauge, 0.60, 15), 0);

You can control whether a text object is drawn using setVisible() and determine its visibility with isVisible.

Aligning text

The lines of text within a label may be centered, or right justified. If text is not centered it may appear that RadialConstraint is not positioning the text at the correct angle. In Figure 24 both text areas are aligned vertically, but without the borders on the components it appears that the lower label is not vertically aligned. Here is the code that produces this layout:

JLabel l1 = new JLabel(
"<html><font color=black><P ALIGN=CENTER>Start Angle <br>= 0\u00B0");
l1.setToolTipText("Start Angle = 0\u00B0");
l1.setBorder(new BevelBorder(BevelBorder.RAISED));
gauge.getGaugeArea().add(l1, new RadialConstraint(gauge, 0.50, 90), 0);

JLabel l2 = new JLabel("<html><font color=black><P>Stop Angle <br>= 360\u00B0");
l2.setToolTipText("Stop Angle = 360\u00B0");
l2.setBorder(new BevelBorder(BevelBorder.RAISED));
gauge.getGaugeArea().add(l2, new RadialConstraint(gauge, 0.50, 270), 0);

Figure 24 :  If text is not centered it may appear to be placed at the wrong angle.

Adding a component

A label (in reality, any JComponent) is an independent rectangular region that can be placed anywhere within the gauge area by specifying the center of the component using either the LinearConstraint or the RadialConstraint class.

3.17.2 Sample Code

The first code snippet shows the addition of a label positioned half way from the center of a gauge to its circumference at an angle of 45°.

RadialConstraint rConstraint = new RadialConstraint(gauge, 0.50, 45)
JLabel label = new JLabel("Start Angle = 0");
label.setToolTipText("Start Angle = 0\u00B0");
gauge.getGaugeArea().add(label, rContstraint, 0);

Usage is the same for a linear constraint. This one puts a label at (0, 0) on a linear scale:

JLabel l0   = new JLabel("<html><font color=black>0");
l0.setToolTipText("0 marks the spot!");
gauge.getGaugeArea().add(l0, new LinearConstraint(gauge, 0.0, 0));

This snippet shows how to label tick marks with a String that specifies the units of the measurement. It uses the JCLabelGenerator interface and its method, makeLabel().

// create a label generator to mark ticks with their units
tick.setLabelGenerator(new JCLabelGenerator() {
public JComponent makeLabel(JCTick tick, double value, RadialConstraint constraint) {
String s = String.valueOf((int) value) + " units";
JLabel label = new JLabel(s);
label.setToolTipText(s);
return label;
}
});


3.18 Events and Listeners in JCGauge

JCGaugePickEvent represents a pick event in JCGauge. A pick event occurs when a JCGaugePickListener is installed on a gauge and the mouse button is pressed over a JCGauge object.

Method

Description

getComponent()

The component associated with this event.

getGauge()

Returns the gauge associated with this event.

getPoint()

Returns the (x, y) point of the click.

getValue()

The value associated with this event. This is the scale value corresponding to the place where the mouse click occurred.

toString()

Returns the point where the mouse was clicked and the associated scale value.

Interface JCGaugePickListener has one method, pick(). It is called on the object that has installed itself as a listener by invoking gauge.addPickListener(). See GaugePickExample.java for an example of the use of a pick listener.


3.19 Utility Functions for JCGauge

Static utility functions are found in com.klg.jclass.swing.gauge.GaugeUtil. They perform conversions or other common functions needed within JCGauge.

3.19.1 GaugeUtil

The following table lists some methods that you might find useful. Consult the API for full details.

GaugeUtil
Method Name

Description

clamp()

If the passed-in value in the first parameter is between the second (min) and third (max) parameters, leave it unchanged. Otherwise return the min or max value, whichever is closer.

drawCircleFor
  Circular
  Scale()

In a circular scale, draws a filled circle based on the supplied scale value, inner extent, and outer extent. Since the method takes a Graphics context as a parameter, you will have to override one of the paint() methods to use it.

drawCircleFor
  Linear
  Scale()

In a linear scale, draws a filled circle based on the supplied scale value, inner extent, and outer extent. Since the method takes a Graphics context as a parameter, you will have to override one of the paint() methods to use it.

drawLinear
  Polygon()

Draws a polygon given a linear scale, inner and outer extent, width, a value on the scale at which to draw, and various other attributes. The type of polygon drawn is a JCPolygon, described in the next section.

normalize
  Angle()

Transforms its (double) argument to an angle between 0° and 360°.

rotate()

Rotates a Polygon by an amount given in degrees by its second argument.

scale()

Scales a Polygon specified in its first argument by independent amounts in the horizontal and vertical directions. The second and third arguments are the X- and Y-scaling ratios.

fromRadians

  toRadians()

 

normalize
  Angle()

Transforms its (double) argument, which should be an angle, to an angle in degrees or in radians.

 

Converts an angle of any size to one in the range 0° - 360°.

translate()

Translate a Polygon by the amount given by X- and Y-parameters, given as integers representing pixels.

valueToAngle()

 

valueTo
  Position()

Converts a double to an angle in degrees. Parameters are value, start_value, stop_value, start_angle, and stop_angle. The returned value is the angle that corresponds to the input value, which is interpreted as a scale value and thus should be between the min and max values for the scale.

 

Example: A circular scale's start_angle is 45° and its start_value is 10. Its stop_angle is 135° and its stop_value is 55°. Given a value of 20, which is between the min and max values for the scale, the function returns 65°, the angular position on the given scale for that value. Note that the input value must be within the range set by the scale.

 

valueToPosition() converts a value on a linear scale to its position in pixels measured from the edge of the component.

3.19.2 JCPolygon

JCPolygon is the abstract super class for JCIndicatorStyle and JCTickStyle. It is a Polygon that retains the dimensions of its bounding box.

GaugeUtil Method Name

Description

getExtrema()

Given a Polygon, returns its bounding Rectangle.


3.20 JCCircularGaugeBean and JCLinearGaugeBean

The two JavaBeans in the gauge package are JCCircularGaugeBean and JCLinearGaugeBean. Their purpose is to make it easy to set gauge properties at design time in an integrated development environment (IDE) tool.

The JCGauge components are designed to be highly configurable. Interfaces support the possibility of replacing indicators, needles, ranges, scales, and ticks with custom-designed components. In the same vein, the concrete objects in JClass Elements based on these interfaces may be subclassed to provide extra functionality. All this flexibility comes at the price of having a gauge's properties distributed throughout the sub objects, making them hard to get at via an IDE's property sheet. To solve this problem, the gauge's JavaBeans provide accessors for the most-needed properties, placing them all within the JavaBean so that they are presented in one table by the IDE.

The property names as they appear in an IDE are listed in Appendix A.

The following figure shows the property sheets for JCCircularGauge and JCCLinearGauge in JBuilder. You see that you can set many needle, scale, and tick properties.

Figure 25 :  The properties tables for JCGaugeBeans in JBuilder.


3.21 Adding Other Components to a Gauge

As an example of adding any JComponent to a gauge, consider a case where the need is to provide a smaller circular gauge within a larger one, such as a stopwatch whose larger scale counts off seconds and whose smaller scale indicates the number of minutes that have elapsed. In the code snippet that follows, bigGauge is the one containing the second hand and smallGauge is the one containing the minute hand. It does not show the details of setting up the properties of the two scales, but once they are configured it is easy to place the smaller gauge within the larger.

JCCircularGauge bigGauge;
JCCircularGauge smallGauge;
bigGauge.addLabel(smallGauge, new RadialConstraint(smallGauge, 0.35, 90), -1);

Figure 26 :  One circular gauge within another.


3.22 JClass 4 to JClass 5: A Mini-porting Guide

The gauge classes have been extensively reorganized for the JClass 5 release, but you should find that there is little or no impact on your existing applications that use circular gauges. You may find that your code compiles against the new classes without the need to change anything; however, if you discover that your application does not run with JClass 5 or newer releases, you can refer to the table below. It should encompass almost all the issues that need attention.

In JClass 4 was:

In JClass 5 becomes:

gauge.getNeedles().firstElement()

(JCCircularNeedle) gauge.getNeedles().firstElement()

gauge.getRanges().firstElement()

(JCCircularRange) gauge.getRanges().firstElement()

gauge.getScale().firstElement()

(JCCircularScale) gauge.getScale().firstElement()

gauge.getTicks().firstElement()

(JCCircularTick) gauge.getTicks().firstElement()

JCCenter(gauge)

JCCenter(circularScale)

JCCircularNeedle(gauge)

JCCircularNeedle(scale)

JCNeedle.InteractionType

JCAbstractNeedle.InteractionType

JCNeedle.setForeground()

JCAbstractNeedle.setForeground()

JCNeedleStyle

JCIndicatorStyle

JCScale.Direction

JCAbstractScale.Direction

1JCCircularGauge uses a start angle and a stop angle to define the angular range, rather than employing Java's notion of a start angle and a sweep angle. For example, a scale that occupies a lower half circle has a start angle of 180° and a stop angle of 360°. Avoid the temptation to specify these two angles as 180° and 180°! See Section 3.10.3, Angles In a Circular Scale, for a discussion on how angles are measured in a JCCircularScale.

2The extent is measured from the scale boundary, not from any border that may enclose the scale.

3The lower edge of a linear scale whose orientation is horizontal, or the right edge of a linear scale whose orientation is vertical. An inner extent of 1.0 is definitely a case for surrounding the scale with a border.

4The two subclasses of GaugeConstraint are LinearConstraint and RadialConstraint.

5As far as direct end user interaction is concerned. Indicators may be repositioned under program control if desired.


PreviousNextIndex