Изменение курсора при рендеринге JList - PullRequest
3 голосов
/ 27 сентября 2011

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

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

У меня есть 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 ]

4 голосов
/ 28 сентября 2011

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

private static class TaskListener implements PropertyChangeListener {

    @Override
    public void propertyChange(PropertyChangeEvent e) {
        if (e.getNewValue() == SwingWorker.StateValue.DONE) {
            // restore cursor
        }
    }
}
3 голосов
/ 27 сентября 2011

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

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

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

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

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

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

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

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

  • удалено, остальные см. В пункте 3
  • подготовлено в Задании BackGroung вместо встроенного конструктора между Renderer и загрузкой + HTML-форматирование + Обратные взаимодействия сRenderer, в данном случае, бесполезен для Renderer, потому что вы можете предварительно отформатировать Предметы, используя HTML, затем удалить Renderer
...