Return-Path: <env_210986391357016213@hermes.sun.com>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id VAA14860; Thu, 22 Aug 2002 21:48:07 -0400 (EDT)
Received: from hermes.sun.com (hermes.sun.com [64.124.140.169])
	by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id VAA28508
	for <alexp@mit.edu>; Thu, 22 Aug 2002 21:48:06 -0400 (EDT)
Date: 22 Aug 2002 15:45:09 -0800
From: "JDC Tech Tips" <body_210986391357016213@hermes.sun.com>
To: alexp@mit.edu
Message-Id: <210986391357016213@hermes.sun.com>
Subject: Correction to Core Java Technologies Tech Tips, August 21, 2002 
Mime-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: SunMail 1.0

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>
Technical Tips
</TITLE>
</HEAD>

<body bgcolor="#ffffff">
<a name="top"></a>
<table border="0" cellpadding="0" cellspacing="0" width="640">
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>

<tr>
<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>

<td>
<table border="0" cellpadding="0" cellspacing="0" width="640">
<tr>
<td colspan="2">
<img src="http://developer.java.sun.com/images/core_java_ttips_header.gif" width="640" alt="" border="0"></td>
</tr>

<tr>
<td colspan="2" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>

<!-- ================== -->
<!-- Start Main Content -->
<!-- ================== -->

<tr bgcolor="#59588d">
<td height="20">&nbsp;&nbsp;&nbsp;<a href="http://developer.java.sun.com/developer/TechTips/txtarchive/2002/Aug02_JohnZ.txt?s=06&w=34" style="text-decoration:none;"><font face="verdana" size="2" color="ffffff">View this issue as simple text</font></a></td>
<td align="right" height="20"><font face="verdana" size="2" color="ffffff"><b>August 21, 2002</b></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
</tr>
<tr>
<td colspan="2" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>

<tr><td colspan="2">

<table border="0" cellpadding="10" cellspacing="0" width="640">
<tr><td>

<FORM METHOD="GET" ACTION="http://search.java.sun.com/search/java/">
<table BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%">
<tr>
<td>
        
<table BORDER="0" CELLPADDING="0" CELLSPACING="0">
<TR> 
<td  align="left" VALIGN="middle"><img src="http://developer.java.sun.com/images/issue.gif" border="0" alt=""></td>
              
<td VALIGN="middle" align="right" WIDTH="100%">
<FONT SIZE="2">
<INPUT TYPE="text" SIZE="15" MAXLENGTH="128" NAME=qt></FONT></td>
            
<td VALIGN="middle" WIDTH="55" align="right">
<INPUT TYPE="image" SRC="http://developer.java.sun.com/images/search.button.gif" ALT="Search" value="search" BORDER="0" WIDTH="55"></td>
</tr>
</table>
</td></tr>
</table>
</FORM>

<p>
<font face="verdana" size="2" color="#000000">This is a corrected version of the Core Java Technologies Tech Tips, August 21, 2002.
The code examples in the earlier version for the tip
<a href="#1">Maintaining a Priority Queue</a> incorrectly reversed the &gt; and &lt; signs.</font>
</p>

<p>
<a href="#1"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt=""><font face="verdana" size="2" color="#666699">Maintaining a Priority Queue</font></a>
<br>    
<a href="#2"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt=""><font face="verdana" size="2" color="#666699">Displaying Text in Multiple Styles</font></a>
</p>

<p>
<font face="verdana" size="2" color="#000000">These tips were developed using java<font size="-2"><sup>TM</sup></font> 2 SDK, Standard Edition, v 1.4.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of <a href="http://www.jzventures.com"><font face="verdana" size="2" color="#666699">JZ Ventures, Inc</font></a>.</font>
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="1"></a>
<p>
<font face="verdana" size="3"><b>Maintaining a Priority Queue</b></font>
</p>


