Несколько JSliders активировать и деактивировать - Обмен значениями - PullRequest
0 голосов
/ 21 ноября 2018

Контекст

Я пишу фрагмент кода, имеющий 1+ ползунков.Эти ползунки образуют группу.Сумма значений ползунков этой группы всегда должна составлять 100. Однако, как НУЖНАЯ функция, пользователь может отключить и включить (добавить / удалить) ползунки из этой группы.Поэтому для этого необходимо, чтобы значения ползунков были правильно отрегулированы.

После попытки кодирования моей собственной группы я решил поискать лучший / протестированный и реализованный код.Он улучшился по сравнению с моим, однако появились некоторые проблемы.


Основная проблема

При добавлении или удалении ползунков путем выбора или отмены выбора флажок вызывает ошибки, и ползунки останавливаютсяза работой.Обратите внимание, что добавление в этом сценарии означает просто включение ранее отключенного ползунка (сняв флажок).

Example of the current issue


ПредварительныйРешение

Приведенный ниже код был найден в stackoverflow.Я реализовал в своем коде, но так как не могу опубликовать его, я решил настроить код, найденный в примере stackoverflow, для представления моего сценария.


Как?

Любая помощь очень ценится.Я не уверен, как подойти к решению этой проблемы, не вызывая больше ошибок.Я попытался заново настроить исчисление, выполненное в методе обновления, но это просто вызвало больше глупостей.Я не нахожу продуктивным размещение всех моих попыток здесь, потому что stackoverflow сказал бы, что это слишком много кода, и потому что я не уверен, что это поможет найти ответ.

Ссылки

https://stackoverflow.com/a/21391448/2280645


import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ConnectedSliders {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI() {
        JSlider s0 = new JSlider(0, 100, 30);
        JSlider s1 = new JSlider(0, 100, 40);
        JSlider s2 = new JSlider(0, 100, 30);

        SliderGroup sliderGroup = new SliderGroup();
        //sliderGroup.add(s0);
        //sliderGroup.add(s1);
        //sliderGroup.add(s2);

        JPanel panel = new JPanel(new GridLayout(0, 3));
        panel.add(s0);
        panel.add(createListeningLabel(s0));
        panel.add(createCheckBox(s0, sliderGroup));

        panel.add(s1);
        panel.add(createListeningLabel(s1));
        panel.add(createCheckBox(s1, sliderGroup));

        panel.add(s2);
        panel.add(createListeningLabel(s2));
        panel.add(createCheckBox(s2, sliderGroup));

        panel.add(createListeningLabel(s0, s1, s2));

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(panel);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static JLabel createListeningLabel(final JSlider... sliders) {
        final JLabel label = new JLabel("");
        for (JSlider slider : sliders) {
            slider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    int sum = 0;
                    for (JSlider slider : sliders) {
                        sum += slider.getValue();
                    }
                    label.setText("Sum: " + sum);
                }
            });
        }
        return label;
    }

    private static JLabel createListeningLabel(final JSlider slider) {
        final JLabel label = new JLabel("");
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                label.setText(String.valueOf(slider.getValue()));
            }
        });
        return label;
    }

    private static JCheckBox createCheckBox(final JSlider slider, SliderGroup group) {
        final JCheckBox checkBox = new JCheckBox();
        checkBox.setSelected(true);

        checkBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    group.add(slider);
                    slider.setEnabled(true);
                } else if(e.getStateChange() == ItemEvent.DESELECTED) {
                    group.remove(slider);
                    slider.setEnabled(false);
                }
            }
        });

        return checkBox;

    }

}

class SliderGroup {

    private final Map<JSlider, Integer> values;
    private final LinkedList<JSlider> candidates;

    private final ChangeListener changeListener;
    private boolean updating = false;

