我使用自定義CellRenderer和上下文菜單來選擇/取消選擇,添加或刪除列表元素,並使用checkBoxes編碼JList。添加新元素後自定義CellRenderer的Swing JList消失
一切工作正常,我可以選擇項目,打開上下文菜單,並通過它刪除/添加元素。我的問題是,當我添加一個元素,然後在列表中有比在開始時更多的元素,列表消失,我得到一個空白麪板。例如,在將一個新元素添加到列表之前而不刪除之前會發生這種情況。
爲了查明問題,我一直試圖讓代碼達到最小,但我仍然不明白爲什麼它不能正常工作。
我想知道的是爲什麼我的清單變得空白,我該如何阻止它這樣做。
當然,歡迎任何附帶意見或建議:)
謝謝。
下面是完整的代碼,如果你想給它一個嘗試(左鍵單擊選擇項目,單擊右鍵打開上下文菜單):
CheckBoxList.java
package misc;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class CheckBoxList extends JList {
private int selection = -1;
protected static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public CheckBoxList(Model m) {
this();
this.setModel(m);
}
public CheckBoxList() {
this.setCellRenderer(new CheckboxCellRenderer());
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int index = locationToIndex(e.getPoint());
selection = index;
CheckBoxList cbl = (CheckBoxList) e.getSource();
cbl.setSelectedIndex(index);
if(index != -1) {
if(e.getButton() == MouseEvent.BUTTON1) {
Data v = (Data) getModel().getElementAt(index);
v.setSelected(!v.isSelected());
JCheckBox checkbox = new JCheckBox(v.getS(), v.isSelected());
checkbox.setSelected(!checkbox.isSelected());
repaint();
} else if(e.getButton() == MouseEvent.BUTTON3) {
ContextMenu pum = new ContextMenu(cbl);
pum.show(e.getComponent(), e.getX(), e.getY());
}
}
}
});
this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CheckboxCellRenderer implements ListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Data v = (Data) value;
JCheckBox checkbox = new JCheckBox(v.getS(), v.isSelected());
checkbox.setBackground(isSelected ? getSelectionBackground() : getBackground());
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder")
: noFocusBorder);
return checkbox;
}
}
public int getSelection() {
return this.selection;
}
public class ContextMenu extends JPopupMenu {
private JMenuItem deleteItem;
private JMenuItem addItem;
private CheckBoxList cbl;
public ContextMenu(CheckBoxList cbl) {
this.cbl = cbl;
this.deleteItem = new JMenuItem("Delete");
this.deleteItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem jmi = (JMenuItem) e.getSource();
ContextMenu cm = (ContextMenu) jmi.getParent();
Model m = (Model) cm.cbl.getModel();
m.remove((Data) m.getElementAt(cm.cbl.getSelection()));
cm.cbl.repaint();
}
});
this.add(deleteItem);
this.addItem = new JMenuItem("Add new");
this.addItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem jmi = (JMenuItem) e.getSource();
ContextMenu cm = (ContextMenu) jmi.getParent();
((Model) cm.cbl.getModel()).add(new Data("Added :)"));
cm.cbl.repaint();
}
});
this.add(addItem);
}
}
}
Model.java
package misc;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ListModel;
import javax.swing.event.ListDataListener;
public class Model implements ListModel {
private List<Data> data = new ArrayList<Data>();
@Override
public void addListDataListener(ListDataListener l) {}
@Override
public Object getElementAt(int index) {
return data.get(index);
}
@Override
public int getSize() {
return data.size();
}
@Override
public void removeListDataListener(ListDataListener l) {}
public void add(Data string) {
this.data.add(string);
}
public void remove(Data d) {
data.remove(d);
}
}
Data.java
package misc;
public class Data {
private String s;
private boolean selected = false;
public Data(String s) {
super();
this.s = s;
}
public String getS() {
return this.s;
}
public void setS(String s) {
this.s = s;
}
public boolean isSelected() {
return this.selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
@Override
public String toString() {
return "Data [s=" + this.s + ", isSelected=" + this.selected + "]";
}
}
Main.java
package misc;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
public class Main {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setPreferredSize(new Dimension(500,200));
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Model m = new Model();
m.add(new Data("test1"));
m.add(new Data("test2"));
CheckBoxList cbl = new CheckBoxList(m);
JScrollPane jsp = new JScrollPane(cbl);
f.add(jsp);
f.pack();
f.setVisible(true);
}
}