【问题标题】:How do I use SwingX's Highlighter to return a different renderer component?如何使用 SwingX 的 Highlighter 返回不同的渲染器组件?
【发布时间】:2014-12-02 00:16:40
【问题描述】:

我注意到 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,以防万一,但它似乎更微妙......

【问题讨论】:

    标签: java swing swingx swingx-highlighter


    【解决方案1】:

    如果你看一下JRendererLabel,你会看到invalidaterevalidatevalidate(以及一堆其他方法)被设置为“无操作”,这意味着它们不再通知布局管理器该组件应该被布局。这样做是为了帮助提高将渲染器“标记”到组件(JXList)上的性能。

    改为使用从JPanel 扩展FixedSecondColumnRendererLabel

    与其在每次调用方法时都创建FixedSecondColumnRendererLabelJRendererLabel 的新实例,不如考虑对其进行优化,以便返回相同的实例,但每次调用方法时都会配置一个实例。

    请记住,此方法会为您的JXList 中的每一行调用,您拥有的越多,调用的次数越多,它创建的对象就越短...

    【讨论】:

    • 我担心使用 JPanel,因为他们在 cmets 中建议,如果您覆盖所有这些方法,则会出现性能问题,我们之前曾目睹过制作自定义复选框渲染器时,复选框会出现类似的性能问题。不过,我肯定会进行实例共享。
    • 是的,这是一个明确的问题,但在您的情况下,您需要此功能,因为每次更改 String/text 时,您都需要重新验证布局,但您不能执行此操作,直到组件实际大小适合绘画...您可以覆盖 setBounds 方法并强制每次调用 doLayout 作为妥协...
    • 这实际上可能是这样做的。或者我保持自己的 layoutDirty 状态,并从我确定正在绘制组件的 paintComponent 中执行此操作。
    • 从技术上讲,组件并不总是由容器绘制,所以我个人会坚持使用setBounds...
    • 我怎么知道他们不会改变 Swing 在 paintComponent 之前调用不同的方法? :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 2023-03-03
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多