2013-09-01 34 views
0

我的最終目標是有兩個JList之間的用戶可以來回移動元素。我正在使用TreeSet,以便按字母順序插入元素。這裏有一個直觀表示:使用ListModel陰影TreeSet

enter image description here

下面是我的代碼到目前爲止,其在SSCCE。它主要是在工作,但我有時會得到一個ArrayOutOfBoundsException。問題與程序思考有關,選擇的元素比實際選擇的要多。重新創建問題的一種方法是在左側選擇兩個元素,然後按右側按鈕兩次。

import java.awt.Dimension; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.*; 
import javax.swing.*; 

public class GUI extends JFrame { 

    private GridBagLayout gridBag = new GridBagLayout(); 
    private static final String[] ALL_STRINGS = { "B", "A", "C" }; 

    private JButton leftButton = new JButton("<"); 
    private JButton rightButton = new JButton(">"); 
    private StringListModel listModel = new StringListModel(Arrays.asList(ALL_STRINGS)); 
    private StringListModel queueModel = new StringListModel(); 
    private JList<String> list = new JList<String>(listModel); 
    private JList<String> queue = new JList<String>(queueModel); 

    public GUI() { 
     setWindowProperties(); 
     addComponents(); 
    } 

    private void setWindowProperties() { 
     setLayout(gridBag); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(new Dimension(300, 200)); 
     setTitle("JList, ListModel, and TreeSet"); 
     setResizable(false); 
     setLocationRelativeTo(null); 
    } 

    private void addComponents() { 
     leftButton.addActionListener(new QueueListener()); 
     rightButton.addActionListener(new QueueListener()); 

     JScrollPane listScroll = new JScrollPane(list); 
     JScrollPane queueScroll = new JScrollPane(queue); 

     Dimension scrollSize = new Dimension(50, 100); 

     listScroll.setPreferredSize(scrollSize); 
     queueScroll.setPreferredSize(scrollSize); 

     add(listScroll); 
     add(leftButton); 
     add(rightButton); 
     add(queueScroll); 
    } 

    private class QueueListener implements ActionListener { 

     private JButton button; 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      button = (JButton) e.getSource(); 

      if (button.equals(leftButton)) { 
       removeFromQueue(); 
      } else if (button.equals(rightButton)) { 
       addToQueue(); 
      } 
     } 

     private void removeFromQueue() { 
      List<String> Strings = queue.getSelectedValuesList(); 

      queueModel.removeAll(Strings); 
      listModel.addAll(Strings); 
     } 

     private void addToQueue() { 
      List<String> Strings = list.getSelectedValuesList(); 

      listModel.removeAll(Strings); 
      queueModel.addAll(Strings); 
     } 
    } 

    private class StringListModel extends DefaultListModel<String> { 
     private TreeSet<String> model = new TreeSet<String>(); 

     public StringListModel() { 
     } 

     public StringListModel(List<String> Strings) { 
      addAll(Strings); 
     } 

     public int getSize() { 
      return model.size(); 
     } 

     public String getElementAt(int index) { 
      return (String) model.toArray()[index]; 
     } 

     public void add(String String) { 
      if (model.add(String)) { 
       fireContentsChanged(this, 0, getSize()); 
      } 
     } 

     public void addAll(List<String> quets) { 
      for (String String : quets) { 
       model.add(String); 
      } 

      fireContentsChanged(this, 0, getSize()); 
     } 

     public void clear() { 
      model.clear(); 
      fireContentsChanged(this, 0, getSize()); 
     } 

     public boolean contains(Object element) { 
      return model.contains(element); 
     } 

     public String firstElement() { 
      return model.first(); 
     } 

     public Iterator iterator() { 
      return model.iterator(); 
     } 

     public String lastElement() { 
      return model.last(); 
     } 

     public void removeAll(Collection<?> elements) { 
      for (Object element : elements) { 
       removeElement(element); 
      } 

      fireContentsChanged(this, 0, getSize()); 
     } 

     public boolean removeElement(Object element) { 
      boolean removed = model.remove(element); 
      if (removed) { 
       fireContentsChanged(this, 0, getSize()); 
      } 

      return removed; 
     } 
    } 

    public static void main(String[] args) { 
     new GUI().setVisible(true); 
    } 
} 
+1

我沒有詳細檢查了它,但你的'StringListModel'是完全錯誤的。如果你從'DefaultListModel'擴展,你應該使用它的add/remove/...方法。我強烈建議你的情況直接實現接口或從'AbstractListModel'擴展而不是 – Robin

+0

我遇到了與AbstractListModel相同的問題。 –

回答

1

如果修改的actionPerformed清除模式的選擇,你將不再有ArrayOutOfBoundsException:

