I noticed SwingX's Highlighter
interface allows the highlighter to return a different component from the one that is being passed in. I can't actually find any examples of this being used, but I thought I would try to use it to create some kind of fake second column.
The intended result is that text in the left column should truncate where the right column starts, so I can't just use a Painter
. The right column should render the same width for the whole list, which is an issue I haven't figured out yet but which doesn't seem like it will be hard.
As for right now though, I am finding that the row height gets compressed to be so small, you can't see any of the text.
Here's what I mean:
Sample program:
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));
}
}
}
I'm wondering if there is a right way to use this bit of the API. I deliberately extended JRendererLabel
in case that was the issue, but it seems to be something more subtle...