I l@ve RuBoard |
![]() ![]() |
21.2 HighlightersHighlighters 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 InterfaceThis 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
21.2.2 A Custom HighlightPainterHere'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![]() 21.2.3 The Highlighter.Highlight InterfaceThe 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 PropertiesTable 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.
21.2.4 The Highlighter InterfaceThe 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 PropertyTable 21-5 shows the property defined by the Highlighter interface. The single property, highlights, is an array of individual areas to be highlighted.
21.2.4.2 Methods
21.2.5 Adding Multiple HighlightsHere'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![]() 21.2.6 The LayeredHighlighter ClassLayeredHighlighter 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
21.2.7 The DefaultHighlighter ClassThe DefaultHighlighter class provides a useful implementation of the Highlighter interface. (It extends LayeredHighlighter.) 21.2.7.1 PropertiesDefaultHighlighter adds one new property to the one it inherits. Table 21-6 shows its two properties.
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 fieldDefaultHighlighter 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.)
21.2.7.3 Constructor
21.2.7.4 MethodsThe following methods implement the Highlighter interface:
There's also one method that's not part of the Highlighter interface:
21.2.8 The DefaultHighlighter.DefaultHighlightPainter ClassAn 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 PropertyThis 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.
21.2.8.2 Constructor
21.2.8.3 Methods
|
I l@ve RuBoard |
![]() ![]() |