<p>
<font face="verdana" size="2" color="#000000">
Have you ever had the need to maintain a collection of items where the order in which the items are processed is controlled by some factor such as importance, future time, or how much money someone gave you to do a job?  While the classes of the <code>Collection</code> Framework support the standard first-in-first-out (FIFO) operations of a queue, they don't have built-in support for prioritization, that is, where an item having a higher priority is processed before an item of lower priority.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
How then can you manage priorities in a collection? For the simple case where the number of priorities is fixed (and small in quantity), you can manage the priorities of the items using an array. The index into the array represents an item's priority. It's possible that multiple items in the array have the same priority. In this case, it would be necessary to maintain items with identical priorities in their own data structure, either in a <code>Set</code> or a <code>LinkedList</code>, depending upon whether you want to maintain the order of the items entered into the queue.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
For the more complicated case, where the number of priorities is large, it is common to replace the priorities array with a linked list for the set of priorities. Here you still keep a separate collection for the items sharing a priority.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
To find the &quot;next&quot; element to process, or one of the items with the highest priority, you just look at the index for the highest priority. Then you work your way down until you find an associated collection that isn't empty. In the more complicated case with more priorities, finding the highest priority item is actually easier. That's because the front of the linked list will have the set of highest priority items associated with it, from which you get to pick one.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Let's create a priority queue. The <code>Collections</code> Framework provides the basics for a priority queue. However, it is still necessarily to do the bulk of the work necessary to create a custom implementation.
</font>
</p>


