2012-06-19 1 views
1

사용자 정의 CellRenderer을 사용하는 checkBoxes 및 목록의 요소를 선택/선택 취소, 추가 또는 제거하기위한 컨텍스트 메뉴를 사용하여 JList를 코딩하고 있습니다.새 요소를 추가 한 후 사용자 정의 CellRenderer가있는 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

addListDataListener 및 removeListDataListener를 구현하지 않은 ListModel 구현에서 문제가 발생하며이를 알리기 위해 적절한 모델 이벤트를 실행하지 마십시오.

은 단순히 당신의 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에서 추가 할 수 있으며, 변경된 사항이있을 때 알림을 받기를 기대합니다.