Почему RolloverRenderer использует неправильный контекст ячейки

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

Я написал ComponentProvider<JLabel>, который принимает значение String и создает интерактивную ячейку, украшенную значком, если String содержит URL-адрес. Если в значении String не найден URL-адрес, то для метки не задан значок, и ячейка не должна быть активной.

Вот код:

public class ExternalLinkProvider extends ComponentProvider<JLabel> implements RolloverRenderer {

    private String url = null;

    @Override
    protected void format(CellContext context) {}

    @Override
    protected void configureState(CellContext context) {
        if (context.getValue() instanceof String) {
            String stringValue = (String) context.getValue();
            WwwLink link = new WwwLink(stringValue);

            // If this contains a valid Url, set a link icon.   
            if (link.isValid()) {
                rendererComponent.setIcon(ExternalLink.WWW_LINK_ICON);
                url = link.getUrl();
            } else {
                rendererComponent.setIcon(null);
                url = null;
            }
            rendererComponent.setText(link.getString());
        }
    }

    @Override
    protected JLabel createRendererComponent() {
        return new JRendererLabel();
    }

    @Override
    public boolean isEnabled() {
        return url != null;
    }

    @Override
    public void doClick() {
        if (url != null) {
              // Follow the url
        }
    }
}

Это выглядит так:

введите здесь описание изображения

Первая ячейка должна быть доступна для перехода по ссылке, которая была в строковом значении и была удалена из отображаемого текста. Вторая ячейка не содержала ссылки в тексте и поэтому не должна быть кликабельной.

Однако в этом случае обе ячейки не кликабельны, и если я сохраняю строковое значение и распечатываю его на консоли из метода isEnabled(), я вижу, что текст из второй ячейки всегда печатается независимо от того, навожу ли я курсор на первую или на вторая ячейка.

Это единственная ситуация, когда я заметил такое поведение. Я знаю, что один экземпляр Provider повторно используется для каждой ячейки, содержащей этот тип, но по какой-то причине RolloverRenderer, похоже, не перенастраивает этот Provider должным образом в этом случае.

Я делаю что-то не так здесь?


person Moritz    schedule 12.07.2012    source источник
comment
хм ... кроме того, что не используются рекомендуемые (во многих документах по этому поводу, моя вина, я знаю :-) методы и, таким образом, нарушается контракт, это должно по крайней мере работать. Может столбец редактируется? Если он доступен для редактирования, ролловер никогда не будет кликабельным.   -  person kleopatra    schedule 13.07.2012
comment
после небольшой игры: возможно, вы столкнулись с проблемой здесь - все наши примеры всегда кликабельны. По сути, хрупко поддерживать состояние, связанное с ячейкой, в провайдере, поскольку его можно часто вызывать и для других ячеек. API RolloverRenderer на самом деле недостаточно богат: механизм полагается на настройку средства визуализации непосредственно перед тем, как происходит щелчок (так что старое состояние все еще сохраняется), недостаточно для вашего варианта использования :-) Вы можете рассмотреть возможность подачи отчета об ошибке в системе отслеживания ошибок Swingx, чтобы мы не забыли изучить его. Спасибо.   -  person kleopatra    schedule 13.07.2012


Ответы (1)


Немного поиграв: возможно, вы столкнулись с проблемой — все наши примеры всегда кликабельны. По сути, хрупко поддерживать состояние, связанное с ячейкой, в провайдере, поскольку его можно часто вызывать и для других ячеек.

API RolloverRenderer на самом деле недостаточно богат: механизм основан на том, что средство визуализации настраивается непосредственно перед тем, как происходит щелчок (так что «старое» состояние все еще сохраняется), недостаточно для вашего варианта использования :-) Вы можете рассмотреть возможность подачи отчет об ошибке в системе отслеживания проблем Swingx, поэтому мы не забываем изучить его. Спасибо.

Фрагмент, с которым можно поиграть, в основном демонстрирующий, какие методы переопределить в пользовательском провайдере (но не решая проблему под рукой - за исключением неудобного для пользователя кладжа, чтобы постоянно включать ролловер...):

public class ExternalLinkProvider extends LabelProvider implements RolloverRenderer {

    private URL url = null;

    /**
     * Overridden to check for valid URL.
     */
    @Override
    protected void configureContent(CellContext context) {
        url = convertValueToUrl(context.getValue());
        super.configureContent(context);
    }

    private URL convertValueToUrl(Object result) {
        if (!(result instanceof String)) return null;
        URL url = null;

        try {
            url = new URL(result.toString());
        } catch (Exception e) {
            // TODO: handle exception
        }
        return url;

    }

    @Override
    protected Icon getValueAsIcon(CellContext context) {
        return url != null ? XTestUtils.loadDefaultIcon() : null;
    }

    /**
     * conditional enabled isn't reliably supported. Returning true 
     * uncondionally probably isn't option, as the cursor is changed ...
     */
    @Override
    public boolean isEnabled() {
        return true; //url != null;
    }

    @Override
    public void doClick() {
        if (url != null) {
              // Follow the url
            System.out.println("clicking");
        }
    }
}
person kleopatra    schedule 13.07.2012
comment
Большое спасибо за анализ. Я зарегистрирую тикет в системе отслеживания ошибок swingx и укажу на этот случай здесь. Тем временем я предпочитаю оставить условное включение, так как в большинстве случаев оно работает хорошо, а ситуации, когда ячейки содержат URL-адреса, встречаются редко. - person Moritz; 17.07.2012
comment
Вот ссылка на сообщение об ошибке Swingx: SWINGX-1511 - person Moritz; 17.07.2012
comment
спасибо за регистрацию ошибки :-) Рад, что вы можете жить с этим на данный момент. Хотя я бы предложил вам изменить свою реализацию, чтобы следовать общей схеме моего примера: componentProvider должен быть последовательным в своем строковом представлении (точно так же для рендеринга и в getString(value)) - person kleopatra; 17.07.2012