21.2 Highlighters


Highlighters determine how text is marked to make it stand out. The order in which we discuss the highlighter interfaces may seem counterintuitive. The basic Highlighter interface is so straightforward that you'll rarely need to work with it directly, so we will describe it later. At this point, we discuss the interface you're most likely to use first: the Highlighter.HighlightPainter interface.

21.2.1 The Highlighter.HighlightPainter Interface

This is an inner interface of the Highlighter interface. If you want to change the way that highlights are drawn in your text component, this is the interface you'd implement.

Implementations of Highlighter.HighlightPainter are returned by Caret implementations and passed to Highlighter implementations (described later in this section; there are a lot of interfaces working together), which use them to decorate the area "behind" a selection. The only concrete implementation that's provided in Swing is DefaultHighlighter.DefaultHighlightPainter, which paints highlights as a solid background rectangle of a specified color.

This interface consists of a single paint( ) method. Unlike the paint( ) method of Caret, this method is called before the text itself is rendered, so there's no need to worry about obscuring text or XOR mode.

21.2.1.1 Method
public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c)

Render a highlighter behind the text of the specified component. The p0 and p1 parameters specify offsets into the document model defining the range to be highlighted. The bounds parameter defines the bounds of the specified component.

21.2.2 A Custom HighlightPainter

Here's a sample implementation of the Highlighter.HighlightPainter interface that paints highlights as thick underlines instead of as the usual solid rectangle. To use this highlight painter, we need to set a Caret that returns an instance of our highlight painter in its getSelectionPainter( ) method. The main( ) method in this example (provided for demonstration purposes only since the highlight painter would be complete without it) shows one way of doing this.

// LineHighlightPainter.java // An implementation of HighlightPainter that underlines text with a thick line import javax.swing.*; import javax.swing.text.*; import java.awt.*; public class LineHighlightPainter implements Highlighter.HighlightPainter {   // Paint a thick line under one line of text, from r extending rightward to x2.   private void paintLine(Graphics g, Rectangle r, int x2) {     int ytop = r.y + r.height - 3;     g.fillRect(r.x, ytop, x2 - r.x, 3);   }   // Paint thick lines under a block of text.   public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) {     Rectangle r0 = null, r1 = null, rbounds = bounds.getBounds( );     int xmax = rbounds.x + rbounds.width; // x-coordinate of right edge     try {  // Convert positions to pixel coordinates.       r0 = c.modelToView(p0);       r1 = c.modelToView(p1);     } catch (BadLocationException ex) { return; }     if ((r0 == null) || (r1 == null)) return;     g.setColor( c.getSelectionColor( ) );     // Special case if p0 and p1 are on the same line     if (r0.y == r1.y) {       paintLine(g, r0, r1.x);       return;     }     // First line, from p1 to end-of-line     paintLine(g, r0, xmax);     // All the full lines in between, if any (assumes that all lines have     // the same height--not a good assumption with JEditorPane/JTextPane)     r0.y += r0.height;   // Move r0 to next line.     r0.x = rbounds.x;    // Move r0 to left edge.     while (r0.y < r1.y) {       paintLine(g, r0, xmax);       r0.y += r0.height; // Move r0 to next line.     }     // Last line, from beginning-of-line to p1     paintLine(g, r0, r1.x);   }   public static void main(String args[]) {     // Extend DefaultCaret as an anonymous inner class.     Caret lineHighlightPainterCaret = new DefaultCaret( ) {       private Highlighter.HighlightPainter lhp = new LineHighlightPainter( );       // Override getSelectionPainter to return the LineHighlightPainter.       protected Highlighter.HighlightPainter getSelectionPainter( ) {         return lhp;       }     };     JFrame frame = new JFrame("LineHighlightPainter demo");     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     JTextArea area = new JTextArea(9, 45);     area.setCaret(lineHighlightPainterCaret);     area.setLineWrap(true);     area.setWrapStyleWord(true);     area.setText("This is the story\nof the hare who\nlost his spectacles.");     frame.getContentPane( ).add(new JScrollPane(area), BorderLayout.CENTER);     frame.pack( );     frame.setVisible(true);   } }

All we've done here is override the paint( ) method to paint thin (three-pixel) rectangles under each line of text in the highlighted region. For this example, we've assumed that each line of text has the same height. This is fine for JTextField and JTextArea, but if you want to customize the highlighting of more complex text components, you need to take the different fonts into account. Figure 21-3 shows the LineHighlightPainter in action.

