java多个JSlider激活和停用共享值
上下文
我正在写一段有1+滑块的代码。这些滑块组成一个组。此组的滑块值之和必须始终为100。但是,作为所需功能,用户可以禁用和启用(添加/删除)此组中的滑块。因此,这需要正确调整滑块值
在尝试编写我自己的小组代码之后,我决定寻找更好的/经过测试并实现的代码。它比我的有所改进,但是出现了一些问题
主要问题
通过选择或取消选择添加或删除滑块复选框将导致错误,滑块将停止工作。请注意,在此场景中,添加只意味着启用以前禁用的滑块(通过取消选中复选框)
初步解决方案
在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 楼答案
对链接到的示例稍作调整后,这应该是可行的
其基本思想是,不仅要有最初用于构造组的
SliderGroup#add
和remove
方法,还要有addAndAdjust
和removeAndAdjust
方法(除了添加/删除滑块外)分配添加或删除的滑块的值,使用与最初仅在一个滑块的值更改时调整滑块相同的方法我还为复选框添加了一个
keepOneSelected
方法:如果所有的滑块都可以被禁用,那么就没有剩余值。因此,该方法确保至少有一个复选框始终处于选中状态(根据评论中的讨论进行编辑:)