有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

上下文

我正在写一段有1+滑块的代码。这些滑块组成一个组。此组的滑块值之和必须始终为100。但是,作为所需功能,用户可以禁用和启用(添加/删除)此组中的滑块。因此,这需要正确调整滑块值

在尝试编写我自己的小组代码之后,我决定寻找更好的/经过测试并实现的代码。它比我的有所改进,但是出现了一些问题


主要问题

通过选择或取消选择添加或删除滑块复选框将导致错误,滑块将停止工作。请注意,在此场景中,添加只意味着启用以前禁用的滑块(通过取消选中复选框)

Example of the current issue


初步解决方案

在stackoverflow中找到以下代码。我确实在我的代码中实现了,但是因为我不能发布它,所以我决定调整stackoverflow示例中的代码来表示我的场景


怎么做

非常感谢您的帮助。我不知道如何在不引起更多错误的情况下解决这个问题。我确实尝试过重新调整update方法上的演算,但这只会导致更多的废话。我不觉得在这里发布我所有的尝试都很有成效,因为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) 个答案

  1. # 1 楼答案

    对链接到的示例稍作调整后,这应该是可行的

    其基本思想是,不仅要有最初用于构造组的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));
            }
        }
    
    
    }