Figure 21-3. The LineHighlightPainter
figs/swng2.2103.gif

21.2.3 The Highlighter.Highlight Interface

The second inner interface of Highlighter is the Highlighter.Highlight interface. It is used by Highlighter to represent a single range of text to be decorated. The only implementation is a package-private inner class of DefaultHighlighter.

21.2.3.1 Properties

Table 21-4 shows the properties defined by the Highlighter.Highlight interface. The startOffset and endOffset properties reflect the range of a given highlighted area as offsets into the document model. The other property, painter, is responsible for rendering the Highlight. The only methods in this interface are the accessors for the three properties.

Table 21-4. Highlighter.Highlight properties

Property

Data type

get

is

set

Default value

endOffset

int

·

     

painter

Highlighter.HighlightPainter

·

     

startOffset

int

·

     

21.2.4 The Highlighter Interface

The Highlighter interface is responsible for marking background areas of a text component to "highlight" selected portions of the text. Highlighters can be used not only to highlight the current text selection but also for other purposes. For example, you could choose to highlight all the misspelled words in the document.

Highlighter defines two inner interfaces (described above) to manage its highlights. Highlighter.Highlight keeps track of a single highlighted area while Highlighter.HighlightPainter is responsible for painting a highlighted area. Refer to Figure 21-1 to see how the various classes and interfaces are related.

21.2.4.1 Property

Table 21-5 shows the property defined by the Highlighter interface. The single property, highlights, is an array of individual areas to be highlighted.

Table 21-5. Highlighter property

Property

Data type

get

is

set

Default value

highlights

Highlighter.Highlight[]

·

     

21.2.4.2 Methods
public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter p) throws BadLocationException

Add a new highlight covering the specified range (from document offset p0 to offset p1) using the specified Highlighter.HighlightPainter (see above) to perform the rendering. If you don't want to create your own HighlightPainter, you may pass in DefaultHighlighter.DefaultPainter (a public static field that DefaultHighlighter provides for this purpose). The return value is a "tag" object that can be passed to changeHighlight( ) and removeHighlight( ). (Implementations of this interface should document the specific type of the object this method returns.)

public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException

Take an existing highlight (tag) and change it to refer to a different portion of the document. The tag should be either an object returned by addHighlight( ) or one of the elements returned by getHighlights( ).

public void install(JTextComponent c)

Called when a UI is installed on a text component. This provides access to the component, its UI delegate, and its Document model.

public void deinstall(JTextComponent c)

Called when the UI is removed from a text component. Any references stored in the install( ) method should be dropped here, and any listeners unregistered.

public void paint(Graphics g)

Render all the highlights.

public void removeAllHighlights( )

Remove all of the Highlighter's highlights.

public void removeHighlight(Object tag)

Remove a single highlight. The tag should be either an object returned by addHighlight( ) or one of the elements returned by getHighlights( ).

21.2.5 Adding Multiple Highlights

Here's an example of a program that adds multiple highlights, one for each vowel. The results of running it are shown in Figure 21-4.

// MultiHighlight.java // import javax.swing.*; import javax.swing.text.*; import java.awt.event.*; import java.awt.BorderLayout; public class MultiHighlight implements ActionListener {   private JTextComponent comp;   private String charsToHighlight;   public MultiHighlight(JTextComponent c, String chars) {     comp = c;     charsToHighlight = chars;   }   public void actionPerformed(ActionEvent e) {     // Highlight all characters that appear in charsToHighlight.     Highlighter h = comp.getHighlighter( );     h.removeAllHighlights( );     String text = comp.getText( );     for (int j=0; j < text.length( ); j+=1) {       char ch = text.charAt(j);       if (charsToHighlight.indexOf(ch) >= 0) try {         h.addHighlight(j, j+1, DefaultHighlighter.DefaultPainter);       } catch (BadLocationException ble) { }     }   }   public static void main(String args[]) {     JFrame frame = new JFrame("MultiHighlight");     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     JTextArea area = new JTextArea(5, 20);     area.setText("This is the story\nof the hare who\nlost his spectacles.");     frame.getContentPane( ).add(new JScrollPane(area), BorderLayout.CENTER);     JButton b = new JButton("Highlight All Vowels");     b.addActionListener(new MultiHighlight(area, "aeiouAEIOU"));     frame.getContentPane( ).add(b, BorderLayout.SOUTH);     frame.pack( );     frame.setVisible(true);    } }
Figure 21-4. Multiple highlights
figs/swng2.2104.gif

