问题
I have two JLists
to move items back and forth between. I add items with a number value in front so example.
1. A
2. B
3. C
...
10. j
The problem is that the list currently sorts as 1. 10. 2. 3., the 10. comes right after the one and isn't the last item as it should be by numerical sort. Can someone shed some light on this or help me fix this please? Thank you!
import java.awt.*;
import java.awt.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class DualListBox extends JPanel
{
private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0);
private static final String ADD_BUTTON_LABEL = ">>";
private static final String REMOVE_BUTTON_LABEL = "<<";
private static final String DEFAULT_TITLE = "";
private static final String DEFAULT_SOURCE_CHOICE_LABEL = "Included";
private static final String DEFAULT_DEST_CHOICE_LABEL = "Excluded";
private JTextField title;
private JLabel sourceLabel;
private JList sourceList;
private SortedListModel sourceListModel;
private JList destList;
private SortedListModel destListModel;
private JLabel destLabel;
private JButton addButton;
private JButton removeButton;
public DualListBox()
{
initScreen();
}
private String getSourceChoicesTitle()
{
return sourceLabel.getText();
}
private void setSourceChoicesTitle(String newValue)
{
sourceLabel.setText(newValue);
}
private String getDestinationChoicesTitle()
{
return destLabel.getText();
}
private void setDestinationChoicesTitle(String newValue)
{
destLabel.setText(newValue);
}
private void clearSourceListModel()
{
sourceListModel.clear();
}
private void clearDestinationListModel()
{
destListModel.clear();
}
public void addSourceElements(ListModel newValue)
{
fillListModel(sourceListModel, newValue);
}
private void setSourceElements(ListModel newValue)
{
clearSourceListModel();
addSourceElements(newValue);
}
public void addDestinationElements(ListModel newValue)
{
fillListModel(destListModel, newValue);
}
private void fillListModel(SortedListModel model, ListModel newValues)
{
int size = newValues.getSize();
for (int i = 0; i < size; i++)
{
model.add(newValues.getElementAt(i));
}
}
public void addSourceElements(Object newValue[])
{
fillListModel(sourceListModel, newValue);
}
private void setSourceElements(Object newValue[])
{
clearSourceListModel();
addSourceElements(newValue);
}
public void addDestinationElements(Object newValue[])
{
fillListModel(destListModel, newValue);
}
private void fillListModel(SortedListModel model, Object newValues[])
{
model.addAll(newValues);
}
private Iterator sourceIterator()
{
return sourceListModel.iterator();
}
private Iterator destinationIterator()
{
return destListModel.iterator();
}
private void setSourceCellRenderer(ListCellRenderer newValue)
{
sourceList.setCellRenderer(newValue);
}
private ListCellRenderer getSourceCellRenderer()
{
return sourceList.getCellRenderer();
}
private void setDestinationCellRenderer(ListCellRenderer newValue)
{
destList.setCellRenderer(newValue);
}
private ListCellRenderer getDestinationCellRenderer()
{
return destList.getCellRenderer();
}
private void setVisibleRowCount(int newValue)
{
sourceList.setVisibleRowCount(newValue);
destList.setVisibleRowCount(newValue);
}
private int getVisibleRowCount()
{
return sourceList.getVisibleRowCount();
}
private void setSelectionBackground(Color newValue)
{
sourceList.setSelectionBackground(newValue);
destList.setSelectionBackground(newValue);
}
private Color getSelectionBackground()
{
return sourceList.getSelectionBackground();
}
private void setSelectionForeground(Color newValue)
{
sourceList.setSelectionForeground(newValue);
destList.setSelectionForeground(newValue);
}
private Color getSelectionForeground()
{
return sourceList.getSelectionForeground();
}
private void clearSourceSelected()
{
Object selected[] = sourceList.getSelectedValues();
for (int i = selected.length - 1; i >= 0; --i)
{
sourceListModel.removeElement(selected[i]);
}
sourceList.getSelectionModel().clearSelection();
}
private void clearDestinationSelected()
{
Object selected[] = destList.getSelectedValues();
for (int i = selected.length - 1; i >= 0; --i)
{
destListModel.removeElement(selected[i]);
}
destList.getSelectionModel().clearSelection();
}
public ArrayList<String> getSourceListModel()
{
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < sourceListModel.getSize(); ++i)
list.add(sourceListModel.getElementAt(i).toString());
return list;
}
public void printSource(ArrayList<String> list)
{
String str = "";
for (int i = 0; i < list.size(); i++)
{
System.out.println(fixString((String) list.get(i)));
}
}
public String fixString(String str)
{
str = str.replaceAll("\\d+\\.\\s", "");
return str;
}
public boolean containsItem(SortedListModel list, String search)
{
return true;
}
private void initScreen()
{
setBorder(BorderFactory.createEtchedBorder());
setLayout(new GridBagLayout());
title = new JTextField("");
title.setEditable(false);
add(title, new GridBagConstraints(0, 0, 3, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
EMPTY_INSETS, 0, 0));
sourceLabel = new JLabel(DEFAULT_SOURCE_CHOICE_LABEL);
sourceListModel = new SortedListModel();
sourceList = new JList(sourceListModel);
sourceList.addListSelectionListener(new AddSelectionListener());
add(sourceLabel, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
EMPTY_INSETS, 0, 0));
add(new JScrollPane(sourceList), new GridBagConstraints(0, 2, 1, 5, .5, 1, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, EMPTY_INSETS, 0, 0));
addButton = new JButton(ADD_BUTTON_LABEL);
add(addButton, new GridBagConstraints(1, 3, 1, 2, 0, .25, GridBagConstraints.CENTER, GridBagConstraints.NONE,
EMPTY_INSETS, 0, 0));
addButton.addActionListener(new AddListener());
removeButton = new JButton(REMOVE_BUTTON_LABEL);
add(removeButton, new GridBagConstraints(1, 5, 1, 2, 0, .25, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(0, 5, 0, 5), 0, 0));
removeButton.addActionListener(new RemoveListener());
destLabel = new JLabel(DEFAULT_DEST_CHOICE_LABEL);
destListModel = new SortedListModel();
destList = new JList(destListModel);
destList.addListSelectionListener(new RemoveSelectionListener());
add(destLabel, new GridBagConstraints(2, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
EMPTY_INSETS, 0, 0));
add(new JScrollPane(destList), new GridBagConstraints(2, 2, 1, 5, .5, 1.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, EMPTY_INSETS, 0, 0));
}
public class AddListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object selected[] = sourceList.getSelectedValues();
addDestinationElements(selected);
title.setText("");
clearSourceSelected();
clearDestinationSelected();
}
}
public class RemoveListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object selected[] = destList.getSelectedValues();
addSourceElements(selected);
title.setText("");
clearSourceSelected();
clearDestinationSelected();
}
}
public class AddSelectionListener implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent e)
{
if (!e.getValueIsAdjusting())
{
if (!sourceList.isSelectionEmpty())
title.setText(fixString(sourceList.getSelectedValue().toString()));
}
}
}
public class RemoveSelectionListener implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent e)
{
if (!e.getValueIsAdjusting())
{
if (!destList.isSelectionEmpty())
title.setText(fixString(destList.getSelectedValue().toString()));
}
}
}
}
class SortedListModel extends AbstractListModel
{
SortedSet model;
public SortedListModel()
{
model = new TreeSet();
}
public int getSize()
{
return model.size();
}
public Object getElementAt(int index)
{
return model.toArray()[index];
}
public void add(Object element)
{
if (model.add(element))
{
fireContentsChanged(this, 0, getSize());
}
}
public void addAll(Object elements[])
{
Collection c = Arrays.asList(elements);
model.addAll(c);
fireContentsChanged(this, 0, getSize());
}
public void clear()
{
model.clear();
fireContentsChanged(this, 0, getSize());
}
public boolean contains(Object element)
{
return model.contains(element);
}
public Object firstElement()
{
return model.first();
}
public Iterator iterator()
{
return model.iterator();
}
public Object lastElement()
{
return model.last();
}
public boolean removeElement(Object element)
{
boolean removed = model.remove(element);
if (removed)
{
fireContentsChanged(this, 0, getSize());
}
return removed;
}
}
The array list is set beforehand and values assigned with list.add("abc")
, etc. Then we iterate the array and add numeric to each element so it's 1. abc, etc.
ArrayList<String>list = null;
String[] arr;
Sample of Call to use this class is:
dual = new DualListBox();
arr = SharedFunctions.appendToArray(list, 0);
dual.addSourceElements(arr);
content.add(dual);
The shared function in question just adds the increment and starts the counter at 0.
public static String[] appendToArray(ArrayList<String> list, int count)
{
count++;
String[] temp = new String[list.size()];
for (int i = 0; i < temp.length; i++)
{
temp[i] = count + ". " + list.get(i);
count++;
}
return temp;
}
If you have any questions please let me know and if you can help me figure out how to fix this so it does a proper numeric sort, i would really appreciate it! :)
回答1:
You should separate the "index" from the "value" so you can customise the sort to work only on the "index" value, ultimately how you do that is up to you, for example, if you want to specify the index of the value, you could pass the two parameters to the model separately, this would allow the model to wrap the values in a POJO which it can manage itself, for example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Objects;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
SortedListModel model = new SortedListModel();
setLayout(new BorderLayout());
add(new JScrollPane(new JList(model)));
Random rnd = new Random();
for (int index = 0; index < 100; index++) {
int value = rnd.nextInt(100);
model.add(value, "This is some data for " + index);
}
}
public class SortedListModel extends AbstractListModel {
private SortedSet<Data> model;
public SortedListModel() {
model = new TreeSet<>(new Comparator<Data>() {
@Override
public int compare(Data o1, Data o2) {
return o1.getIndex() - o2.getIndex();
}
});
}
public void add(int index, Object value) {
Data data = new Data(index, value);
if (!model.contains(data)) {
model.add(data);
// int insertIndex = new ArrayList<Data>(model).indexOf(data);
int insertIndex = model.headSet(data).size();
fireIntervalAdded(data, insertIndex, insertIndex);
}
}
@Override
public int getSize() {
return model.size();
}
@Override
public Object getElementAt(int index) {
return model.toArray()[index];
}
protected class Data {
private int index;
private Object value;
public Data(int index, Object data) {
this.index = index;
this.value = data;
}
public Object getValue() {
return value;
}
public int getIndex() {
return index;
}
@Override
public String toString() {
return getIndex() + ". " + getValue();
}
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + this.index;
hash = 97 * hash + Objects.hashCode(this.value);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Data other = (Data) obj;
if (this.index != other.index) {
return false;
}
if (!Objects.equals(this.value, other.value)) {
return false;
}
return true;
}
}
}
}
}
If the index is unimportant (and is just a rendering side effect), you could use a custom ListCellRenderer
instead or a row header in the JScrollPane
to render the "line" numbers, further separating the two concepts
来源:https://stackoverflow.com/questions/35666648/sortedlistmodel-and-jlist-numerical-sort