<p><font face="verdana" size="2" color="#000000">
First let's examine how to add entries to a priority queue, and how to remove elements.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
You might think that you could use the basic <code>add()</code> method of <code>Collection</code> to add entries to the queue, but that won't work because it doesn't support specifying a priority. There is a second version of <code>add()</code> that accepts an integer argument, however this integer is meant to serve the role of an index into the list, not a priority. In order to avoid the confusion of providing yet another <code>add()</code> method that just swaps the argument order, let's add an <code>insert()</code> method for adding an object with a priority:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
public void insert(Object element, int priority)
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Let's also provide two methods to fetch elements out of the queue: a destructive version and a nondestructive version. The destructive version gets an item from the internal collection with the highest priority and removes it from the queue. The nondestructive version only gets the item.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
public Object removeFirst()
public Object getFirst()
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Because a queue is typically implemented as a <code>LinkedList</code>, the rest of the definition is that of a <code>java.util.List</code>. Instead of implementing the interface directly, though, it's less work to extend <code>AbstractList</code>.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
The start of the class for the priority queue simply gives the class a name and says it extends from <code>AbstractList</code>. <code>Collection</code> implementations should be serializable, so the class implements that interface, too.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  import java.util.*;
  import java.io.Serializable;

  public class PriorityQueue
    extends AbstractList
      implements Serializable {
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Next, you need to decide on a data structure. Let's assume the simpler case, and maintain the elements for each priority in a <code>List</code>. So make an array declaration like this:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  private List queue[];
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Next are the constructors. <code>Collection</code> implementations must support at least two constructors, one with no arguments and another that accepts a <code>Collection</code> as its argument. Two more constructors need to be added. These constructors include an argument for the number of priorities to support:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  private final static int DEFAULT_PRIORITY_COUNT = 10;

  public PriorityQueue() {
    this(DEFAULT_PRIORITY_COUNT);
  }

  public PriorityQueue(Collection col) {
    this(col, DEFAULT_PRIORITY_COUNT);
  }

  public PriorityQueue(int count) {
    this(null, count);
  }

  public PriorityQueue(Collection col, int count) {
    if (count &lt;= 0) {
      throw new IllegalArgumentException(
        &quot;Illegal priority count: &quot;+ count);
    }
    queue = new List[count];
    if (col != null) {
      addAll(col);
    }
  }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
To get the size of the collection, the <code>PriorityQueue</code> sums up the elements at each position in the array:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  public int size() {
    int size = 0;
    for (int i=0, n=queue.length; i&lt;n; i++) {
      if (queue[i] != null) {
        size += queue[i].size();
      }
    }
    return size;
  } 
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The <code>PriorityQueue</code> has two mechanisms to add elements: <code>add</code> and <code>insert</code>. Because the <code>add</code> method from the <code>List</code> interface only accepts an <code>Object</code> parameter, you need to use a default priority for those adds. For <code>inserts</code>, you specify a priority, then you add the element to the <code>List</code> at the proper position in the internal data structure.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  private final static int DEFAULT_PRIORITY = 0;

  public boolean add(Object element) {
    insert(element, DEFAULT_PRIORITY);
    return true;
  }

  public void insert(Object element, int priority) {
    if (priority &lt; 0) {
      throw new IllegalArgumentException(
        &quot;Illegal priority: &quot; + priority);
    }
    if (queue[priority] == null) {
      queue[priority] = new LinkedList();
    }
    queue[priority].add(element);
    modCount++;
  }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The <code>modCount</code> variable is inherited from <code>AbstractList</code> (more about this variable later).</font>
</p>

<p><font face="verdana" size="2" color="#000000">
The fetching operations are next: <code>getFirst</code> and <code>get</code>. The <code>getFirst</code> method returns the highest priority element. The <code>get</code> method returns the element at a specific index. Any <code>Collection</code> implementation needs an <code>iterator()</code>, so you can rely on its existence to simplify the fetching methods. For <code>getFirst</code>, just return the first element of the iterator. For <code>get</code> you need to count.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  public Object getFirst() {
    return iterator().next();
  }

  public Object get(int index) {
    if (index &lt; 0) {
      throw new IllegalArgumentException(
        &quot;Illegal index: &quot;+ index);
    }
    Iterator iter = iterator();
    int pos = 0;
    while (iter.hasNext()) {
      if (pos == index) {
        return iter.next();
      } else 
        {
        pos++;
      }
    }
    return null;
  }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Removal works in a similar way to fetching, in that it relies on the iterator where possible. There are two removal methods to implement: <code>clear</code> and <code>removeFirst</code>. With <code>clear</code>, you need to clear the elements for each priority in the internal array. With <code>removeFirst</code>, you remove and return the first element of the iterator, the highest priority item.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  public void clear() {
    for (int i=0, n=queue.length; i&lt;n; i++) {
      queue[i].clear();
    }
  }

  public Object removeFirst() {
    Iterator iter = iterator();
    Object obj = iter.next();
    iter.remove();
    return obj;
  } 
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The bulk of the code is the iterator, which is shown below with the full class definition. The purpose of an Iterator is to visit each item in the <code>Collection</code>. For the <code>PriorityQueue</code> iterator, it must not only visit each item, but visit each item in priority order. The way this iterator does its work is by starting with the iterator for the highest priority list, and visiting all of those items. When the end of that iterator is hit, the iterator for the next priority item comes into play, and so on until no more priorities (and their associated iterator) is available.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
The previously mentioned <code>modCount</code> variable is used to check for modifications within the queue while any iterator is being traversed. This iterator also supports the removal of elements from the queue. This support is an implementation of the optional remove method and it is utilized by the <code>removeFirst</code> method. The remainder of the <code>List</code> interface methods are inherited from <code>AbstractList</code>.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Here is the code for the priority queue:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  import java.io.Serializable;
  import java.util.*;

  public class PriorityQueue
    extends AbstractList
      implements Serializable {

    private final static int DEFAULT_PRIORITY_COUNT = 10;
    private final static int DEFAULT_PRIORITY = 0;

    private List queue[];

    public PriorityQueue() {
      this(DEFAULT_PRIORITY_COUNT);
    }

    public PriorityQueue(Collection col) {
      this(col, DEFAULT_PRIORITY_COUNT);
    }

    public PriorityQueue(int count) {
      this(null, count);
    }

    public PriorityQueue(Collection col, int count) {
      if (count &lt;= 0) {
        throw new IllegalArgumentException(
          &quot;Illegal priority count: &quot;+ count);
      }
      queue = new List[count];
      if (col != null) {
        addAll(col);
      }
    }

    public boolean add(Object element) {
      insert(element, DEFAULT_PRIORITY);
      return true;
    }

    public void insert(Object element, int priority) {
      if (priority &lt; 0) {
        throw new IllegalArgumentException(
          &quot;Illegal priority: &quot; + priority);
      }
      if (queue[priority] == null) {
        queue[priority] = new LinkedList();
      }
      queue[priority].add(element);
      modCount++;
    }

    public Object getFirst() {
      return iterator().next();
    }

    public Object get(int index) {
      if (index &lt; 0) {
        throw new IllegalArgumentException(
          &quot;Illegal index: &quot;+ index);
      }
      Iterator iter = iterator();
      int pos = 0;
      while (iter.hasNext()) {
        if (pos == index) {
          return iter.next();
        } else {
          pos++;
        }
      }
      return null;
    }

    public void clear() {
      for (int i=0, n=queue.length; i&gt;n; i++) {
        queue[i].clear();
       }
    }

    public Object removeFirst() {
      Iterator iter = iterator();
      Object obj = iter.next();
      iter.remove();
      return obj;
    }

    public int size() {
      int size = 0;
      for (int i=0, n=queue.length; i&lt;n; i++) {
        if (queue[i] != null) {
          size += queue[i].size();
        }
      }
      return size;
    }
  
    public Iterator iterator() {
      Iterator iter = new Iterator() {
        int expectedModCount = modCount;
        int priority = queue.length - 1;
        int count = 0;
        int size = size();

        // Used to prevent successive remove() calls
        int lastRet = -1;

        Iterator tempIter;

        // Get iterator for highest priority
        {
          if (queue[priority] == null) {
            tempIter = null;
          } else {
            tempIter = queue[priority].iterator();
          }
        }
   
        private final void checkForComodification() {
          if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
          }
        }

        public boolean hasNext() {
          return count != size();
        }

        public Object next() {
          while (true) {
            if ((tempIter != null) &amp;&amp; (
                                 tempIter.hasNext())) {
              Object next = tempIter.next();
              checkForComodification();
              lastRet = count++;
              return next;
            } else {
              // Get next iterator
              if (--priority &lt; 0) {
                checkForComodification();
                throw new NoSuchElementException();
              } else {
                if (queue[priority] == null) {
                  tempIter = null;
                } else {
                  tempIter = queue[priority].iterator();
                }
              }
            }
          }
        }

        public void remove() {
          if (lastRet == -1) {
            throw new IllegalStateException();
          }
          checkForComodification();

          tempIter.remove();
          count--;
          lastRet = -1;
          expectedModCount = modCount;
        }
      };
      return iter;
    }

    public String toString() {
      StringBuffer buffer = new StringBuffer(&quot;{&quot;);
      for (int n=queue.length-1, i=n; i&gt;=0; --i) {
        if (i != n) {
          buffer.append(&quot;,&quot;);
         }
        buffer.append(i + &quot;:&quot;);
        if ((queue[i] != null) &amp;&amp; (
                               queue[i].size() &gt; 0)) {
          buffer.append(queue[i].toString());
        }
       }
       buffer.append(&quot;}&quot;);
       return buffer.toString();
     }
  }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The following program tests the priority queue and some of its capabilities. First, the test program creates a <code>PriorityQueue</code> object from elements passed in the command line. Then, the program creates an empty queue and tries to remove an element, receiving an expected exception. Finally, the program fills the queue with some names, and then removes each element in priority order.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  import java.util.*;

  public class TestPriorityQueue {
    public static void main (String args[]) {
      List list = Arrays.asList(args);
      PriorityQueue queue = new PriorityQueue(list);
      System.out.println(queue);
      queue = new PriorityQueue(10);
      try {
        System.out.println(queue.removeFirst());
      } catch (NoSuchElementException e) {
        System.out.println(
                        &quot;Received expected exception&quot;);
      }
      queue.insert(&quot;Joy&quot;, 8);
      queue.insert(&quot;Scott&quot;, 9);
      queue.insert(&quot;Sueltz&quot;, 5);
      queue.insert(&quot;Bill&quot;, 8);
      queue.insert(&quot;McNealy&quot;, 9);
      queue.insert(&quot;Patricia&quot;, 5);
      queue.insert(&quot;C.&quot;, 5);
      queue.insert(&quot;Papadopoulos&quot;, 4);
      queue.insert(&quot;Greg&quot;, 4);
      System.out.println(queue);
      queue.addAll(list);
      System.out.println(queue);
      while (queue.size() != 0) {
        System.out.println(queue.removeFirst());
      }
    }
  }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Run the test program as follows from the command line:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  java TestPriorityQueue one two three four
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
You should see the following output:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  {9:,8:,7:,6:,5:,4:,3:,2:,1:,0:[one, two, three, four]}
  Received expected Exception
  {9:[Scott, McNealy],8:[Joy, Bill],7:,6:,
    5:[Sueltz, Patricia, C.],4:[Papadopoulos, 
      Greg],3:,2:,1:,0:}
  {9:[Scott, McNealy],8:[Joy, Bill],7:,6:,
    5:[Sueltz, Patricia, C.],4:[Papadopoulos, 
      Greg],3:,2:,1:, 0:[one, two, three, four]}
  Scott
  McNealy
  Joy
  Bill
  Sueltz
  Patricia
  C.
  Papadopoulos
  Greg
  one
  two
  three
  four
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">  
For more information about creating a priority queue, see 
Chapter 9, &quot;Lists&quot;, in &quot;<a href="http://developer.java.sun.com/developer/Books/javaprogramming/JavaCollections/?s=06&w=34"><font face="verdana" size="2" color="#666699">Java Collections</font></a>&quot; by John Zukowski.</font>
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="right">
<a href="#top"><font face="verdana" size="2" color="#666699">back to top</font><img src="http://developer.java.sun.com/images/back_to_top.gif" border="0" alt=""></a>
</div>
</td></tr>

