多个JSlider激活和停用-共享值

时间:2018-11-21 16:15:57

标签: java swing awt jslider

上下文

我正在编写一段包含1个以上Sliders的代码。这些滑块组成一个组。该组滑块值的总和必须始终为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 :(得分:2)

对您链接的示例进行较小的调整,这应该是可行的。

基本思想是不仅要具有最初用于构造组的SliderGroup#addremove方法,而且还要具有addAndAdjustremoveAndAdjust除了添加/删除滑块之外),使用仅在更改一个滑块的值时最初调整滑块的方法,才能分配添加或删除的滑块的值。

我还为复选框添加了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));
        }
    }


}