@Override 
    public void actionPerformed(ActionEvent e) { 
     button = (JButton) e.getSource(); 

     if (button.equals(leftButton)) { 
      removeFromQueue(); 
      **queue.getSelectionModel().clearSelection();** 
     } else if (button.equals(rightButton)) { 
      addToQueue(); 
      **list.getSelectionModel().clearSelection();** 
     } 
    } 
+0

如果您的底層'ListModel'觸發正確的更改(例如在'remove'事件中,它應該從選擇中自動消失) – Robin

+0

是的,這是有道理的。 OP的StringListModel應該如何修改?我只能在明確清除選擇時才能使其工作。將它添加爲答案,然後我將它投票,但是如果沒有明確的調用,我又無法使其工作。 – ditkin

+0

很好的回答!謝謝!羅賓,我很樂意看到你的建議。 –

2

這個實現似乎工作。請注意,我將TreeSet更改爲簡單List。缺點是插入/刪除會慢一點,但至少我可以發出正確的事件。鑑於這是一個UI小部件,我認爲這是可以接受的,因爲底層模型永遠不會是巨大的(或者UI將變得不可用)。

我從AbstractListModel擴展,但您也可以從DefaultListModel擴展。在這種情況下,你可能會想,以確保addElement方法計算正確的索引,並呼籲super.add(calculatedIndex, element)

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.*; 
import javax.swing.*; 

public class GUI extends JFrame { 

    private GridBagLayout gridBag = new GridBagLayout(); 
    private static final String[] ALL_STRINGS = {"B", "A", "C"}; 

    private JButton leftButton = new JButton("<"); 
    private JButton rightButton = new JButton(">"); 
    private StringListModel listModel = new StringListModel(Arrays.asList(ALL_STRINGS)); 
    private StringListModel queueModel = new StringListModel(); 
    private JList<String> list = new JList<String>(listModel); 
    private JList<String> queue = new JList<String>(queueModel); 

    public GUI() { 
    setWindowProperties(); 
    addComponents(); 
    } 

    private void setWindowProperties() { 
    setLayout(gridBag); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setSize(new Dimension(300, 200)); 
    setTitle("JList, ListModel, and TreeSet"); 
    setResizable(false); 
    setLocationRelativeTo(null); 
    } 

    private void addComponents() { 
    leftButton.addActionListener(new QueueListener()); 
    rightButton.addActionListener(new QueueListener()); 

    JScrollPane listScroll = new JScrollPane(list); 
    JScrollPane queueScroll = new JScrollPane(queue); 

    Dimension scrollSize = new Dimension(50, 100); 

    listScroll.setPreferredSize(scrollSize); 
    queueScroll.setPreferredSize(scrollSize); 

    add(listScroll); 
    add(leftButton); 
    add(rightButton); 
    add(queueScroll); 
    } 

    private class QueueListener implements ActionListener { 

    private JButton button; 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     button = (JButton) e.getSource(); 

     if (button.equals(leftButton)) { 
     removeFromQueue(); 
     } 
     else if (button.equals(rightButton)) { 
     addToQueue(); 
     } 
    } 

    private void removeFromQueue() { 
     List<String> Strings = queue.getSelectedValuesList(); 

     queueModel.removeAll(Strings); 
     listModel.addAll(Strings); 
    } 

    private void addToQueue() { 
     List<String> Strings = list.getSelectedValuesList(); 

     listModel.removeAll(Strings); 
     queueModel.addAll(Strings); 
    } 
    } 

    private class StringListModel extends AbstractListModel<String> { 
    private List<String> model = new ArrayList<>(); 

    public StringListModel() { 
    } 

    public StringListModel(List<String> strings) { 
     addAll(strings); 
    } 

    @Override 
    public int getSize() { 
     return model.size(); 
    } 

    @Override 
    public String getElementAt(int index) { 
     return model.toArray(new String[model.size()])[index]; 
    } 

    public void addAll(Collection<String> strings){ 
     for (String string : strings) { 
     add(string); 
     } 
    } 
    public void add(String string){ 
     int index = calculateIndex(string); 
     model.add(index, string); 
     fireIntervalAdded(this, index, index); 
    } 

    public void remove(String string){ 
     int index = model.indexOf(string); 
     if (index != -1){ 
     model.remove(index); 
     fireIntervalRemoved(this, index, index); 
     } 
    } 

    public void removeAll(Collection<String> strings){ 
     for (String next : strings) { 
     remove(next); 
     } 
    } 
    private int calculateIndex(String input){ 
     if (model.size() == 0){ 
     return 0; 
     } 
     int index = 0; 
     while (model.get(index).compareTo(input) <=0){ 
     index++; 
     if (index == model.size()){ 
      return index; 
     } 
     } 
     return index; 
    } 
    } 

    public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
     new GUI().setVisible(true); 
     } 
    }); 

    } 
}