0

私の最終目標はJList、ユーザーが要素を前後に移動できる 2 つの s を持つことです。TreeSet要素がアルファベット順に挿入されるように、を使用しています。視覚的な表現は次のとおりです。

ここに画像の説明を入力

以下はこれまでの私のコードで、SSCCE に含まれています。ほとんど動作していますが、ArrayOutOfBoundsException. 問題は、実際よりも多くの要素が選択されていると考えるプログラムに関係しています。問題を再現する 1 つの方法は、左側の 2 つの要素を選択してから、右側のボタンを 2 回押すことです。

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たが、 から拡張することもできますDefaultListModeladdElementその場合、メソッドが正しいインデックスと呼び出しを計算することを確認したいでしょう。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 に答える