Изменение курсора при рендеринге JList

Я достиг того, что я пытаюсь сделать, но я не могу не думать, что есть более эффективный способ... позвольте мне проиллюстрировать.

Короче говоря, вопрос, который я задаю, заключается в том, есть ли способ определить, когда компонент завершил свой первоначальный рендеринг.

У меня есть JList, который подключен к DefaultListModel и рисуется пользовательским средством визуализации, которое расширяет DefaultListCellRenderer.

Это намерение JList состоит в том, чтобы «пролистывать» файл журнала, заполняя 2500 элементов каждый раз, когда загружается новая страница. На моей машине обычно требуется пара секунд, чтобы полностью отобразить JList, что на самом деле не является проблемой, потому что изменение курсора на курсор ожидания было бы приемлемым, поскольку это дало бы пользователю немедленную обратную связь. К сожалению, я не могу найти элегантный способ узнать, когда первоначальный рендеринг завершен.

Ниже приведен код моего рендерера, в нем вы увидите, что я подсчитываю количество итераций на рендерере. Если он находится в диапазоне от 0 до N-20, курсор изменится на курсор ожидания. После достижения N-20 он возвращается к курсору по умолчанию. Как я упоминал ранее, это прекрасно работает, но решение действительно похоже на хак. Я реализовал ListDataListener из DefaultListModel и PropertyChangeListener из JList, но ни один из них не дает той функциональности, которую я ищу.

/**
 * 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>";
    }
}

Все, что я делаю для заполнения модели, это:

// 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));

person JoshBramlett    schedule 27.09.2011    source источник
comment
Был добавлен дополнительный код, но я не уверен, что это поможет с вопросом. То, что я ищу, - это способ определить, завершен ли компонент с его первоначальным рендерингом без реализации счетчика.   -  person JoshBramlett    schedule 27.09.2011
comment
никогда (как в: nononono, просто не) меняйте состояние списка вызовов в рендерере. Все параметры, указанные в getXXRendererComponent, строго доступны только для чтения. Переместите свою логику в другое место, как уже предложил @trashgod   -  person kleopatra    schedule 28.09.2011


Ответы (2)


1) вы добавили Cursor в JList, а не внутрь Renderer, например здесь или здесь

2) Renderer по умолчанию возвращает JLabel, особых причин определять это нет

3) Renderer может setBackground, Font любыми методами (в данном случае) JLabel

РЕДАКТИРОВАТЬ:

4) удалить retVal.setText(formatListBoxOutput((String)value, index)); создать DefaulListModel и переместить подготовленные Items в Model#addItem

5) int index, можно сравнить с JList#getModel().getSize() -1; убрать это из Renderer,

6) лучше было бы добавить свои элементы из BackGround Task (@trashgod, ваше предложение было правильным :-) и заполнить партии (спасибо), если вы будете внедрять SwingWorker, то вы можете создать партию из 50 элементов и добавить по 50. .. пока не сделано

7) Renderer предназначен только для форматирования вывода, ваше форматирование Html может быть:

  • удалено, остальное см. в пункте 3-м.
  • подготовленный в BackGroung Task вместо встроенного конструктора между средством визуализации и загрузкой + форматирование HTML + обратное взаимодействие с средством визуализации, в этом случае средство визуализации бесполезно, потому что вы можете предварительно форматировать элементы, используя Html, а затем удалить средство визуализации
person mKorbel    schedule 27.09.2011
comment
Спасибо, но я полагаю, что вы неправильно поняли вопрос. Курсор устанавливается в родительском окне (через глобальную переменную m_This). Как я уже сказал в посте, моя реализация работает, мне просто любопытно, есть ли способ элегантно определить, когда завершился первоначальный рендеринг JList. - person JoshBramlett; 27.09.2011
comment
Я согласен; насколько это возможно, постарайтесь переместить любую загрузку/форматирование из средства визуализации и в рабочий поток. - person trashgod; 28.09.2011
comment
@Josh: Престижность за то, что принял этот исчерпывающий ответ. Я также призываю вас проголосовать за него. - person trashgod; 14.10.2011

В дополнение к предложениям @mKorbel используйте SwingWorker для пакетного заполнения модели списка. Добавьте прослушиватель изменения свойств в рабочий процесс и восстановите курсор, когда закончите. Здесь есть соответствующие вопросы и ответы .

private static class TaskListener implements PropertyChangeListener {

    @Override
    public void propertyChange(PropertyChangeEvent e) {
        if (e.getNewValue() == SwingWorker.StateValue.DONE) {
            // restore cursor
        }
    }
}
person trashgod    schedule 27.09.2011
comment
Извините за фальстарт; SwingWorker уведомляет PropertyChangeListeners в потоке отправки событий. - person trashgod; 28.09.2011
comment
Привет, ребята, просто хотел предупредить, я не брошу это... просто меня поставили перед более неотложной проблемой, и у меня не было возможности рассмотреть ваши предложения. Еще раз спасибо всем за помощь. - person JoshBramlett; 01.10.2011
comment
Спасибо, ребята, это именно то, что я искал, и, что более важно, я гораздо лучше понимаю, что происходит. - person JoshBramlett; 03.10.2011