<tr><td bgcolor="#ffffff" height="2"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td></tr>

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="2"></a>
<p>
<font face="verdana" size="3"><b>Displaying Text In Multiple Styles</b></font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
A commonly asked question is how to display text in multiple colors or styles within a <code>JTextArea</code> component. The short answer is: you can't. Both the <code>JTextField</code> and <code>JTextArea</code> components are designed to display text in a single style, color, font. When you change the characteristics of the text, you are changing all text in the component. You can't change the characteristics of only the selected text, or just the piece you want changed.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Just because the <code>JTextArea</code> component can't display its content in multiple colors or styles, doesn't mean there isn't support for displaying text in multiple styles. It just isn't done with the <code>JTextArea</code>. You need to use the <code>JTextPane</code>. Knowing that it is the <code>JTextPane</code> and not the <code>JTextArea</code> will lead you to the actual &quot;how&quot; answer to the original question.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Within the <code>JTextPane</code>, text that you add to the component is 
associated with an <code>AttributeSet</code>. The <code>AttributeSet</code> contains a set of key-value pairs for the various display attributes of the text. These pairs can answer questions like &quot;what's the current font?&quot;, &quot;what's the background color?&quot;, and &quot;with what alignment should I display the current paragraph?&quot; By setting this <code>AttributeSet</code> before adding the text, you can change the way the added text is displayed. You can also change the <code>AttributeSet</code> for the currently selected text.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
<code>AttributeSet</code> is an interface in the <code>javax.swing.text</code> package. To fill the set with the desired characteristics, you need to work with an implementation of that interface. That implementation is most likely <code>SimpleAttributeSet</code>, though it can also be <code>StyleContext.SmallAttributeSet</code> or <code>StyleContext.NamedStyle</code>.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
SimpleAttributeSet set = new SimpleAttributeSet();
</pre>
</font>

