Как я могу использовать Highlighter SwingX для возврата другого компонента рендерера?

Я заметил SwingX Highlighter Интерфейс позволяет подсветчику возвращать компонент, отличный от того, который передается. На самом деле я не могу найти никаких примеров его использования, но я подумал, что попытаюсь использовать его для создания какого-то фальшивого второго столбца.

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

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

Вот что я имею в виду:

Скриншот

Пример программы:

import java.awt.BorderLayout;
import java.awt.Component;

import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.LayoutStyle;
import javax.swing.SwingUtilities;

import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.renderer.JRendererLabel;
import org.jdesktop.swingx.renderer.StringValue;

public class RendererTest implements Runnable
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new RendererTest());
    }

    @Override
    public void run()
    {
        JFrame frame = new JFrame("Highlighter test");
        JXList list = new JXList();
        DefaultListModel<String> listModel = new DefaultListModel<>();
        listModel.addElement("one");
        listModel.addElement("two");
        listModel.addElement("three");
        list.setModel(listModel);
        list.setVisibleRowCount(8);
        list.setPrototypeCellValue("some string");
        list.addHighlighter(new AddSecondColumnHighlighter(v -> ((String) v).toUpperCase()));
        JScrollPane listScroll = new JScrollPane(list);
        frame.setLayout(new BorderLayout());
        frame.add(listScroll, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }

    private static class AddSecondColumnHighlighter extends AbstractHighlighter
    {
        private final StringValue secondColumnStringValue;

        public AddSecondColumnHighlighter(StringValue secondColumnStringValue)
        {
            this.secondColumnStringValue = secondColumnStringValue;
        }

        @Override
        protected Component doHighlight(Component component, ComponentAdapter adapter)
        {
            JRendererLabel rightColumn = new JRendererLabel();
            rightColumn.setText(secondColumnStringValue.getString(adapter.getValue()));

            return new FixedSecondColumnRendererLabel(component, rightColumn);
        }
    }

    private static class FixedSecondColumnRendererLabel extends JRendererLabel
    {
        private FixedSecondColumnRendererLabel(Component leadingComponent, Component trailingComponent)
        {
            GroupLayout layout = new GroupLayout(this);
            setLayout(layout);

            layout.setHorizontalGroup(layout.createSequentialGroup()
                                            .addComponent(leadingComponent, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                            .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                                            .addComponent(trailingComponent));

            layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                          .addComponent(leadingComponent)
                                          .addComponent(trailingComponent));
        }
    }

}

Мне интересно, есть ли правильный способ использовать этот бит API. Я намеренно продлил JRendererLabel в случае, если это было проблемой, но это кажется чем-то более тонким...

1 ответ

Решение

Если вы посмотрите на JRendererLabel, вы увидите, что invalidate, revalidate, validate (и куча других методов) были установлены на "бездействие", что означает, что они больше не отправляют диспетчеру макета уведомления о том, что компонент должен быть размечен. Это сделано для того, чтобы улучшить производительность "штамповки" рендерера на компоненте (JXList).

Вместо этого используйте расширение FixedSecondColumnRendererLabel от JPanel,

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

Помните, этот метод вызывается для КАЖДОЙ строки в вашем JXListчем больше у вас есть, чем больше он будет вызываться, тем более недолговечные объекты он будет создавать...

Другие вопросы по тегам