Вы близки.
Вам действительно нужно запускать событие при добавлении и удалении элементов из списка, но за это отвечает модель, а не счетчик. Поэтому вам нужно реализовать свою собственную модель.
Другая проблема заключается в том, что когда список опустошается, счетчику нечего отображать, и, вероятно, поэтому вы получаете исключение.
Итак, вам нужно решить, что делать, когда спиннер опустеет.
Скажем, например, вы хотите, чтобы счетчик отключался, когда он пуст, и снова включался, когда он не пуст.
Как я уже говорил вам ранее, вы должны реализовать свой SpinnerListModel
, чтобы вручную запускать события для добавление и удаление. Но теперь вы также хотите, чтобы счетчик отключался и включался в соответствии с моделью. Таким образом, вы можете реализовать модель для получения ссылки на счетчик...
Ниже приведен пример кода:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerListModel;
public class ImageDealer2 {
public static class RemoveSpinnerListModel extends SpinnerListModel {
private static final String VALUE_OF_EMPTY_LIST = ""; //This value indicates the spinner is empty.
protected JSpinner spin; //The spinner which this model referes to.
private boolean empty; //indicates if the list spinner is empty.
//The spinner is empty if it contains only the VALUE_OF_EMPTY_LIST value.
public RemoveSpinnerListModel() {
super(new ArrayList(Arrays.asList(VALUE_OF_EMPTY_LIST))); //We initialize to an "empty" read-write list.
empty = true; //The spinner does not contain any valid value.
}
public void setSpinner(final JSpinner spin) {
this.spin = Objects.requireNonNull(spin); //Just a null check plus assignment.
//We ensure the list has at least one element in it (the VALUE_OF_EMPTY_LIST):
if (getList().isEmpty())
((List)getList()).add(VALUE_OF_EMPTY_LIST);
//The spinner is empty if and only if the list contains only the VALUE_OF_EMPTY_LIST.
empty = getList().size() == 1 && getList().get(0).equals(VALUE_OF_EMPTY_LIST);
//We enable/disable the spinner accordingly:
spin.setEnabled(!empty);
if (empty) //If the spinner is empty of valid values:
spin.setValue(VALUE_OF_EMPTY_LIST); //then we add the VALUE_OF_EMPTY_LIST.
}
public void add(final Object value) {
if (empty) //If the spinner contains only the VALUE_OF_EMPTY_LIST, then:
getList().clear(); //Remove the VALUE_OF_EMPTY_LIST string.
((List)getList()).add(value); //Add the requested value.
if (spin != null) {
spin.setEnabled(true); //Enable the spinner for sure, because now it has at least one valid value.
spin.setValue(value);
}
empty = false; //The spinner is surely not empty.
fireStateChanged(); //Important step: updates the spinner via firing an event in the model.
}
public void remove(final Object value) {
if (!getList().isEmpty()) { //If there is something to remove.
getList().remove(value); //Remove the requested value.
if (getList().isEmpty()) //If now the list is empty, then we mark the spinner as empty:
markTheSpinnerAsEmpty();
else //Else the list still contains valid elements, so we mark the spinner as not-empty:
empty = false;
}
else //Else, the list is empty, so nothing to remove and the spinner must be marked as empty:
markTheSpinnerAsEmpty();
if (spin != null)
spin.setEnabled(!empty);
fireStateChanged(); //Important step: updates the spinner via firing an event in the model.
}
public void clear() {
getList().clear(); //Remove everything for sure.
markTheSpinnerAsEmpty();
}
private void markTheSpinnerAsEmpty() {
((List)getList()).add(VALUE_OF_EMPTY_LIST);
if (spin != null) {
spin.setValue(VALUE_OF_EMPTY_LIST); //Let's show the user that nothing is here.
spin.setEnabled(false);
}
empty = true;
}
}
protected JFrame selectCoverFrame;
protected JSpinner spinnerCovers;
protected JButton deleteCoverButton;
protected RemoveSpinnerListModel spinnerCoversM;
public ImageDealer2() {
selectFrameInit();
}
private void selectFrameInit() {
selectCoverFrame = new JFrame("Select");
selectCoverFrame.setSize(new Dimension(500, 100));
selectCoverFrame.getContentPane().setLayout(new BoxLayout(selectCoverFrame.getContentPane(), BoxLayout.Y_AXIS));
spinnerCoversM = new RemoveSpinnerListModel();
spinnerCoversM.add("a");
spinnerCoversM.add("b");
spinnerCoversM.add("c");
spinnerCoversM.add("d");
spinnerCovers = new JSpinner(spinnerCoversM);
spinnerCoversM.setSpinner(spinnerCovers); //DO NOT forget this step!
deleteCoverButton = new JButton("Delete current element");
DeleteCurrentCoverHandler deleteCurrentCoverHandler = new DeleteCurrentCoverHandler();
deleteCoverButton.addActionListener(deleteCurrentCoverHandler);
final JButton addButton = new JButton("Add an element");
AddANewCoverHandler addANewCoverHandler = new AddANewCoverHandler();
addButton.addActionListener(addANewCoverHandler);
final JPanel buttonPanel = new JPanel(); //FlowLayout.
buttonPanel.add(deleteCoverButton);
buttonPanel.add(addButton);
selectCoverFrame.getContentPane().add(spinnerCovers);
selectCoverFrame.getContentPane().add(buttonPanel);
selectCoverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //With this call, when you close the frame, then the application gets terminated.
selectCoverFrame.setLocationRelativeTo(null); //With this call, the frame gets to the center of the screen.
selectCoverFrame.setVisible(true);
}
private class DeleteCurrentCoverHandler implements ActionListener {
@Override
public void actionPerformed(final ActionEvent e) {
spinnerCoversM.remove(spinnerCovers.getValue());
}
}
private class AddANewCoverHandler implements ActionListener {
@Override
public void actionPerformed(final ActionEvent e) {
spinnerCoversM.add(JOptionPane.showInputDialog("Enter the new element string:"));
}
}
public static void main(final String[] args) {
new ImageDealer2();
}
}
Если вы хотите добавить или удалить какие-либо объекты из счетчика, вы должны сделать это с помощью этой модели.
Однако для любого другого действия «только для чтения» (например, isEmpty()
и size()
) вы можете вызвать getList()
из модель.
Возможно, это решение больше, чем ожидалось, но его можно использовать повторно.
person
gthanop
schedule
04.04.2018
SpinnerListModel
просто хранит ссылку на список, переданный в конструкторе, поэтому достаточно просто удалить элемент из списка и запустить событие. Нет необходимости снова вызыватьsetList
иsetModel
. Это может даже решить вашу проблему, но я не уверен в этом. Обратите внимание, что мне не очень нравится иметь список, который поддерживает модель, но который вы не можете изменить, не запуская события. Я предпочитаю модель, которая может сама о себе позаботиться и сама запускать события. - person Robin   schedule 01.10.2012