JSpinner动态更新,如何删除元素?

时间:2012-10-01 14:10:33

标签: java swing jspinner

我有一个带有 SpinnerListModel JSpinner 。我想要做的是,一旦列表加载到模型中并且JSpiner在框架中显示,就应该可以从微调器中移除元素。只需抓住同一框架上的按钮即可完成。 click操作的处理程序将删除微调器上当前选定的元素。 我当前实现的问题是,当这个处理程序返回时,spinner中有一个 IndexOutOfBoundsExeception (当我从列表中删除最后一个元素时),这表明JSpinner不是更新。

我创建了一个新类 ExtendedSpinner ,它扩展了 JSpinner ,只使用了fireStateChanged。 这是为了在删除元素时更新 JSpinner 。它适用于删除列表中间的元素,但不适用于最后一个元素。

我做错了什么?这是代码:

package image;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerModel;

public class ImageDealer2 {

protected JFrame selectCoverFrame;
protected JExtendedSpinner spinnerCovers;
protected JButton deleteCoverButton;
protected SpinnerListModel spinnerCoversM;
protected ArrayList<Object> stringList = new ArrayList<Object>();

public ImageDealer2() {
selectFrameInit();
}


public void selectFrameInit(){

selectCoverFrame = new JFrame("Select");
selectCoverFrame.setSize(new Dimension(500,100));
selectCoverFrame.getContentPane().setLayout(new    BoxLayout(selectCoverFrame.getContentPane(),BoxLayout.Y_AXIS));


stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("d");

spinnerCoversM = new SpinnerListModel(stringList);
spinnerCovers = new JExtendedSpinner(spinnerCoversM);

deleteCoverButton = new JButton("Delete current element");
DeleteCurrentCoverHandler deleteCurrentCoverHandler = new DeleteCurrentCoverHandler();
deleteCoverButton.addActionListener(deleteCurrentCoverHandler);

selectCoverFrame.getContentPane().add(spinnerCovers);
selectCoverFrame.getContentPane().add(deleteCoverButton);
selectCoverFrame.setVisible(true);
}



public class JExtendedSpinner extends JSpinner{

/**
 * 
 */
private static final long serialVersionUID = 6109392800971431371L;

public JExtendedSpinner() {
    super();
    // TODO Auto-generated constructor stub
}

public JExtendedSpinner(SpinnerModel model) {
    super(model);
    // TODO Auto-generated constructor stub
}

public void fireUpdate(){
    this.fireStateChanged();
}
}    

private class DeleteCurrentCoverHandler implements ActionListener {

public void actionPerformed(ActionEvent e) {
    if (stringList.size()>1){
        stringList.remove(spinnerCovers.getValue());
        spinnerCoversM.setList(stringList);
        spinnerCovers.setModel(spinnerCoversM);
        spinnerCovers.fireUpdate();
    } else{
        stringList.clear();
        selectCoverFrame.dispose();
    }

}
}
}

2 个答案:

答案 0 :(得分:0)

我认为你过于复杂,你不应该扩展JSpinner。

启动程序时,请确保在创建JSpinner之前添加值:

    //create the list   
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");

    //make sure you set the model to the list
    jSpinner.setModel(new javax.swing.SpinnerListModel(stringList));

你应该像这样创建事件(先做其他事情):

    jSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
        public void stateChanged(javax.swing.event.ChangeEvent evt) {
            stateChanged(evt);
        }
    });

stateChanged(evt)方法应如下所示:

    //Get selected item/object
    Object selected = jSpinner.getValue();
    //Remove selected item/object
    stringList.remove(selected);

答案 1 :(得分:0)

你很亲密 在列表中添加和删除元素时,您确实需要触发事件,但这是模型的责任,而不是微调器。所以你必须实现自己的模型 另一个问题是当清单被清空时,微调器没有显示任何内容,这可能是你获得异常的原因。 所以你必须决定在微调器被清空时该怎么做。

例如,假设您想让微调器在空时被禁用,并在非空时返回启用状态。 正如我之前告诉你的那样,你必须实现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();
    }
}

如果要在微调器中添加或删除任何对象,则必须通过此模型执行此操作 对于任何其他&#34;只读&#34;尽管可以采取行动(例如isEmpty()size()),但您可以调用模型的getList()
也许这是一个比预期更大的解决方案,但它可以重复使用。