0

我的最终目标是让JList用户可以在两个 s 之间来回移动元素。我正在使用 aTreeSet以便按字母顺序插入元素。这是一个视觉表示:

在此处输入图像描述

以下是我迄今为止的代码,位于 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);
    }
}
4

2 回答 2

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 );
      }
    } );

  }
}
于 2013-09-02T19:50:37.913 回答
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();**
        }
    }
于 2013-09-01T20:14:49.433 回答