2012-06-19 70 views
1

我使用自定義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); 
    } 
} 

回答

4

問題來自您的ListModel的實現,您沒有實現addListDataListener和removeListDataListener,也不會觸發適當的模型事件來通知它們。

簡而言之下面你ListModel的,它應該工作好了很多:

private List<ListDataListener> listeners = new ArrayList<ListDataListener>(); 

    @Override 
    public void addListDataListener(ListDataListener l) { 
     listeners.add(l); 
    } 

    @Override 
    public void removeListDataListener(ListDataListener l) { 
     listeners.remove(l); 
    } 

    public void add(Data string) { 
     this.data.add(string); 
     ListDataEvent addition = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, data.size() - 1, data.size() - 1); 
     for (ListDataListener l : listeners) { 
      l.intervalAdded(addition); 
     } 
    } 

    public void remove(Data d2) { 
     data.remove(d2); 
     ListDataEvent removal = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, data.size(), data.size()); 
     for (ListDataListener l : listeners) { 
      l.intervalRemoved(removal); 
     } 
    } 

可能考慮延長或usind直接DefaultListModel它爲你處理這一切。

2

我想你一定在你的模型實現數據的聽衆。監聽器可以通過Swing添加,並且他們希望在事情發生變化時得到通知。

相關問題