I'm attempting to add 3 JSliders to a java swing application, such that the total value across the three sliders always adds up to 100. Each slider is a probability, slider A is the probability of adding a value to a queue, slider B is the probability of removing a value from a queue, and slider C is the probability of nothing happening.
Example: Slider A is set to 40, Slider B is set to 40, and slider C is set to 20 initially. If the user changes Slider A to 50 I want the values of Slider B and C to both decrease by 5. Such that the total is still 100. I understand that there may be some issues when the user changes the value to say, 41, because I'd like the other values to remain as whole integers.
Ok, so I've added some code, after reviewing some information concerning BoundedRangeModel. I've managed to get the sliders to change based on the otherse, but I'm still unsure as to how I can implement there initial values. Also, the sliders are only seeming to work in pairs, as opposed to a group of 3.
I'll keep working on it and if I come up with a solution that I'm satisfied with using this method I'll post it here.
package stackoverflow;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BoundedRangeModel;
import javax.swing.DefaultBoundedRangeModel;
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 Controller {
public static void main(String[] args)
{
//GUI up
Frame f = new Frame();
f.setSize(600, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
@SuppressWarnings("serial")
public static class Frame extends JFrame implements PropertyChangeListener, ChangeListener
{
//Sliders
private JSlider s1;
private JSlider s2;
private JSlider s3;
//Initial Values for fields (not sure how to implement)
private int inis1 = 45;
private int inis2 = 40;
private int inis3 = 15;
//Labels
private JLabel s1Label;
private JLabel s2Label;
private JLabel s3Label;
//Strings for labels
private static String s1String = "Probability of adding one to queue";
private static String s2String = "Probability of subtracting one from queue";
private static String s3String = "Probability of doing nothing";
public Frame()
{
//title of window
super("Sliders");
//Layout
//Label Panel, GridBag Setup
JPanel pane = new JPanel(new GridBagLayout());
this.add(pane);
GridBagConstraints c = new GridBagConstraints();
class LimitedBoundedRangeModel extends DefaultBoundedRangeModel {
BoundedRangeModel limit;
public LimitedBoundedRangeModel(BoundedRangeModel limit) {
this.limit = limit;
}
/**
* @inherited <p>
*/
@Override
public void setRangeProperties(int newValue, int newExtent, int newMin,
int newMax, boolean adjusting) {
if (limit != null) {
int combined = newValue + limit.getValue();
if (combined > newMax) {
newValue = newMax - limit.getValue();
}
}
boolean invoke =
(adjusting != getValueIsAdjusting()) && !adjusting;
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
if (invoke) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fireStateChanged();
}
});
}
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
}
}
// use
LimitedBoundedRangeModel firstModel = new LimitedBoundedRangeModel(null);
LimitedBoundedRangeModel secondModel = new LimitedBoundedRangeModel(firstModel);
LimitedBoundedRangeModel thirdModel = new LimitedBoundedRangeModel(secondModel);
firstModel.limit = secondModel;
secondModel.limit = thirdModel;
thirdModel.limit = firstModel;
s1 = new JSlider(firstModel);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 5;
pane.add(s1, c);
s2 = new JSlider(secondModel);
c.gridx = 0;
c.gridy = 5;
c.gridwidth = 5;
pane.add(s2, c);
s3 = new JSlider(thirdModel);
c.gridx = 0;
c.gridy = 7;
c.gridwidth = 5;
pane.add(s3, c);
s1Label = new JLabel(s1String);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 5;
pane.add(s1Label, c);
s2Label = new JLabel(s2String);
c.gridx = 0;
c.gridy = 4;
c.gridwidth = 5;
pane.add(s2Label, c);
s3Label = new JLabel(s3String);
c.gridx = 0;
c.gridy = 6;
c.gridwidth = 5;
pane.add(s3Label, c);
//enable 'tick' markers
s1.setMajorTickSpacing(25);
s1.setMinorTickSpacing(1);
s1.setPaintTicks(true);
s1.setPaintLabels(true);
s1.setSnapToTicks(true);
s2.setMajorTickSpacing(25);
s2.setMinorTickSpacing(1);
s2.setPaintTicks(true);
s2.setPaintLabels(true);
s2.setSnapToTicks(true);
s3.setMajorTickSpacing(25);
s3.setMinorTickSpacing(1);
s3.setPaintTicks(true);
s3.setPaintLabels(true);
s3.setSnapToTicks(true);
//Listening to sliders
s1.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent ce)
{
JSlider source = (JSlider)ce.getSource();
if (!source.getValueIsAdjusting())
{
int P = (int)source.getValue();
System.out.println("Probability of adding to queue is now: " + P);
/*
* TODO
* Would setting the values of the other sliders here,
* instead of using the BoundedRangeModel work?
* Tricky math would have to be used.
*/
// s2Slider.setValue();
}
}
});
s2.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent ce)
{
JSlider source = (JSlider)ce.getSource();
if (!source.getValueIsAdjusting())
{
int P = (int)source.getValue();
System.out.println("Probability of subtracting from queue is now: " + P);
}
}
});
s3.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent ce)
{
JSlider source = (JSlider)ce.getSource();
if (!source.getValueIsAdjusting())
{
int P = (int)source.getValue();
System.out.println("Probability of doing nothing to the queue is now: " + P);
}
}
});
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Auto-generated method stub
}
@Override
public void stateChanged(ChangeEvent e) {
// TODO Auto-generated method stub
}
}
}