<p>
<font face="verdana" size="2" color="#000000">
After you create the set, you set the attributes, but this involves a little complexity. The possible settings for the different styles are found in the inner classes of the <code>StyleConstants</code> class:</font>
</p>

<ul>
  <li><font face="verdana" size="2" color="#000000"><code>CharacterConstants</code></font></li>
  <li><font face="verdana" size="2" color="#000000"><code>ColorConstants</code></font></li>
  <li><font face="verdana" size="2" color="#000000"><code>FontConstants</code></font></li>
  <li><font face="verdana" size="2" color="#000000"><code>ParagraphConstants</code></font></li>
</ul>

<p>
<font face="verdana" size="2" color="#000000">
Each of these inner classes has a set of constants for each of its supported attributes:
</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
CharacterConstants
- Background
- BidiLevel
- Bold
- ComponentAttribute
- Family
- Foreground
- IconAttribute
- Italic
- Size
- StrikeThrough
- Subscript
- Superscript
- Underline

ColorConstants
- Background
- Foreground

FontConstants
- Bold
- Family
- Italic
- Size

ParagraphConstants
- Alignment
- FirstLineIndent
- LeftIndent 
- LineSpacing
- Orientation
- RightIndent
- SpaceAbove
- SpaceBelow
- TabSet
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
To change the set of attributes for newly-added text, you add the necessary attribute to an <code>AttributeSet</code>, and associate the set with the <code>JTextPane</code>. You can also replace the existing set, or as previously mentioned, change the attributes for the current text selection.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  SimpleAttributeSet set = new SimpleAttributeSet();
  set.addAttribute(
    StyleConstants.CharacterConstants.Bold,
    Boolean.TRUE);
  JTextPane tp = new JTextPane();
  // false = don't replace attribute for all text
  tp.setCharacterAttributes(set, false);
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
In addition to using <code>addAttribute</code> to add attributes to the set, there are some helper methods in the <code>StyleConstants</code> class. For instance, instead of having to use <code>StyleConstants.CharacterConstants.Bold</code>, as shown above, you can simply call the <code>setBold</code> method of <code>StyleConstants</code>, and pass in the appropriate <code>AttributeSet</code> and boolean value:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  StyleConstants.setBold(set, true);
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
Actually, the first argument to the <code>StyleConstants</code> methods must be a <code>MutableAttributeSet</code>, which is an extension of the <code>AttributeSet</code> interface. <code>SimpleAttributeSet</code> implements both <code>MutableAttributeSet</code> and <code>AttributeSet</code>. See the <a href="http://java.sun.com/j2se/1.4.1/docs/api/javax/swing/text/StyleConstants.CharacterConstants.html?s=06&w=34"><font face="verdana" size="2" color="#666699"><code>StyleConstants</code> class definition</font></a> for the full set of methods.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Because the <code>setText</code> method of <code>JTextPane</code> will replace all the content, a better way to add multi-attributed text is to work with the component's <code>Document</code>, which contains the text and its attributes. Get the <code>Document</code> with <code>getStyledDocument</code>, and add text to it with <code>insertString</code>. The <code>insertString</code> method requires as arguments, the position to add, the text to add, and the attribute set. The method can also throw a <code>BadLocationException</code>, which you must catch or pass along.</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  Document doc = pane.getStyledDocument();
  try {
    doc.insertString(doc.getLength(), &quot;Blind&quot;, set);
  } catch (BadLocationException e) {
    System.err.println(&quot;Bad location&quot;);
    return;
  }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
