title: Changing cursor when rendering a JList
body: <p>I've achieved what I'm trying to do, but I can't help but to think there is a more efficient way...allow me to illustrate.</p>
  
  <p>In short, the question I'm asking is if there's a way to determine when a component has finished it's initial rendering.</p>
  
  <p>I have a JList, which is hooked up to a DefaultListModel and getting painted by a custom renderer which extends the DefaultListCellRenderer.</p>
  
  <p>This intention of the JList is to "page" through a log file, populating 2500 elements every time a new page is loaded.  On my machine it usually takes a couple seconds to fully render the JList, which is not really a problem because changing the cursor to a wait cursor would be acceptable because it would give the user immediate feedback.  Unfortunately, I cannot figure out an elegant way to know when the initial rendering has completed.</p>
  
  <p>Below is the code of my renderer, in it you'll see I'm counting the number of iterations on the renderer.  If that is between 0 and N-20, the cursor changes to a wait cursor.  Once N-20 has been reached, it reverts back to a default cursor.  Like I previously mentioned, this works just fine, but the solution really feels like a hack.  I've implemented the ListDataListener of the DefaultListModel and the PropertyChangeListener of the JList, but neither produce the functionality I'm looking for.</p>
  
  <pre><code>/**
   * Renders the MessageHistory List based on the search text and processed events
   */
  public class MessageListRenderer extends DefaultListCellRenderer
  {
      private static final long serialVersionUID = 1L;
  
      String lineCountWidth = Integer.toString(Integer.toString(m_MaxLineCount).length());
  
      @Override
      public Component getListCellRendererComponent(JList l, Object value, int index, boolean isSelected, boolean haveFocus) 
      {
          JLabel retVal = (JLabel)super.getListCellRendererComponent(l, value, index, isSelected, haveFocus);
          retVal.setText(formatListBoxOutput((String)value, index));
  
          // initial rendering is beginning - change the cursor
          if ((renderCounter == 0) &amp;&amp; !renderCursorIsWait)
          {
              m_This.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));   
              renderCursorIsWait = true;
          }
  
          // initial rendering is complete - change the cursor back
          if ((renderCounter &gt; (l.getModel().getSize() - 20)) &amp;&amp; renderCursorIsWait)
          {
              m_This.setCursor(Cursor.getDefaultCursor());
              renderCursorIsWait = false;
          }
  
          renderCounter++;
  
          return retVal;
      }
  
      /**
       * Adds font tags (marks as red) around all values which match the search criteria
       * 
       * @param lineValue string to search in 
       * @param lineIndex line number being processed
       * @return string containing the markup
       */
      private String formatListBoxOutput(String lineValue, int lineIndex)
      {
          // Theoretically the count should never be zero or less, but this will avoid an exception just in case
          if (m_MaxLineCount &lt;= 0)
              return lineValue;
  
          String formattedLineNumber = String.format("%" + Integer.toString(Integer.toString(m_MaxLineCount).length()) + "s", m_CurrentPage.getStartLineNumber() + lineIndex) + ": ";
  
          // We're not searching, simply return the line plus the added line number
          if((m_lastSearchText == null) || m_lastSearchText.isEmpty())
              return "&lt;html&gt;&lt;font color=\"#4682B4\"&gt;" + formattedLineNumber.replaceAll(" ", "&amp;nbsp;") + "&lt;/font&gt;" + lineValue + "&lt;/html&gt;";
  
          // break up the search string by the search value in case there are multiple entries 
          String outText = "";    
          String[] listValues = lineValue.split(m_lastSearchText);
  
          if(listValues.length &gt; 1)
          {
              // HTML gets rid of the preceding whitespace, so change it to the HTML code
              outText = "&lt;html&gt;&lt;font color=\"#4682B4\"&gt;" + formattedLineNumber.replaceAll(" ", "&amp;nbsp;") + "&lt;/font&gt;";
  
              for(int i = 0; i &lt; listValues.length; i++)
              {
                  outText += listValues[i];
                  if(i + 1 &lt; listValues.length)
                      outText += "&lt;font color=\"red\"&gt;" + m_lastSearchText + "&lt;/font&gt;";
              }
  
              return outText + "&lt;/html&gt;";
          }
  
          return "&lt;html&gt;&lt;font color=\"#4682B4\"&gt;" + formattedLineNumber.replaceAll(" ", "&amp;nbsp;") + "&lt;/font&gt;" + lineValue + "&lt;/html&gt;";
      }
  }
  </code></pre>
  
  <p>All I'm doing to populate the model is this:</p>
  
  <pre><code>// reset the rendering counter
  this.renderCounter = 0;
  
  // Reset the message history and add all new values
  this.modelLogFileData.clear();
  for (int i = 0; i &lt; this.m_CurrentPage.getLines().size(); i++)
      this.modelLogFileData.addElement(this.m_CurrentPage.getLines().elementAt(i));
  </code></pre>