21.2.6 The LayeredHighlighter Class

LayeredHighlighter is an abstract class that implements the Highlighter interface. It doesn't provide an implementation for any of the Highlighter methods (for that, see DefaultHighlighter in the next section) but declares one abstract method used by View objects.

21.2.6.1 Method
public abstract void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view)

Leaf views call this method to render any layered highlights that have overlapping offsets.

21.2.7 The DefaultHighlighter Class

The DefaultHighlighter class provides a useful implementation of the Highlighter interface. (It extends LayeredHighlighter.)

21.2.7.1 Properties

DefaultHighlighter adds one new property to the one it inherits. Table 21-6 shows its two properties.

Table 21-6. DefaultHighlighter properties

Property

Data type

get

is

set

Default value

highlightso

Highlighter.Highlight[]

·

   

Empty array

drawsLayeredHighlights

boolean

·

 

·

true

ooverridden

See also the properties of Highlighter (Table 21-5).

The drawsLayeredHighlights property changes the behavior of the addHighlight( ) method. If the Highlighter.HighlightPainter object passed into addHighlight( ) is an instance of LayeredHighlighter.LayerPainter, DefaultHighlighter takes special advantage of it only if the value of this property is true.

21.2.7.2 Static field

DefaultHighlighter provides a default implementation of the Highlighter.HighlightPainter interface that can be passed to the addHighlight( ) method. (Its declared type is LayeredHighlighter.LayerPainter, a public abstract class that implements HighlightPainter.)

public static final LayeredHighlighter.LayerPainter DefaultPainter

This highlighter renders a solid-color rectangular highlight. It uses the color specified by the component's selectionColor property.

21.2.7.3 Constructor
public DefaultHighlighter( )

Create a new DefaultHighlighter.

21.2.7.4 Methods

The following methods implement the Highlighter interface:

public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter p) throws BadLocationException

Add a new highlight using the createPosition( ) method on the component's Document to track the specified beginning and end, even as changes are made to it. It returns an instance of a package-private inner class implementing High-lighter.Highlight.

public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException

Clean up the area previously highlighted by the given highlight and reset it. tag should be a Highlight returned from either addHighlight( ) or getHighlights( ).

public void deinstall(JTextComponent c)

Called when the UI is removed from a text component. It drops the reference to the component supplied by install( ).

public void install(JTextComponent c)

Called when a UI is installed on a text component. It clears any existing highlights and stores the given component for use in other methods.

public void paint(Graphics g)

Call paint( ) on the HighlightPainter defined for each Highlight.

public void removeAllHighlights( )

Remove all of the Highlighter's highlights and clean up the areas they covered.

public void removeHighlight(Object tag)

Remove the given highlight and clean up the area it covered. tag should be a Highlight returned from either addHighlight( ) or getHighlights( ).

There's also one method that's not part of the Highlighter interface:

public void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view)

Render any layered highlights that have overlapping offsets.

21.2.8 The DefaultHighlighter.DefaultHighlightPainter Class

An instance of this inner class is returned by DefaultCaret's getSelectionPainter( ) method. It paints highlights as a solid background rectangle of a specified color.

You might want to instantiate one of these if you want to set your own color for a highlight. If you want to use the color specified by the component's selectionColor property, you can avoid a redundant object creation by using the instance made available to you through DefaultHighlighter's DefaultPainter field.

21.2.8.1 Property

This inner class defines the property shown in Table 21-7. The color property defines the color used to draw highlights. It can be set only in the constructor.

Table 21-7. DefaultHighlighter.DefaultHighlightPainter property

Property

Data type

get

is

set

Default value

color

Color

·

   

From constructor

21.2.8.2 Constructor
public DefaultHighlightPainter(Color c)

Create a new painter that uses the specified color. If the color is null, the highlights are drawn with the component's selectionColor.

21.2.8.3 Methods
public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c)

Determine the pixel locations of the given endpoints and draw a rectangle to highlight the specified region. If the two offsets are on different lines, three rectangles are drawn: one from the start point to the end of that line, another that highlights any full lines that follow, and a third from the start of the next line up to the last offset.

public void paintLayer(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c, View view)

Render just the part of the highlight that corresponds to the specified view.



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net