我的最终目标是让两个JList
用户可以来回移动元素。我正在使用TreeSet
,以便按字母顺序插入元素。这是一个直观的表示:
以下是我的代码,在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);
}
}
答案 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 );
}
} );
}
}
答案 1 :(得分: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();**
}
}