To demonstrate, let's provide a <code>JTextPane</code> with three words, where each word has a different style. Notice the different ways the 
attribute sets are initialized and associated with the <code>JTextPane</code>.
</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
  import java.awt.*;
  import javax.swing.*;
  import javax.swing.text.*;

  public class Multi {
    public static void main(String args[]) {
      JFrame frame = new JFrame(
                               &quot;Multiattributed text&quot;);
      frame.setDefaultCloseOperation(
                                 JFrame.EXIT_ON_CLOSE);
      Container content = frame.getContentPane();
      JTextPane pane = new JTextPane();
      SimpleAttributeSet set = 
                              new SimpleAttributeSet();
      set.addAttribute(
        StyleConstants.CharacterConstants.Bold,
        Boolean.TRUE);
      // Initialize attributes before adding text
      pane.setCharacterAttributes(set, true);
      pane.setText(&quot;Three&quot;);

      set = new SimpleAttributeSet();
      StyleConstants.setItalic(set, true);
      StyleConstants.setForeground(set, Color.PINK);
      StyleConstants.setBackground(set, Color.GREEN);

      Document doc = pane.getStyledDocument();
      try {
        doc.insertString(
                        doc.getLength(), &quot;Blind&quot;, set);
      } catch (BadLocationException e) {
        System.err.println(&quot;Bad location&quot;);
        return;
      }

      set = new SimpleAttributeSet();
      StyleConstants.setFontSize(set, 48);
      
      try {
        doc.insertString(
                         doc.getLength(), &quot;Mice&quot;, set);
      } catch (BadLocationException e) {
        System.err.println(&quot;Bad location&quot;);
        return;
      }

      JScrollPane scrollPane = new JScrollPane(pane);
      content.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 200);
      frame.show();
    }
  }
