我有N个JSliders列表(N不会在程序上更改,只是随着我添加更多功能而已。当前N等于4)。所有滑块的值之和必须等于100。随着一个滑块的移动,其余的滑块应进行调整。每个滑块的值范围从0到100。
当前,当更改滑块(伪代码)时,我正在使用以下逻辑:
newValue = currentSlider.getValue
otherSliders = allSliders sans currentSlider
othersValue = summation of otherSliders values
properOthersValue = 100 - newValue
ratio = properOthersValue / othersValue
for slider in otherSlider
slider.value = slider.getValue * ratio
此设置的问题是滑块的值存储为整数。因此,当我调整滑块时,会遇到精度问题:滑块会根据比例值抽动或完全不移动。同样,总价值不一定总等于100。
没有人可以解决此问题,而无需创建支持浮点数或双精度数的全新JSlider类吗?
如果您想要我想要的行为的示例,请访问:Humble Indie
Bundle
并滚动到页面底部。
谢谢
ps将值乘以比率可以使用户将值“锁定”为0。但是,当4个滑块中的3个滑块为0且第4个滑块为100时,我不确定该怎么做下。使用上面的逻辑,3个滑块的值为0,它们将保持放置状态,而第4个滑块将移动到用户放置它的位置,这使总数小于100,这是不正确的行为。
编辑
这是SSCCE:
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.LinkedList;
public class SliderDemo
{
static LinkedList<JSlider> sliders = new LinkedList<JSlider>();
static class SliderListener implements ChangeListener
{
boolean updating = false;
public void stateChanged(ChangeEvent e)
{
if (updating) return;
updating = true;
JSlider source = (JSlider)e.getSource();
int newValue = source.getValue();
LinkedList<JSlider> otherSliders = new LinkedList<JSlider>(sliders);
otherSliders.remove(source);
int otherValue = 0;
for (JSlider slider : otherSliders)
{
otherValue += slider.getValue();
}
int properValue = 100 - newValue;
double ratio = properValue / (double)otherValue;
for (JSlider slider : otherSliders)
{
int currentValue = slider.getValue();
int updatedValue = (int) (currentValue * ratio);
slider.setValue(updatedValue);
}
int total = 0;
for (JSlider slider : sliders)
{
total += slider.getValue();
}
System.out.println("Total = " + total);
updating = false;
}
}
public static void main(String[] args)
{
JFrame frame = new JFrame("SliderDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = frame.getContentPane();
JPanel sliderPanel = new JPanel(new GridBagLayout());
container.add(sliderPanel);
SliderListener listener = new SliderListener();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
int sliderCount = 4;
int initial = 100 / sliderCount;
for (int i = 0; i < sliderCount; i++)
{
gbc.gridy = i;
JSlider slider = new JSlider(0, 100, initial);
slider.addChangeListener(listener);
slider.setMajorTickSpacing(50);
slider.setPaintTicks(true);
sliders.add(slider);
sliderPanel.add(slider, gbc);
}
frame.pack();
frame.setVisible(true);
}
}
为什么不说JSlider模型的粒度从0到1000000,并且总和为1000000,以使粒度更细?使用适用Dictionary
于LabelTable
的适当名称,用户可能不会知道它的范围不是从0到100。
例如:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@SuppressWarnings("serial")
public class LinkedSliders2 extends JPanel {
private static final int SLIDER_COUNT = 5;
public static final int SLIDER_MAX_VALUE = 1000;
private static final int MAJOR_TICK_DIVISIONS = 5;
private static final int MINOR_TICK_DIVISIONS = 20;
private static final int LS_WIDTH = 700;
private static final int LS_HEIGHT = 500;
private JSlider[] sliders = new JSlider[SLIDER_COUNT];
private SliderGroup2 sliderGroup = new SliderGroup2(SLIDER_MAX_VALUE);
public LinkedSliders2() {
Dictionary<Integer, JComponent> myDictionary = new Hashtable<Integer, JComponent>();
for (int i = 0; i <= MAJOR_TICK_DIVISIONS; i++) {
Integer key = i * SLIDER_MAX_VALUE / MAJOR_TICK_DIVISIONS;
JLabel value = new JLabel(String.valueOf(i * 100 / MAJOR_TICK_DIVISIONS));
myDictionary.put(key, value);
}
setLayout(new GridLayout(0, 1));
for (int i = 0; i < sliders.length; i++) {
sliders[i] = new JSlider(0, SLIDER_MAX_VALUE, SLIDER_MAX_VALUE
/ SLIDER_COUNT);
sliders[i].setLabelTable(myDictionary );
sliders[i].setMajorTickSpacing(SLIDER_MAX_VALUE / MAJOR_TICK_DIVISIONS);
sliders[i].setMinorTickSpacing(SLIDER_MAX_VALUE / MINOR_TICK_DIVISIONS);
sliders[i].setPaintLabels(true);
sliders[i].setPaintTicks(true);
sliders[i].setPaintTrack(true);
sliderGroup.addSlider(sliders[i]);
add(sliders[i]);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(LS_WIDTH, LS_HEIGHT);
}
private static void createAndShowGui() {
LinkedSliders2 mainPanel = new LinkedSliders2();
JFrame frame = new JFrame("LinkedSliders");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class SliderGroup2 {
private List<BoundedRangeModel> sliderModelList = new ArrayList<BoundedRangeModel>();
private ChangeListener changeListener = new SliderModelListener();
private int maxValueSum;
public SliderGroup2(int maxValueSum) {
this.maxValueSum = maxValueSum;
}
public void addSlider(JSlider slider) {
BoundedRangeModel model = slider.getModel();
sliderModelList.add(model);
model.addChangeListener(changeListener);
}
private class SliderModelListener implements ChangeListener {
private boolean internalChange = false;
@Override
public void stateChanged(ChangeEvent cEvt) {
if (!internalChange) {
internalChange = true;
BoundedRangeModel sourceModel = (BoundedRangeModel) cEvt.getSource();
int sourceValue = sourceModel.getValue();
int oldSumOfOtherSliders = 0;
for (BoundedRangeModel model : sliderModelList) {
if (model != sourceModel) {
oldSumOfOtherSliders += model.getValue();
}
}
if (oldSumOfOtherSliders == 0) {
for (BoundedRangeModel model : sliderModelList) {
if (model != sourceModel) {
model.setValue(1);
}
}
internalChange = false;
return;
}
int newSumOfOtherSliders = maxValueSum - sourceValue;
for (BoundedRangeModel model : sliderModelList) {
if (model != sourceModel) {
long newValue = ((long) newSumOfOtherSliders * model
.getValue()) / oldSumOfOtherSliders;
model.setValue((int) newValue);
}
}
int total = 0;
for (BoundedRangeModel model : sliderModelList) {
total += model.getValue();
}
//!! System.out.printf("Total = %.0f%n", (double)total * 100 / LinkedSliders2.SLIDER_MAX_VALUE);
internalChange = false;
}
}
}
}
编辑为让SliderGroup2使用BoundedRangeModels列表而不是JSliders。
问题内容: 我知道以下行为是一个老问题,但我仍然不明白。 或者即使我使用 为什么这个结果是:而不是:? 我该如何解决? 问题答案: 你真正想要的是 该构造得到的所有的不精确性,所以由你说的时候,你已经引入了舍入误差。使用构造函数可避免与通过导致的舍入错误。
问题内容: 我的同事做了这个实验: 对于这个一年级的操作,我希望得到以下输出: 但是意外的输出是: 为什么在如此简单的操作中double会失败?而且如果double不是这项工作的数据类型,我应该使用什么? 问题答案: 在内部以分数形式存储在 二进制文件中 -例如 值-或值-不能以精确的分数形式存储在二进制中,因此不能存储精确的值,并且相减后的值也不太精确。 如果您关心精确的十进制算术,请使用。 您
https://github.com/camsong/blog/issues/9
问题内容: 文档的内容如下(强调我的意思)。 此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值表示自某个固定但任意时间以来的纳秒(也许是将来的时间,因此值可能为负)。 此方法提供纳秒精度,但不一定提供纳秒精度。 无法保证值更改的频率。 如我所见,这可以用两种不同的方式解释: 在句子中 大胆 上面是指个人的返回值。然后,将在数字意义上理解精度和准确性。也就是说,精度是指有效
问题内容: 我遇到这样的情况,两个人可能在两台不同的计算机上以相同的顺序工作(存储在MS SQL数据库中)。为了防止数据丢失,在这种情况下,一个人先保存订单的副本,然后再稍等一会再保存他的副本并覆盖第一个副本,我在保存之前对 lastSaved 字段(日期时间)添加了一个检查。 该代码大致如下所示: 这在大多数情况下都有效,但是我发现了一个小错误。 如果 orderIsChangedByOther
屏幕显示我试图从扫描的身份证中提取数据,但OCR的准确性有问题。名字后面有一些额外的小字,与身份证上的常规名字混淆了。表单识别器中的OCR不准确。我尝试了计算机视觉3.0预览读取应用编程接口,它工作正常。有没有办法将新的3.0计算机视觉OCR应用编程接口与表单识别器2.0一起使用?我看到一些留档,其中提到在容器中使用表单识别器时使用计算机视觉应用编程接口?如果我们使用云表单识别器应用编程接口而不是