The AttributeSet InterfaceStyled text packages allow the developer to associate attributes with regions of text. Most commonly, a Swing application uses attributes to determine how to render, or represent, a run of text -- that is, a contiguous sequence text that has the same characteristics. You can use attributes to specify certain characteristics that will be applied to a run of text -- for instance, to make a specific region of the text bold. Swing, like some other markup languages, allows attributes to be inherited. You may know that in the CSS markup language, you can specify a paragraph to be red. Subsequently, all runs of text in that paragraph inherit the red attribute unless you explicitly define a different foreground attribute for a given run of text. Swing attributes work in a similar way. The Swing text package manages attributes using the AttributeSet interface. The AttributeSet interface is very similar to Swing's Hashtable interface; that is, it's a collection of key/value pairs. There is one important difference, though; while Hashtable is mutable, AttributeSet is immutable. (Swing also provides a mutable subclass of AttributeSet named MutableAttributeSet, which we will examine later in this article). You can implement inheritance by associating AttributeSets with each other. In Swing, these methods define the AttributeSet interface.
The resolveParent property, a read-only property, is used for inheritance. When an AttributeSet is asked for a particular attribute (via getAttribute()) that it does not have, the request is forwarded to its resolve parent. The MutableAttributeSet InterfaceAs previously mentioned, AttributeSet is immutable. But Swing provides another interface, named MutableAttributeSet, which allows attributes to be modified. The SimpleAttributeSet class provides the default implementation of MutableAttributeSet. In Swing, these methods define MutableAttributeSet : public void addAttribute(Object name, Object value);
public void addAttributes(AttributeSet attributes);
public void removeAttribute(Object name);
public void removeAttributes(Enumeration names);
public void removeAttributes(AttributeSet attributes);
public void setResolveParent(AttributeSet parent);
Swing uses the Element interface to model the content of a text Document. Each Element is associated with a particular AttributeSet that can be returned via the getAttributes() method. There are several ways to modify the attributes of a particular run of text. For instance, you can:
Here is an example that calls setCharacterAttributes() to make the characters in the range 4 through 10 bold in a styled document: SimpleAttributeSet attrs = new SimpleAttributeSet();
StyleConstants.setBold(sas, true);
styledDocument.setCharacterAttributes(4, 6, attrs, false);
The StyleConstants class defines most of the attribute key values that are used throughout Swing. In developing your own application, however, you are not restricted to using the keys defined by the StyleConstants class; you can store whatever you like in your AttributeSets. For example, if you were writing your own View implementation, you might want your View to understand special constants such as blink or dithering. To create such constants, you could define them and then mark up your model with them. StylesIn Swing, the Style interface is an extension of MutableAttributeSet. The Style interface is made up of a mutable set of attributes, plus a name property and a ChangeListener. You can change the attributes that a Style represents by calling its MutableAttributeSet methods. When you do that, any ChangeListeners associated with the Style being used are notified. The StyledDocument interface provides a number of methods for managing Styles. These include getStyle() to look up an existing Style, addStyle() to create a new Style, and removeStyle() to remove an existing Style. Once you have created a Style, you can associate it with a particular region of text by calling setLogicalStyle(). The DefaultStyledDocument interface adds listeners to Styles that are added to the document so that the display is updated as the Style changes. As previously mentioned, each AttributeSet has a resolveParent property. Similarly, each Element has an AttributeSet property. To changs the resolveParent property of the AttributeSet associated with a paragraph Element at a specified location, you can call the setLogicalStyle() method . The following example creates a JTextPane, inserts three paragraphs, assigns a Style to the first two paragraphs, and then modifies the Style: JTextPane textPane = new JTextPane();
textPane.setText("p 1\np 2\np 3");
Style style = textPane.addStyle("Sample Style", null);
textPane.getStyledDocument().setLogicalStyle(0, style);
textPane.getStyledDocument().setLogicalStyle(4, style);
StyleConstants.setBold(style, true);
In this example, the statement setLogicalStyle(0, style) attaches style to the first paragraph (the first paragraph is represented by the region 0-4). Similarly, setLogicalStyle(4, style) attaches style to the second paragraph (the second paragraph is represented by the region 4-8). Because the first two paragraphs are associated with the style Style, which defines the bold attribute to be true, this code sequence causes the first two paragraphs to appear in bold. Continuing with this example, if we wanted the third character not to be bold, we could use the following code: SimpleAttributeSet sas = new SimpleAttributeSet();
StyleConstants.setBold(sas, false);
textPane.getStyledDocument().setCharacterAttributes(2, 1,
sas, false);
Remember that Styles are attached to a paragraph Element's AttributeSet, and that the attributes of the Style show through to the character Element's attributes (assuming that neither the character Element nor the paragraph Element's AttributeSet contains the attribute). In the preceding example, the character Element's AttributeSet at the third character defines the bold attribute, in effect shadowing the bold attribute defined in style, so that the third character appears to be regular, not bold. Now let's say we wanted to make the third character in this example appear once again in the manner defined by the style variable. To make this change, we would have to remove the bold attribute that is defined in the character Element's AttributeSet. We could do this by calling the setCharacterAttributes() method, as shown in the following code sequence: SimpleAttributeSet sas = new SimpleAttributeSet();
textPane.getStyledDocument().setCharacterAttributes
(2, 1, sas, true);
In this example, the value true is passed to the setCharacterAttributes() method to indicate that the current attributes should be replaced by new attributes. At this point, the character Element's AttributeSet does not define any attributes, so the attributes defined in the style show through. AttributeContext and StyleContextMost styled documents use a small set of unique AttributeSets to perform such specialized tasks as defining bold and italic regions of text, or defining italic regions of text, or defining colored regions of text. As a document gets bigger, reusing common AttributeSets becomes more critical. If each Element used in an application stored its own copy of each AttributeSet, the app would incur a substantial cost without deriving any benefit. For this reason, the AbstractDocument defines an interface named AttributeContext, which can be used to share AttributeSets. In Swing, these methods define AttributeContext:
As you may notice, these methods mirror the methods that the MutableAttributeSet interface provides for mutating an AttributeSet. You can use AttributeContext as an entry point for AttributeSet mutation. AttributeContext in turn tries to limit the number of unique AttributeSets vended. The StyleContext class provides the default implementation of AbstractDocument.AttributeContext. StyleContext keeps a cache of all unique AttributeSets with fewer than nine attributes. (The number nine is not magical; you can use a different number by subclassing and overriding the getCompressionThreshold() method). For AttributeSets with more than nine members, Swing creates a new MutableAttributeSet. The following code creates a StyleContext and calls addAttribute() twice. If the two AttributeSets used in the example are the same (= =), Swing prints a message to standard ouput:
In most cases, you'll never have to concern yourself with what's shown in the above example. AbstractDocument handles it for you. When you pass in an AttributeSet to methods such as setCharacterAttributes() or insertString(), the AttributeSet is uniqued for you, using the above, by AbstractDocument. StyleContext is also responsible for creating Styles and notifying ChangeListeners when the a Style changes. Elements and AttributeSets in AbstractDocumentsThe AbstractDocument class provides the default abstract implementation of the Document interface. All Document subclasses in the Swing text package directly or indirectly subclass from the AbstractDocument class. AbstractDocument also provides the default implementation of Element that all subclasses of AbstractDocument use. This implementation, named AbstractElement, is an inner class of AbstractDocument. AbstractElement not only implements Element, but also implements MutableAttributeSet. AbstractElement implements the AttributeSet methods by forwarding to an instance variable of type AttributeSet. The two AttributeSet methods getResolveParent() and getAttribute() are forwarded to the AttributeSet instance variable as well, null is returned, the method is forwarded on to the Element's parent. These methods are implemented in this way to allow the attributes of parent Elements to show through to children Elements. For example, if a paragraph Element has a bold attribute, any children Elements will pick up the bold attribute, assuming they do not define it locally. Each instance of AbstractDocument is associated with an AttributeContext. The AttributeContext is set in the constructor of AbstractDocument. AbstractDocument also provides a protected method namedgetAttributeContext() for accessing the AttributeContext. As previously mentioned, AbstractElement implements MutableAttributeSet. The MutableAttributeSet methods are forwarded to the equivalent AttributeContext method to obtain a new AttributeSet. The AttributeSet returned from the AttributeContext methods is the AttributeSet that AbstractElements will delegate to. In this way, AttributeContext provides a way for different AttributeSets to be shared by multiple Elements, and potentially across Documents.
| |||||||||||||
|
| ||||||||||||