    SliderGroup() {
        this.values = new HashMap<JSlider, Integer>();
        this.candidates = new LinkedList<JSlider>();

        changeListener = new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                update(source);
            }
        };
    }

    private void update(JSlider source) {
        if (updating) {
            return;
        }
        updating = true;

        int delta = source.getValue() - values.get(source);
        if (delta > 0) {
            distributeRemove(delta, source);
        } else {
            distributeAdd(delta, source);
        }

        for (JSlider slider : candidates) {
            values.put(slider, slider.getValue());
        }

        updating = false;
    }

    private void distributeRemove(int delta, JSlider source) {
        int counter = 0;
        int remaining = delta;
        while (remaining > 0) {
            JSlider slider = candidates.removeFirst();
            counter++;

            if (slider == source) {
                candidates.addLast(slider);
            } else {
                if (slider.getValue() > 0) {
                    slider.setValue(slider.getValue() - 1);
                    remaining--;
                    counter = 0;
                }
                candidates.addLast(slider);
                if (remaining == 0) {
                    break;
                }
            }
            if (counter > candidates.size()) {
                String message = "Can not distribute " + delta + " among " + candidates;
                //System.out.println(message);
                //return;
                throw new IllegalArgumentException(message);
            }
        }
    }

    private void distributeAdd(int delta, JSlider source) {
        int counter = 0;
        int remaining = -delta;
        while (remaining > 0) {
            JSlider slider = candidates.removeLast();
            counter++;

            if (slider == source) {
                candidates.addFirst(slider);
            } else {
                if (slider.getValue() < slider.getMaximum()) {
                    slider.setValue(slider.getValue() + 1);
                    remaining--;
                    counter = 0;
                }
                candidates.addFirst(slider);
                if (remaining == 0) {
                    break;
                }
            }
            if (counter > candidates.size()) {
                String message = "Can not distribute " + delta + " among " + candidates;
                //System.out.println(message);
                //return;
                throw new IllegalArgumentException(message);
            }
        }
    }

    void add(JSlider slider) {
        candidates.add(slider);
        values.put(slider, slider.getValue());
        slider.addChangeListener(changeListener);
    }

    void remove(JSlider slider) {
        candidates.remove(slider);
        values.remove(slider);
        slider.removeChangeListener(changeListener);
    }

}

1 Ответ

0 голосов
/ 21 ноября 2018

С небольшой корректировкой примера, с которым вы связались, это должно быть выполнимо.

Основная идея состоит в том, чтобы не только иметь методы SliderGroup#add и remove, которые используются для построения группыизначально, но также методы addAndAdjust и removeAndAdjust, которые (в дополнение к добавлению / удалению ползунка) распределяют значение ползунка, который был добавлен или удален, с использованием тех же методов, которые первоначально настраивали ползунки только при значении одногоползунок изменен.

Я также добавил метод keepOneSelected для флажков: если все ползунки могут быть отключены, то нет ни одного, чтобы иметь оставшееся значение.Таким образом, метод гарантирует, что по крайней мере один из флажков остается всегда установленным.

(отредактировано на основе обсуждения в комментариях:)

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ConnectedSlidersExt
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(() -> createAndShowGUI());
    }

    private static void createAndShowGUI()
    {
        JSlider s0 = new JSlider(0, 100, 33);
        JSlider s1 = new JSlider(0, 100, 33);
        JSlider s2 = new JSlider(0, 100, 34);

        int expectedSum = 100;
        SliderGroup sliderGroup = new SliderGroup(expectedSum);
        sliderGroup.add(s0);
        sliderGroup.add(s1);
        sliderGroup.add(s2);

        JPanel panel =new JPanel(new GridLayout(0,3));
        panel.add(s0);
        panel.add(createListeningLabel(s0));
        JCheckBox checkBox0 = createCheckBox(s0, sliderGroup);
        panel.add(checkBox0);
        panel.add(s1);
        panel.add(createListeningLabel(s1));
        JCheckBox checkBox1 = createCheckBox(s1, sliderGroup);
        panel.add(checkBox1);
        panel.add(s2);
        panel.add(createListeningLabel(s2));
        JCheckBox checkBox2 = createCheckBox(s2, sliderGroup);
        panel.add(checkBox2);

        keepOneSelected(checkBox0, checkBox1, checkBox2);

        panel.add(createListeningLabel(s0, s1, s2));

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(panel);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static void keepOneSelected(JCheckBox ...checkBoxes)
    {
        ActionListener actionListener = new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                int numSelected = 0;
                for (JCheckBox checkBox : checkBoxes)
                {
                    if (checkBox.isSelected())
                    {
                        numSelected++;
                    }
                }
                if (numSelected == 1)
                {
                    for (int i = 0; i < checkBoxes.length; i++)
                    {
                        JCheckBox checkBox = checkBoxes[i];
                        if (checkBox.isSelected())
                        {
                            checkBox.setEnabled(false);
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < checkBoxes.length; i++)
                    {
                        JCheckBox checkBox = checkBoxes[i];
                        checkBox.setEnabled(true);
                    }
                }
            }
        };
        for (JCheckBox checkBox : checkBoxes)
        {
            checkBox.addActionListener(actionListener);
        }
    }

    private static JCheckBox createCheckBox(
        JSlider slider, SliderGroup group)
    {
        JCheckBox checkBox = new JCheckBox();
        checkBox.setSelected(true);
        checkBox.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if (checkBox.isSelected())
                {
                    slider.setEnabled(true);
                    group.addAndAdjust(slider);
                }
                else
                {
                    slider.setEnabled(false);
                    group.removeAndAdjust(slider);
                }
            }
        });

        return checkBox;

    }

    private static JLabel createListeningLabel(final JSlider ... sliders)
    {
        final JLabel label = new JLabel("");
        for (JSlider slider : sliders)
        {
            slider.addChangeListener(new ChangeListener()
            {
                @Override
                public void stateChanged(ChangeEvent e)
                {
                    int sum = 0;
                    for (JSlider slider : sliders)
                    {
                        if (slider.isEnabled())
                        {
                            sum += slider.getValue();
                        }
                    }
                    label.setText("Sum: "+sum);
                }
            });
        }
        return label;
    }

    private static JLabel createListeningLabel(final JSlider slider)
    {
        final JLabel label = new JLabel("");
        slider.addChangeListener(new ChangeListener()
        {
            @Override
            public void stateChanged(ChangeEvent e)
            {
                label.setText(String.valueOf(slider.getValue()));
            }
        });
        return label;
    }


}


