Changing cursor when rendering JList

I have achieved what I am trying to do, but I cannot help but think that there is a more efficient way ... let me illustrate.

In short, the question I'm asking is whether there is a way to determine when a component completed its initial rendering.

I have a JList that is connected to the DefaultListModel module and is drawn by a special render that extends DefaultListCellRenderer.

This JList intent is to “page” through the log file, filling out 2,500 items each time a new page is loaded. On my machine, it usually takes a few seconds to fully display the JList, which is not really a problem, because changing the cursor to the wait cursor would be acceptable, because it would give the user immediate feedback. Unfortunately, I cannot find an elegant way to find out when the initial rendering is complete.

Below is the code of my visualization tool, in it you will see that I am calculating the number of iterations on the renderer. If it is from 0 to N-20, the cursor changes to a wait cursor. Once the N-20 is reached, it will revert to the default cursor. As I mentioned, this works fine, but the solution really looks like a hack. I implemented ListDataListener from DefaultListModel and PropertyChangeListener from JList, but did not create the functionality I'm looking for.

/** * 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) && !renderCursorIsWait) { m_This.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); renderCursorIsWait = true; } // initial rendering is complete - change the cursor back if ((renderCounter > (l.getModel().getSize() - 20)) && 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 <= 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 "<html><font color=\"#4682B4\">" + formattedLineNumber.replaceAll(" ", "&nbsp;") + "</font>" + lineValue + "</html>"; // 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 > 1) { // HTML gets rid of the preceding whitespace, so change it to the HTML code outText = "<html><font color=\"#4682B4\">" + formattedLineNumber.replaceAll(" ", "&nbsp;") + "</font>"; for(int i = 0; i < listValues.length; i++) { outText += listValues[i]; if(i + 1 < listValues.length) outText += "<font color=\"red\">" + m_lastSearchText + "</font>"; } return outText + "</html>"; } return "<html><font color=\"#4682B4\">" + formattedLineNumber.replaceAll(" ", "&nbsp;") + "</font>" + lineValue + "</html>"; } } 

All I do to fill the model is:

 // reset the rendering counter this.renderCounter = 0; // Reset the message history and add all new values this.modelLogFileData.clear(); for (int i = 0; i < this.m_CurrentPage.getLines().size(); i++) this.modelLogFileData.addElement(this.m_CurrentPage.getLines().elementAt(i)); 
+3
source share
2 answers

1) you added Cursor to JList , and not inside Renderer , for example here or here

2) Renderer returns JLabel by default, there is no particular reason to determine that

3) Renderer can setBackground , Font any methods for (in this case) JLabel

EDIT:

4) delete retVal.setText(formatListBoxOutput((String)value, index)); create DefaulListModel and move prepared elements to Model # addItem

5) int index, can be compared with JList#getModel().getSize() -1; remove from renderer,

6) it would be better to add your elements from the BackGround Task (@trashgod, your suggestion was correct :-) and fill in the batches (thanks), if you use SwingWorker, then you can create a batch of 50 items and add 50 ... to completion

7) Renderer is intended only for generating output; your Html formation may be:

  • deleted, see point 3.
  • prepared in the BackGroung Task instead of the built-in constructor between Renderer and loading + Html Forming + reverse interactions with Renderer, in this case Renderer is useless because you can pertinent elements that are created using Html and then remove Renderer
+3
source

In addition to @mKorbel's suggestions, use SwingWorker to populate the list model with lots. Add a property change listener to the worker and restore the cursor when done. There is a related Q&A here .

 private static class TaskListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent e) { if (e.getNewValue() == SwingWorker.StateValue.DONE) { // restore cursor } } } 
+4
source

All Articles