</pre>
</font>


<p><font face="verdana" size="2" color="#000000">
When you run the program, here's what you should see:</font>
</p>

<p>
<img src="http://developer.java.sun.com/images/tt0821.gif" border="0" alt="Multitext">
</p>

<p><font face="verdana" size="2" color="#000000">
For more information about attribute sets and style constants, 
see Chapter 23 &quot;Customizing Text Components&quot; in &quot;<a href="http://www.sun.com/books/catalog/swing/?s=06&w=34"><font face="verdana" size="2" color="#666699">Graphic Java, Mastering the JFC, 3rd Edition, Volume 2: Swing</font></a>&quot; by David Geary.</font>
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="right">
<a href="#top"><font face="verdana" size="2" color="#666699">back to top</font><img src="http://developer.java.sun.com/images/back_to_top.gif" border="0" alt=""></a>
</div>
</td></tr>

<tr><td bgcolor="#ffffff" height="2"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td></tr>

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<p>
<font face="verdana" color="#999999" size="2">IMPORTANT: Please read our Terms of Use, Privacy, and Licensing
policies:</font><br>
<a href="http://www.sun.com/share/text/termsofuse.html?s=06&w=34"><font face="verdana" size="2" color="#666699">http://www.sun.com/share/text/termsofuse.html</font></a><br>
<a href="http://www.sun.com/privacy/?s=06&w=34"><font face="verdana" size="2" color="#666699">http://www.sun.com/privacy/</font></a><br>
<a href="http://developer.java.sun.com/berkeley_license.html?s=06&w=34"><font face="verdana" size="2" color="#666699">http://developer.java.sun.com/berkeley_license.html</font></a>
</p>

<P>
<font face="verdana" color="#999999" size="2">Comments? Send your feedback on the Java<font size="-2"><sup>TM</sup></font> Developer Technical Tips to: <a href="mailto:jdc-webmaster@sun.com"><font face="verdana" size="2" color="#666699">jdc-webmaster@sun.com</font></a></font>
</P>

<p><font face="verdana" color="#999999" size="2">
Subscribe to other Java developer Tech Tips:</font>
</p>

<p><font face="verdana" color="#999999" size="2">
&#45; Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE<font size="-2"><sup>TM</sup></font>).<br>
&#45; Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME<font size="-2"><sup>TM</sup></font>).</font>
</p>

<P>
<font face="verdana" color="#999999" size="2">Go to the <a href="http://developer.java.sun.com/subscription/?s=06&w=34"><font face="verdana" size="2" color="#666699">subscriptions page</font></a> to subscribe or unsubscribe to this newsletter.</font>
</P>

<p>
<font face="verdana" color="#999999" size="2">ARCHIVES: You'll find the Java Developer Connection Technical Tips archives at:</font><br>
<a href="http://developer.java.sun.com/developer/TechTips/?s=06&w=34"><font face="verdana" size="2" color="#666699">http://developer.java.sun.com/developer/TechTips/</font></a>
</p>

<P>
<font face="verdana" color="#999999" size="2">Copyright 2002 <a href="http://www.sun.com?s=06&w=34"><font face="verdana" size="2" color="#666699">Sun Microsystems, Inc.</font></a> All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.</font>
</P>


<P>
<font face="verdana" color="#999999" size="2">Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.</font>
</P>

<!-- ================ -->
<!-- End Main Content -->
<!-- ================ -->

<center>
<a href="http://www.sun.com?s=06&w=34"><img src="http://developer.java.sun.com/images/lgsun.gif" border="0" alt="Sun Microsystems, Inc."></a>
</center>

</td>
</tr>
</table>

</td></tr>
</table>
</td>

<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
</table>

<table bgcolor = "#efefef"><tr><td><a href="http://bulkmail.sun.com/servlet/PreferenceServlet?action=change&pref_name=content-type&pref_value=text&id=210986391357016213">Please send me newsletters in text.</a><br><a href="http://bulkmail.sun.com/unsubscribe?210986391357016213">Please unsubscribe me from this newsletter.</a><img src="http://bulkmail2.sun.com/OTServlet?id=210986391357016213" width=1 height=1></td></tr></table></body>
</html>		