class SliderGroup
{
    private final int expectedSum;
    private final LinkedList<JSlider> candidates;

    private final ChangeListener changeListener;
    private boolean updating = false;

    SliderGroup(int expectedSum)
    {
        this.expectedSum = expectedSum;
        this.candidates = new LinkedList<JSlider>();

        changeListener = new ChangeListener()
        {
            @Override
            public void stateChanged(ChangeEvent e)
            {
                JSlider source = (JSlider)e.getSource();
                update(source);
            }
        };
    }

    private void update(JSlider source)
    {
        if (updating)
        {
            return;
        }
        updating = true;

        for (JSlider slider : candidates)
        {
            slider.setValueIsAdjusting(true);
        }

        if (candidates.size() > 1)
        {
            int delta = computeSum() - expectedSum;
            if (delta > 0)
            {
                distributeRemove(delta, source);
            }
            else
            {
                distributeAdd(delta, source);
            }
        }

        for (JSlider slider : candidates)
        {
            slider.setValueIsAdjusting(false);
        }

        updating = false;
    }


    private void distributeRemove(int delta, JSlider source)
    {
        int counter = 0;
        int remaining = delta;
        while (remaining > 0)
        {
            //System.out.println("remove "+remaining);

            JSlider slider = candidates.removeFirst();
            counter++;

            if (slider == source)
            {
                candidates.addLast(slider);
            }
            else
            {
                if (slider.getValue() > 0)
                {
                    slider.setValue(slider.getValue()-1);
                    remaining--;
                    counter = 0;
                }
                candidates.addLast(slider);
                if (remaining == 0)
                {
                    break;
                }
            }
            if (counter > candidates.size())
            {
                String message =
                    "Can not distribute " + delta + " among " + candidates;
                // System.out.println(message);
                // return;
                throw new IllegalArgumentException(message);
            }
        }
    }

    private void distributeAdd(int delta, JSlider source)
    {
        int counter = 0;
        int remaining = -delta;
        while (remaining > 0)
        {
            //System.out.println("add "+remaining);

            JSlider slider = candidates.removeLast();
            counter++;

            if (slider == source)
            {
                candidates.addFirst(slider);
            }
            else
            {
                if (slider.getValue() < slider.getMaximum())
                {
                    slider.setValue(slider.getValue()+1);
                    remaining--;
                    counter = 0;
                }
                candidates.addFirst(slider);
                if (remaining == 0)
                {
                    break;
                }
            }
            if (counter > candidates.size())
            {
                String message =
                    "Can not distribute " + delta + " among " + candidates;
                // System.out.println(message);
                // return;
                throw new IllegalArgumentException(message);
            }
        }
    }

    private int computeSum()
    {
        int sum = 0;
        for (JSlider slider : candidates)
        {
            sum += slider.getValue();
        }
        return sum;
    }

    void add(JSlider slider)
    {
        candidates.add(slider);
        slider.addChangeListener(changeListener);
    }

    void remove(JSlider slider)
    {
        candidates.remove(slider);
        slider.removeChangeListener(changeListener);
    }

    void addAndAdjust(JSlider slider)
    {
        add(slider);
        if (candidates.size() == 2)
        {
            update(candidates.get(0));
        }
        else
        {
            update(slider);
        }
    }

    void removeAndAdjust(JSlider slider)
    {
        remove(slider);
        update(slider);
        if (candidates.size() == 1)
        {
            JSlider candidate = candidates.get(0);
            int max = candidate.getMaximum();
            candidate.setValue(Math.min(max, expectedSum));
        }
    }


}
...