Java Swing заставляет JSpinner перестать добавлять

Я сейчас работаю над небольшим проектом для школы, и у меня огромная проблема с JSpinners, которые я использую. У меня есть три JSpinner, максимальное значение которых равно 8, но все числа трех JSpinner вместе не должны превышать 20. Итак, скажем, три Spinners - это A, B и C, а у меня A и B уже переключены полностью до 8, тогда C должен идти только до 4. Если я переключу A обратно на 4, я смогу переключить все C до 8 и так далее. Проблема в том, что я не могу найти какой-либо метод в JSpinner, поддерживающий это. Если кто-нибудь знает, как мне этого добиться, я был бы очень благодарен.

3 ответа

Вы можете подкласс JSpinner и переопределить getNextValue, ничего не делать (return null) в случае, если следующее значение будет слишком большим, делайте все как обычно (return super.getNextValue()) если это не так.

Зарегистрировать ChangeListener на каждом из JSpinner,

Когда ChangeEvent происходит, просто пересчитать текущую сумму.

Вот пример:

import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Spinners implements ChangeListener {

    private int currentTotal = 15;
    private final int maxTotal = 20;
    private final JSpinner[] spins = new JSpinner[3];

    public Spinners() {

        JFrame frame = new JFrame();
        JPanel content = new JPanel(new GridLayout(3, 1));

        for (int i = 0; i < 3; i++) {

            SpinnerModel model = new SpinnerNumberModel(5, //initial value
                    1, //min
                    10, //max
                    1); //step
            JSpinner spinner = new AutoBlockSpinner();
            spinner.setModel(model);
            spinner.addChangeListener(this);
            spins[i] = spinner;
            content.add(spinner);
        }

        computeCurrentTotal();

        frame.setContentPane(content);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();

    }

    private void computeCurrentTotal() {

        currentTotal = 0;

        for (JSpinner spin : spins) {

            currentTotal += (Integer) spin.getModel().getValue();
        }

    }

    @Override
    public void stateChanged(final ChangeEvent e) {

        computeCurrentTotal();

    }

    public static void main(final String[] args) {

        Spinners spinners = new Spinners();

    }

    class AutoBlockSpinner extends JSpinner {

        @Override
        public Object getNextValue() {

            if (currentTotal + 1 <= maxTotal) {
                return super.getNextValue();
            } else {
                return null;
            }

        }

    }

}

Вот подход, который создает обычай SpinnerModel, Каждая модель затем связывается с другими моделями, образуя группу.

В основном код переопределяет getNextValue() метод SpinnerModel чтобы определить, находитесь ли вы на максимуме или нет. Значение обновляется только тогда, когда вы находитесь ниже максимума группы.

Вы можете увеличить счетчики только до 10:

import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;

public class GroupSpinner
{
    private int groupMaximum;

    private List<GroupSpinnerNumberModel> models = new ArrayList<GroupSpinnerNumberModel>();

    public GroupSpinner(int maximum)
    {
        this.groupMaximum = maximum;
    }

    public SpinnerNumberModel createGroupModel(int value, int minimum, int maximum, int step)
    {
        GroupSpinnerNumberModel model = new GroupSpinnerNumberModel(value, minimum, maximum, step, this);
        models.add( model );

        return model;
    }

    public Object getNextValue(int currentValue, int step)
    {
        int maximum = getGroupValue() + step;

        if (maximum > groupMaximum)
        {
            return currentValue;
        }
        else
        {
            groupValueUpdated(maximum);
            int nextValue = currentValue + step;
            return nextValue;
        }
    }

    public int getGroupValue()
    {
        int maximum = 0;

        for (GroupSpinnerNumberModel model: models)
        {
            maximum += model.getNumber().intValue();
        }

        return maximum;
    }

    private void groupValueUpdated(int value)
    {
        System.out.println(value);
    }

    public class GroupSpinnerNumberModel extends SpinnerNumberModel
    {
        private GroupSpinner model;

        public GroupSpinnerNumberModel(int value, int minimum, int maximum, int step, GroupSpinner model)
        {
            super(value, minimum, maximum, step);

            this.model = model;
        }

        public Object getNextValue()
        {
            int currentValue = super.getNumber().intValue();
            int step = super.getStepSize().intValue();

            return model.getNextValue(currentValue, step);
        }
    }

    private static void createAndShowGUI()
    {
        JPanel panel = new JPanel( new GridLayout(0, 1) );

        GroupSpinner group = new GroupSpinner(10);

        JSpinner number1 = new JSpinner( group.createGroupModel(0, 0, 10, 1) );
        panel.add(number1);
        panel.add( new JSpinner( group.createGroupModel(0, 0, 10, 1) ) );
        panel.add( new JSpinner( group.createGroupModel(0, 0, 10, 1) ) );
        panel.add( new JSpinner( group.createGroupModel(0, 0, 10, 1) ) );

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }

}

Вы можете создать JSpinnerModel следующим образом:

SpinnerModel sm = new SpinnerNumberModel(0, 0, 8, 1);
JSpinner spinner = new JSpinner(sm);

Вам нужен слушатель изменений для всех JSpinners. Когда вы увеличиваете или уменьшаете Spinner, вы увеличиваете / уменьшаете сумму всех Spinner. Вы можете добавить Change Listener следующим образом:

aSpinner.addChangeListener(new ChangeListener(){
    @Override
    public void stateChanged(ChangeEvent event) {
    //count and update here
    }
});

Затем вы перебираете JSpinner и создаете новую SpinnerModel для каждого из них с новым максимальным значением и устанавливаете его в JSpinner.

Например: A:8, B:7, C:0. Теперь вы увеличиваете B до 8, а затем - до 16. Вы создаете новую SpinnerModel и добавляете ее в JSpinner для C:

 SpinnerModel sm = new SpinnerNumberModel(0, 0, 20-16, 1);
 cSpinner.setModel(sm);

Надеюсь, это поможет!

Другие вопросы по тегам