One of the main problems I have with JList
is that no component is actually added to it. This means that things like ActionListener
s don't work, and you can't really have a list of interactive components. To solve this, I've tried to quickly implement an alternative.
I have a number of concerns.
Speed: Will this be fast enough to display hundreds (thousands? millions?) of items?
Reliability: I've tried to make it reasonably solid, but no doubt there are a lot of things I should be checking that I am not.
Design: This is probably the most important. I tried to make a general, all-purpose design similar to that of
JList
, but it feels almost too complex to me. However, I cannot think of a better way. Any suggestions on how to improve it are most welcome.
It has three general parts:
The AdvancedList
:
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.util.List;
import java.util.Vector;
import javax.swing.BoxLayout;
public class AdvancedList<E> extends Container {
protected List<E> model;
protected List<AdvancedListCell<E>> listCells;
protected AdvancedCellRenderer<E> cellRenderer;
public AdvancedList(List<E> model, AdvancedCellRenderer<E> cellRenderer){
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.cellRenderer = cellRenderer;
this.model = new Vector<E>();
this.listCells = new Vector<AdvancedListCell<E>>();
for(E element: model){
this.addElement(element);
}
}
public AdvancedList(AdvancedCellRenderer<E> cellRenderer){
this(new Vector<E>(), cellRenderer);
}
public void addElement(E element){
AdvancedListCell<E> alc = cellRenderer.getAdvancedListCell(this, element, model.size());
this.add(alc.getComponent());
this.listCells.add(alc);
this.model.add(element);
}
public E removeElement(E element){
int idx = this.model.indexOf(element);
if(idx != -1) {
this.remove(idx);
this.listCells.remove(idx);
E removed = this.model.remove(idx);
this.repaint();
return removed;
}
return null;
}
public void paint(Graphics g){
AdvancedListCell<E> tmpListCell = null;
Component tmpComponent = null;
for(int i = 0; i < this.model.size(); i++){
tmpListCell = this.listCells.get(i);
tmpComponent = this.getComponent(i);
tmpListCell.updateCell(this, this.model.get(i), i, tmpComponent.hasFocus());
}
super.paint(g);
}
}
The AdvancedCellRenderer
:
public interface AdvancedCellRenderer<E> {
public AdvancedListCell<E> getAdvancedListCell(AdvancedList<? extends E> list, E value, int index);
}
The AdvancedListCell
:
import java.awt.Component;
public interface AdvancedListCell<E> {
public void updateCell(AdvancedList<? extends E> list, E value,
int index, boolean cellHasFocus);
public Component getComponent();
}
And finally, a simple test class:
import java.awt.Component;
import java.awt.Container;
import java.util.Arrays;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class AdvancedListTest {
public static void main(String[] args){
JFrame myFrame = new JFrame();
Vector<String> myStrings = new Vector<String>();
myStrings.addAll(Arrays.asList("TEST", "HI", "FOO", "BAR"));
AdvancedList<String> myList = new AdvancedList<String>(myStrings, new AdvancedCellRenderer<String>(){
@Override
public AdvancedListCell<String> getAdvancedListCell(
AdvancedList<? extends String> list, String value, int index) {
return new AdvancedListCell<String>(){
private JLabel myLabel = new JLabel();
@Override
public Component getComponent() {
return myLabel;
}
@Override
public void updateCell(AdvancedList<? extends String> list,
String value, int index, boolean cellHasFocus) {
myLabel.setText(value+", index: "+index+", has focus: "+cellHasFocus);
}
public String toString(){
return "Class: "+myLabel.getClass()+", text: "+myLabel.getText();
}
};
}
});
myFrame.setSize(500, 500);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.add(myList);
myFrame.revalidate();
myFrame.repaint();
myFrame.setVisible(true);
myList.addElement("Added a string");
myList.removeElement("HI");
}
}