Изменение курсора при рендеринге 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));

2 ответа

Решение

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

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

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

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

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

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

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

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

  • снято, остальное см. в пункте 3
  • подготовленный в BackGroung Task вместо встроенного конструктора между Renderer и загрузкой + Html Formating + Обратные взаимодействия с Renderer, в этом случае Renderer бесполезен, потому что вы можете пометить элементы предварительного форматирования, которые с помощью Html, затем удалить Renderer

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

private static class TaskListener implements PropertyChangeListener {

    @Override
    public void propertyChange(PropertyChangeEvent e) {
        if (e.getNewValue() == SwingWorker.StateValue.DONE) {
            // restore cursor
        }
    }
}
Другие вопросы по тегам