I'm getting ArrayList from intent. I insert that ArrayList, to every item I create into RecyclerView like this:
mGameItemList = new ArrayList<>();
/** Set selected names into the recyclerview **/
for (int i = 0; i < ActivityNewGame.mCheckedBoxes.size(); i++) {
mGameItemList.add(new GameItem(getIntent().getStringArrayListExtra("PARNUMBERSINDIVIDUALLY"), ActivityNewGame.mCheckedBoxes.get(i), getIntent().getStringArrayListExtra("PARNUMBERSINDIVIDUALLY").get(0), R.drawable.ic_minus, R.drawable.ic_plus, "TTL :", "0"));
}
This is that GameItem:
public class GameItem {
private ArrayList<String> mParNumbersIndividually;
private String mText1, mText2, mText3, mText4;
private int mImageMinus, mImagePlus;
public GameItem(ArrayList<String> parNumbersIndividually, String text1, String text2, int imageMinus, int imagePlus, String text3, String text4) {
mParNumbersIndividually = parNumbersIndividually;
mText1 = text1;
mText2 = text2;
mImageMinus = imageMinus;
mImagePlus = imagePlus;
mText3 = text3;
mText4 = text4;
}
public ArrayList<String> getAllParNumbers() {
return mParNumbersIndividually;
}
public void setAllParnumbers(int position, String newNumber) {
mParNumbersIndividually.set(position, newNumber);
}
public String getText1() {
return mText1;
}
public String getText2() {
return mText2;
}
public void changeText2(String text) {
mText2 = text;
}
public int getImageMinus() {
return mImageMinus;
}
public int getImagePlus() {
return mImagePlus;
}
public String getText3() {
return mText3;
}
public String getText4() {
return mText4;
}
public void changeText4(String text) {
mText4 = text;
}
}
The layout that this Activity uses:
The number of player throws (green background number) comes from that intended list. Its okay when I create hole 1, that it uses first numbers straight from that intended list, but when I go on, I have to make every item use its own ArrayList and manipulate those numbers with new numbers, so my question is, how I make my Items use their own ArrayLists for getting that green background number?
I tried to implement my own JSpinner model to accept an enumeration (including I18N), so I did like that:
searchSpinner.setModel(new AbstractSpinnerModel() {
int index = 0;
int minIndex = 0;
int maxIndex = MY_ENUM.values().length - 1;
Object selected = MY_ENUM.values()[index];
#Override
public Object getValue() {
return selected;
}
#Override
public void setValue(Object value) {
selected = value;
fireStateChanged();
}
#Override
public Object getNextValue() {
if (index < maxIndex) {
index++;
}
fireStateChanged();
return MY_ENUM.values()[index];
}
#Override
public Object getPreviousValue() {
if (index > minIndex) {
index--;
}
fireStateChanged();
return MY_ENUM.values()[index];
}
#Override
public void addChangeListener(ChangeListener l) {
}
#Override
public void removeChangeListener(ChangeListener l) {
}
});
The problem is that did not work, and even the spinner list looks like disabled. What am I doing wrong?
UPDATE: Based on first answer
You should extend from AbstractSpinnerModel (note to folks new to his question -- note that his original question had the class implementing the SpinnerModel interface. He later changed his code to reflect my recommendation) and be sure to call the fireStateChanged() method when appropriately. Also you've not taken into account edge cases and beyond edge cases.
e.g.,
import javax.swing.*;
import javax.swing.JSpinner.DefaultEditor;
public class MySpinnerPanel extends JPanel {
public static void main(String[] args) {
JSpinner spinner = new JSpinner(new MyEnumSpinnerModel());
JSpinner.DefaultEditor editor = (DefaultEditor) spinner.getEditor();
editor.getTextField().setColumns(5);
JPanel panel = new JPanel();
panel.add(spinner);
JOptionPane.showMessageDialog(null, panel);
}
}
enum MyEnum {
FE, FI, FO, FUM, FOO, FUBAR, SPAM
}
class MyEnumSpinnerModel extends AbstractSpinnerModel {
private int index = 0;
#Override
public Object getValue() {
return MyEnum.values()[index];
}
#Override
public void setValue(Object value) {
if (value instanceof MyEnum) {
index = ((MyEnum) value).ordinal();
fireStateChanged();
} else {
String text = value.toString() + " is not a valid enum item";
throw new IllegalArgumentException(text);
}
}
#Override
public Object getNextValue() {
if (index >= MyEnum.values().length - 1) {
return null;
} else {
return MyEnum.values()[index + 1];
}
}
#Override
public Object getPreviousValue() {
if (index <= 0) {
return null;
} else {
return MyEnum.values()[index - 1 ];
}
}
}
Edit
Note that the model itself should not require a listener to notify the view (as per the other answer to this question) as that's what the AbstractSpinnerModel does internally. It's fireStateChange() method is what the model itself should call to trigger this notification, same as most all other similar model structures in Swing such as any TableModel object that you create that derives from the AbstractTableModel. For details, please see the source code for the SpinnerListModel. Your code should emulate this class.
You should use ChangeListener to notify the view of changes in the model.
spinner = new JSpinner(new SpinnerModel() {
private ChangeListener l;
#Override
public void setValue(Object value) {
...
if(l != null) {
l.stateChanged(new ChangeEvent(this));
}
}
...
#Override
public void addChangeListener(ChangeListener l) {
this.l = l;
}
#Override
public void removeChangeListener(ChangeListener l) {
if(this.l == l) {
this.l = null;
}
}
});
Edit: You can use List to register many listeners.
Below is my code that displays images in a JList. I want to edit the description by each of the images shown in the JList. I don't know how to do it & need help. Thanks...
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Serializable;
public class DesignPicture2 {
private static String imageName;
static ArrayList<String> imgName = new ArrayList<String>();
public static void main(String[] args) throws Exception {
DesignPicture2 mm = new DesignPicture2();
mm.getImageName("C:\\Images 2 display");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("Image panel");
frame.setSize(800, 500);
//frame.setLocationByPlatform(true);
frame.setLocation(600, 300);
JList imageList = createImageList();
frame.getContentPane().add(new JScrollPane(imageList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JList createImageList() {
JList imageList = new JList(createModel("C:\\Images 2 display"));
imageList.setCellRenderer(new ImageCellRenderer());
imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
imageList.setVisibleRowCount(0);
imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imageList.setFixedCellWidth(240);
imageList.setFixedCellHeight(120);
// imageList.setDragEnabled(false);
//imageList.setDropMode(DropMode.INSERT);
imageList.setTransferHandler(new ImageTransferHandler(imageList));
return imageList;
}
private static DefaultListModel createModel(String path) {
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultListModel model = new DefaultListModel();
int count = 0;
for (int i = 0; i < listOfFiles.length - 1; i++) {
System.out.println("check path: " + listOfFiles[i]);
imageName = imgName.get(i).toString();
String name = listOfFiles[i].toString();
//load only JPEGS
if (name.endsWith("jpg")) {
try {
ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
model.add(count, ii);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return model;
}
static class ImageTransferHandler extends TransferHandler {
private static final DataFlavor DATA_FLAVOUR = new DataFlavor(ColorIcon.class, "Images");
private final JList previewList;
private boolean inDrag;
ImageTransferHandler(JList previewList) {
this.previewList = previewList;
}
public int getSourceActions(JComponent c) {
return TransferHandler.MOVE;
}
protected Transferable createTransferable(JComponent c) {
inDrag = true;
return new Transferable() {
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DATA_FLAVOUR};
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DATA_FLAVOUR);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return previewList.getSelectedValue();
}
};
}
public boolean canImport(TransferSupport support) {
if (!inDrag || !support.isDataFlavorSupported(DATA_FLAVOUR)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
if (dl.getIndex() == -1) {
return false;
} else {
return true;
}
}
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
Transferable transferable = support.getTransferable();
try {
Object draggedImage = transferable.getTransferData(DATA_FLAVOUR);
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
DefaultListModel model = (DefaultListModel) previewList.getModel();
int dropIndex = dl.getIndex();
if (model.indexOf(draggedImage) < dropIndex) {
dropIndex--;
}
model.removeElement(draggedImage);
model.add(dropIndex, draggedImage);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
protected void exportDone(JComponent source, Transferable data, int action) {
super.exportDone(source, data, action);
inDrag = false;
}
}
static class ImageCellRenderer extends JPanel implements ListCellRenderer {
int count = 0;
DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
JLabel imageLabel = new JLabel();
JLabel descriptionLabel = new JLabel();
ImageCellRenderer() {
setLayout(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
imageLabel.setBorder(emptyBorder);
descriptionLabel.setBorder(emptyBorder);
add(imageLabel, BorderLayout.AFTER_LINE_ENDS);
add(descriptionLabel, BorderLayout.SOUTH);
// imageLabel.setText(imgName.get(0).toString());
}
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
setBorder(defaultListCellRenderer.getBorder());
setBackground(defaultListCellRenderer.getBackground());
imageLabel.setIcon((Icon) value);
if (count > imgName.size() - 1) {
count = 0;
} else {
descriptionLabel.setText(imgName.get(count).toString());
}
return this;
}
}
public void getImageName(String path) {
int c = 0;
final File dir = new File(path);
// array of supported extensions (use a List if you prefer)
final String[] EXTENSIONS = new String[]{
"jpg", "gif", "png", "bmp" // and other formats you need
// filter to identify images based on their extensions
};
final FilenameFilter IMAGE_FILTER = new FilenameFilter() {
#Override
public boolean accept(final File dir, final String name) {
for (final String ext : EXTENSIONS) {
if (name.endsWith("." + ext)) {
return (true);
}
}
return (false);
}
};
if (dir.isDirectory()) { // make sure it's a directory
for (final File f : dir.listFiles(IMAGE_FILTER)) {
BufferedImage img = null;
c++;
try {
img = ImageIO.read(f);
// you probably want something more involved here
// to display in your UI
System.out.println("image: " + f.getName());
imgName.add(f.getName().toString());
} catch (final IOException e) {
// handle errors here
System.out.println("Error!");
}
}
System.out.println("C: " + c);
} else {
System.out.println("Invalid Directory!");
}
}
static class ColorIcon implements Icon, Serializable {
private Color color;
ColorIcon(Color color) {
this.color = color;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
g.fillRect(x, y, getIconWidth(), getIconHeight());
}
public int getIconWidth() {
return 200;
}
public int getIconHeight() {
return 100;
}
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
return color.equals(((ColorIcon) o).color);
}
}
}
When I run the above code, it show the image in proper way, but the description of each image is fixed and I don't know how to change it. Hope anyone can help me.
I agree with trashgod (+1 to his suggestion), a JTable will be a simpler solution, here's why...
JList doesn't support editability, so you'd need to create it...
So, first, we'd need some kind of ListModel that provided some additional functionality, in particular, the ability to set the value at a particular index...
import javax.swing.ListModel;
public interface MutableListModel<E> extends ListModel<E> {
public void setElementAt(E value, int index);
public boolean isCellEditable(int index);
}
Next, we'd need some kind editor, in this case, following standard Swing API conventions, this asks for some kind of base interface
import java.awt.Component;
import javax.swing.CellEditor;
import javax.swing.JList;
public interface ListCellEditor<E> extends CellEditor {
public Component getListCellEditorComponent(
JList<E> list,
E value,
boolean isSelected,
int index);
public void applyEditorValue(E value);
}
Now, we need to create ourselves a custom JList capable of actually performing all the required functionality of editing a cell value...
Things like...
Recognising a "start editing" event
Determine if the cell can be edited
Managing the editing process, preparing and showing the editor, knowing when the editor has stopped or canceled and clean up appropriately...
Handling selection changes while editing is in progress
Handling component focus change (which I've not done cause that's an awesome amount of fun in itself...)
For example...
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JList;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class EditableList<E> extends JList<E> {
private ListCellEditor<E> editor;
private int editingCell = -1;
private Component editorComponent;
private CellEditorHandler handler;
public EditableList(MutableListModel<E> model) {
this();
setModel(model);
}
public EditableList() {
InputMap im = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "editorCell");
ActionMap am = getActionMap();
am.put("editorCell", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Edit baby");
int cell = getSelectedIndex();
editCellAt(cell);
}
});
addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (isEditing()) {
if (!stopCellEditing()) {
cancelCellEditing();
}
}
}
});
}
public boolean isEditing() {
return editorComponent != null;
}
public void cancelCellEditing() {
getEditor().cancelCellEditing();
}
public boolean stopCellEditing() {
return getEditor().stopCellEditing();
}
public CellEditorHandler getCellEditorHandler() {
if (handler == null) {
handler = new CellEditorHandler();
}
return handler;
}
public void setEditor(ListCellEditor<E> value) {
if (value != editor) {
ListCellEditor old = editor;
editor = value;
firePropertyChange("editor", old, editor);
}
}
public ListCellEditor<E> getEditor() {
return editor;
}
public boolean isCellEditable(int cell) {
boolean isEditable = false;
ListModel model = getModel();
if (model instanceof MutableListModel) {
MutableListModel mcm = (MutableListModel) model;
isEditable = mcm.isCellEditable(cell);
}
return isEditable;
}
protected void editCellAt(int index) {
if (isCellEditable(index)) {
ListCellEditor<E> editor = getEditor();
if (editor != null) {
Rectangle cellBounds = getCellBounds(index, index);
E value = getModel().getElementAt(index);
boolean selected = isSelectedIndex(index);
editingCell = index;
editor.addCellEditorListener(getCellEditorHandler());
editorComponent = editor.getListCellEditorComponent(this, value, selected, index);
editorComponent.setBounds(cellBounds);
ensureIndexIsVisible(index);
add(editorComponent);
revalidate();
}
}
}
public int getEditingCell() {
return editingCell;
}
protected void editingHasStopped(ListCellEditor editor) {
editingCell = -1;
if (editorComponent != null) {
remove(editorComponent);
}
if (editor != null) {
editor.removeCellEditorListener(getCellEditorHandler());
}
}
public class CellEditorHandler implements CellEditorListener {
#Override
public void editingStopped(ChangeEvent e) {
E value = getModel().getElementAt(getEditingCell());
getEditor().applyEditorValue(value);
((MutableListModel) getModel()).setElementAt(value, getEditingCell());
editingHasStopped((ListCellEditor)e.getSource());
}
#Override
public void editingCanceled(ChangeEvent e) {
editingHasStopped((ListCellEditor)e.getSource());
}
}
}
Now, having done all that, you will need change the way you've structured your program, instead of using a List and ListModel to manage the descriptions and images separately, you should probably merge the concept into a single, manageable object, for example...
public class ImagePreview {
private String name;
private ImageIcon image;
public ImagePreview(String name, ImageIcon image) {
this.name = name;
this.image = image;
}
public String getDescription() {
return name;
}
public ImageIcon getImage() {
return image;
}
protected void setDescription(String description) {
this.name = description;
}
}
Even if you choose to use a JTable instead, you'll find this easier to manage...
Now we need some way to render and edit these values, to this end, I choose to start with a base component which could display the image and text...
public class ImagePreviewPane extends JPanel {
private JLabel imageLabel = new JLabel();
private JLabel descriptionLabel = new JLabel();
public ImagePreviewPane() {
setLayout(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
imageLabel.setBorder(emptyBorder);
descriptionLabel.setBorder(emptyBorder);
add(imageLabel, BorderLayout.CENTER);
add(descriptionLabel, BorderLayout.SOUTH);
}
protected JLabel getDescriptionLabel() {
return descriptionLabel;
}
protected JLabel getImageLabel() {
return imageLabel;
}
public void setImage(ImageIcon icon) {
imageLabel.setIcon(icon);
}
public void setDescription(String text) {
descriptionLabel.setText(text);
}
}
Create an extended version that could handle editing...
public static class ImagePreviewEditorPane extends ImagePreviewPane {
private JTextField editor;
public ImagePreviewEditorPane() {
super();
editor = new JTextField();
remove(getDescriptionLabel());
add(editor, BorderLayout.SOUTH);
}
#Override
public void setDescription(String text) {
editor.setText(text);
}
public String getDescription() {
return editor.getText();
}
public void setImagePreview(ImagePreview preview) {
setImage(preview.getImage());
setDescription(preview.getDescription());
}
#Override
public void addNotify() {
super.addNotify();
editor.requestFocusInWindow();
}
}
This is done to try and make it easier to modify the components later...
Next, a ListCellRenderer
public class ImageCellRenderer extends ImagePreviewPane implements ListCellRenderer {
public ImageCellRenderer() {
}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(this, getUI(), "List.dropCellBackground");
fg = DefaultLookup.getColor(this, getUI(), "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
setBackground(bg == null ? list.getSelectionBackground() : bg);
setForeground(fg == null ? list.getSelectionForeground() : fg);
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
if (value instanceof ImagePreview) {
ImagePreview ip = (ImagePreview) value;
setImage(ip.getImage());
setDescription(ip.getDescription());
} else {
setImage(null);
setDescription("??");
}
setEnabled(list.isEnabled());
setFont(list.getFont());
return this;
}
}
And editor...
public class ImagePreviewListCellEditor extends AbstactListCellEditor<ImagePreview> {
private ImagePreviewEditorPane previewPane;
public ImagePreviewListCellEditor() {
previewPane = new ImagePreviewEditorPane();
InputMap im = previewPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "accept");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
ActionMap am = previewPane.getActionMap();
am.put("accept", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
am.put("cancel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
cancelCellEditing();
}
});
}
public void applyEditorValue(ImagePreview preview) {
preview.setDescription(previewPane.getDescription());
}
#Override
public Component getListCellEditorComponent(JList<ImagePreview> list, ImagePreview value, boolean isSelected, int index) {
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellBackground");
fg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
previewPane.setBackground(bg == null ? list.getSelectionBackground() : bg);
previewPane.setForeground(fg == null ? list.getSelectionForeground() : fg);
} else {
previewPane.setBackground(list.getBackground());
previewPane.setForeground(list.getForeground());
}
if (value instanceof ImagePreview) {
ImagePreview preview = (ImagePreview)value;
previewPane.setImagePreview(preview);
} else {
previewPane.setImagePreview(null);
}
return previewPane;
}
}
And finally, putting it altogether...
public class DesignPicture2 {
public static void main(String[] args) throws Exception {
DesignPicture2 mm = new DesignPicture2();
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("Image panel");
frame.setSize(800, 500);
frame.setLocation(600, 300);
JList imageList = createImageList();
frame.getContentPane().add(new JScrollPane(imageList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JList createImageList() {
EditableList<ImagePreview> imageList = new EditableList(createModel("..."));
imageList.setEditor(new ImagePreviewListCellEditor());
imageList.setCellRenderer(new ImageCellRenderer());
imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
imageList.setVisibleRowCount(0);
imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imageList.setFixedCellWidth(240);
imageList.setFixedCellHeight(120);
return imageList;
}
private static MutableListModel<ImagePreview> createModel(String path) {
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultMutableListModel<ImagePreview> model = new DefaultMutableListModel<>();
int count = 0;
for (int i = 0; i < listOfFiles.length - 1; i++) {
System.out.println("check path: " + listOfFiles[i]);
String name = listOfFiles[i].toString();
if (name.endsWith("jpg")) {
try {
ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
model.addElement(new ImagePreview(name, ii));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return model;
}
}
JList does not support the notion of a cell editor. Instead, use a two-column JTable. Some important points:
Your model's isCellEditable() implementation should return true for the description column in order to make it editable.
Your model's implementation of getColumnClass() can let the default renderer display your image by returning ImageIcon or Icon .
Having problems with the ComboBox, I have populated multiple ComboBoxes with the same model, but when I run my program and select a value from one ComboBox it selects the same value for the rest.
ComboHBoy.setModel(defaultComboBoxModel);
ComboHGirl.setModel(defaultComboBoxModel);
ComboDHBoy.setModel(defaultComboBoxModel);
ComboDHGirl.setModel(defaultComboBoxModel);
That's because they all are referenced to the same model, any change of the model will affect the all the other combos.
There is no way to solve this except that every combobox have it's own DefaultComboBoxModel.
private DefaultComboBoxModel hBoyModel= new DefaultComboBoxModel();
private DefaultComboBoxModel hGirlModel= new DefaultComboBoxModel();
//....
ComboHBoy.setModel(hBoyModel);
ComboHGirl.setModel(hGrilModel);
//....
Use just a ListModel to manage your data and create a ComboboxModel adapter that is based on the ListModel. This ComboboxModel will only add the selection capability. Remember that a ComboboxModel extends ListModel. So it is easy to adapt the interfaces.
The only tricky part is to handle the update events.
For example:
public class ListAdapterComboboxModel implements ComboBoxModel {
private ListModel dataModel;
private Object selectedObject;
private DataModelListDataListenerAdapter listDataListenerAdapter;
public ListAdapterComboboxModel(ListModel ListModel) {
dataModel = ListModel;
this.listDataListenerAdapter = new DataModelListDataListenerAdapter();
dataModel.addListDataListener(listDataListenerAdapter);
}
public int getSize() {
return dataModel.getSize();
}
public Object getElementAt(int index) {
return dataModel.getElementAt(index);
}
public void addListDataListener(ListDataListener l) {
listDataListenerAdapter.addListDataListener(l);
}
public void removeListDataListener(ListDataListener l) {
listDataListenerAdapter.removeListDataListener(l);
}
public void setSelectedItem(Object anObject) {
if ((selectedObject != null && !selectedObject.equals(anObject))
|| selectedObject == null && anObject != null) {
selectedObject = anObject;
ListDataEvent e = new ListDataEvent(this,
ListDataEvent.CONTENTS_CHANGED, -1, -1);
listDataListenerAdapter.delegateListDataEvent(e);
}
}
public Object getSelectedItem() {
return selectedObject;
}
private class DataModelListDataListenerAdapter implements ListDataListener {
protected EventListenerList listenerList = new EventListenerList();
public void removeListDataListener(ListDataListener l) {
listenerList.remove(ListDataListener.class, l);
}
public void addListDataListener(ListDataListener l) {
listenerList.add(ListDataListener.class, l);
}
public void intervalAdded(ListDataEvent e) {
delegateListDataEvent(e);
}
public void intervalRemoved(ListDataEvent e) {
checkSelection(e);
delegateListDataEvent(e);
}
public void contentsChanged(ListDataEvent e) {
checkSelection(e);
delegateListDataEvent(e);
}
private void checkSelection(ListDataEvent e) {
Object selectedItem = getSelectedItem();
ListModel listModel = (ListModel) e.getSource();
int size = listModel.getSize();
boolean selectedItemNoLongerExists = true;
for (int i = 0; i < size; i++) {
Object elementAt = listModel.getElementAt(i);
if (elementAt != null && elementAt.equals(selectedItem)) {
selectedItemNoLongerExists = false;
break;
}
}
if (selectedItemNoLongerExists) {
ListAdapterComboboxModel.this.selectedObject = null;
}
}
protected void delegateListDataEvent(ListDataEvent lde) {
ListDataListener[] listeners = listenerList
.getListeners(ListDataListener.class);
for (ListDataListener listDataListener : listeners) {
listDataListener.contentsChanged(lde);
}
}
}
}
And then just use it like this
public class ComboboxModelTest extends JFrame{
public static void main(String[] args) {
ComboboxModelTest comboboxModelTest = new ComboboxModelTest();
comboboxModelTest.pack();
comboboxModelTest.setVisible(true);
}
public ComboboxModelTest() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
DefaultListModel defaultListModel = new DefaultListModel();
defaultListModel.addElement("Element 1");
defaultListModel.addElement("Element 2");
ComboBoxModel firstComboboxModel = new ListAdapterComboboxModel(defaultListModel);
ComboBoxModel secondComboboxModel = new ListAdapterComboboxModel(defaultListModel);
JComboBox jComboBox1 = new JComboBox(firstComboboxModel);
JComboBox jComboBox2 = new JComboBox(secondComboboxModel);
contentPane.add(jComboBox1);
contentPane.add(jComboBox2);
}
}
Then you only have to manage the data in one ListModel and you have distinct selection models.
Also take a look at The MVC pattern and SWING.
I have following editor class, and I'm curious what's wrong with it. When running, it does correctly set the right radio button as selected. However, when flushing the top level editor, getValue is never called, and my object's property never get updated. Here's the code (hint - modified ValueListBox):
public class ValueRadioList<T> extends FlowPanel implements
HasConstrainedValue<T>, LeafValueEditor<T>, ValueChangeHandler<Boolean> {
private final List<T> values = new ArrayList<T>();
private final Map<Object, Integer> valueKeyToIndex =
new HashMap<Object, Integer>();
private final String name;
private final Renderer<T> renderer;
private final ProvidesKey<T> keyProvider;
private T value;
public ValueRadioList(Renderer<T> renderer) {
this(renderer, new SimpleKeyProvider<T>());
}
public ValueRadioList(Renderer<T> renderer, ProvidesKey<T> keyProvider) {
super();
this.name = DOM.createUniqueId();
this.keyProvider = keyProvider;
this.renderer = renderer;
}
private void addValue(T value) {
Object key = keyProvider.getKey(value);
if (valueKeyToIndex.containsKey(key)) {
throw new IllegalArgumentException("Duplicate value: " + value);
}
valueKeyToIndex.put(key, values.size());
values.add(value);
RadioButton radio = new RadioButton(name, renderer.render(value));
radio.addValueChangeHandler(this);
add(radio);
assert values.size() == getWidgetCount();
}
#Override public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<T> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
#Override public T getValue() {
return value;
}
#Override public void onValueChange(ValueChangeEvent<Boolean> event) {
int selectedIndex = -1;
for (int i = 0, l = getWidgetCount(); i < l; i++) {
if (((RadioButton) getWidget(i)).getValue()) {
selectedIndex = i;
break;
}
}
if (selectedIndex < 0) {
return; // Not sure why this happens during addValue
}
T newValue = values.get(selectedIndex);
setValue(newValue, true);
}
#Override public void setAcceptableValues(Collection<T> newValues) {
values.clear();
valueKeyToIndex.clear();
clear();
for (T nextNewValue : newValues) {
addValue(nextNewValue);
}
updateRadioList();
}
#Override public void setValue(T value) {
setValue(value, false);
}
#Override public void setValue(T value, boolean fireEvents) {
if (value == this.value
|| (this.value != null && this.value.equals(value))) {
return;
}
T before = this.value;
this.value = value;
updateRadioList();
if (fireEvents) {
ValueChangeEvent.fireIfNotEqual(this, before, value);
}
}
private void updateRadioList() {
Object key = keyProvider.getKey(value);
Integer index = valueKeyToIndex.get(key);
if (index == null) {
addValue(value);
}
index = valueKeyToIndex.get(key);
((RadioButton) getWidget(index)).setValue(true);
}
}
Solved it, my POJO missed a setter for that field.