Potrzebuję zrobić 3 slidery, w których suma wartości ma być zawsze taka sama, np 100. Przykład takiego czegoś jest na stronie humble bundle. Chciałbym wiedzieć jak uzupełnić funkcję stateChanged, aby to uzyskać.

- Rejestracja:prawie 17 lat
- Ostatnio:prawie 5 lat
To nie jest takie proste. Jeśli suma wartości ma być stała, to musisz przesuwać programowo pozostałe suwaki w trakcie przesuwania ręcznego. Ale te suwaki przesuwane ręcznie też mają listenery.
Druga sprawa, zmniejszenie obu o 20 moze być niemozliwe, bo jeden z nich ma wartość 0 5 większą od jego wartości minimalnej.
- Rejestracja:ponad 16 lat
- Ostatnio:ponad 4 lata
Co za problem stworzyć metodę uruchamianą przez listenery, przekazujemy jej eventArg, który zawiera co i o ile się przesunęło. Metoda wtedy za pomocą ifów etc. sprawdzi wcześniej stan innych suwaków i na tej podstawie, odpowiednio zmniejszy/zwiększy ich wartość. Jeśli suwak ma już minimalną wartość jakiś to wcześniej to sprawdzamy i zmniejszamy o całą wartość ten trzeci.
Ważne żeby nie gubić części ułamkowych po dzieleniu.
- Rejestracja:prawie 14 lat
- Ostatnio:ponad 7 lat
- Postów:18
Mam takie coś:
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
slider_1.setValue(100 - source.getValue() - slider_2.getValue());
slider_2.setValue(100 - source.getValue() - slider_1.getValue());
}
});
i analogicznie w pozostałych dwóch sliderach. Niby działa, ale na przesuwany ręcznie slider reaguje tylko 1 i to średnio wygląda. Ten ostatni zmienia dopiero wartość jeśli przekroczona miała by być ta stała suma dla wszystkich, czyli 100, tzn kiedy ten poprzedni jest już ustawiony na 0 lub 100.

- Rejestracja:około 20 lat
- Ostatnio:około 12 godzin
No to działa dokładnie tak jak zaprogramowałeś. Jeśli chcesz by oba naraz się przesuwały to:
- Najpierw oblicz różnicę sumy, tzn difference = 100 - (slider1.value() + slider2.value() + slider3.value());
- Następnie podziel tą wartość na dwa składniki (niekoniecznie różne), np difference1 = difference / 3; difference2 = difference - difference1, przy czym musisz zadbać o to by końcowe wartości nie wyleciały poza zakres [0, 100].
- Nastepnie dodaj difference1 do slider1 i difference2 do slider2.

- Rejestracja:około 20 lat
- Ostatnio:około 12 godzin
Ewentualnie możesz przekazać do wszystkich listenerów jeden i ten sam AtomicBoolean i zrobić metodę stateChanged w tym stylu:
if (atomicBoolean.compareAndSet(false, true)) {
// ustawiamy setValue, w tym czasie odpalają się metody changeEvent w innych listenerach, ale tam mamy takiego samego ifa
.....
atomicBoolean.set(false);
}
\
Uwaga: we wszystkich trzech listenerach do tych trzech sliderów ma być użyta ta sama instancja AtomicBoolean, tzn operację new AtomicBoolean(false)
masz robić tylko raz.
- Rejestracja:prawie 14 lat
- Ostatnio:ponad 7 lat
- Postów:18
^ Dzięki, zrobiłem tym sposobem i działa. Jeszcze muszę tylko ogarnąć jeden problem. Z chwilą kiedy zaczynam przesuwać dowolny slider, oba pozostałe się wyrównują, ale cały czas utrzymując stałą wartość.
Tak to wygląda w tej chwili:
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
int dif = (100 - slider.getValue());
if (lol.compareAndSet(false, true)) {
slider_1.setValue(dif/2);
slider_2.setValue(dif/2);
lol.set(false);
}
}
});

- Rejestracja:około 20 lat
- Ostatnio:około 12 godzin
Bo nie zrobiłeś tak jak napisałem. A napisałem tak:
Jeśli chcesz by oba naraz się przesuwały to:
- Najpierw oblicz różnicę sumy, tzn difference = 100 - (slider1.value() + slider2.value() + slider3.value());
- Następnie podziel tą wartość na dwa składniki (niekoniecznie różne), np difference1 = difference / 3; difference2 = difference - difference1, przy czym musisz zadbać o to by końcowe wartości nie wyleciały poza zakres [0, 100].
- Nastepnie dodaj difference1 do slider1 i difference2 do slider2.
A więc zamiast :
int dif = (100 - slider.getValue());
slider_1.setValue(dif/2);
slider_2.setValue(dif/2);
Powinieneś zrobić coś mniej więcej takiego:
int dif = 100 - slider.getValue() - slider1.getVaule() - slider2.getValue(); // liczenie dif też rób w ifie !!
int dif1 = dif * jakaśStałaMiędzy0a1; // np 0.5
int toSlide;
if (dif < 0) {
toSlide = Math.max(-slider1.getValue(), dif1);
} else if (dif > 0) {
toSlide = Math.min(100 - slider1.getValue(), dif1);
}
slider1.setValue(slider1.getValue() + toSlide);
slider2.setValue(slider2.getValue() + dif - toSlide);
Całość powyższego kodu ma być w ifie z atomicBooleanem. Kod 100% nietestowany.
- Rejestracja:prawie 14 lat
- Ostatnio:ponad 7 lat
- Postów:18
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (lol.compareAndSet(false, true)) {
int dif = 100 - slider.getValue() - slider_1.getValue() - slider_2.getValue();
double dif1 = dif*0.5; //* 0.5; // np 0.5
int toSlide = 0;
if (dif < 0)
{
toSlide = (int) Math.max(-slider.getValue(), dif1);
}
else if (dif > 0)
{
toSlide = (int) Math.min((100 - slider.getValue()), dif1);
}
slider_1.setValue((slider_1.getValue() + toSlide));
slider_2.setValue((slider_2.getValue() + dif - toSlide));
String aString = Integer.toString(toSlide);
lblNewLabel.setText(aString);
lol.set(false);
}
}
});
Działa dosyć dobrze, dzięki. Będę musiał potem jeszcze nad tym posiedzieć, bo czasami suma lekko przekracza 100.

- Rejestracja:około 20 lat
- Ostatnio:około 12 godzin
W złym miejscu robisz zaokrąglanie. Zamiast:
double dif1 = dif*0.5; //* 0.5; // np 0.5
Zrób:
int dif1 = (int) (dif * 0.5)
W sumie nasunęła mi się teraz jeszcze jedna myśl, tzn ten ChangeEvent będzie raczej leciał bardzo często i np dif może mieć bardzo małe wartości względne, co może psuć wrażenie przy przesuwaniu. Proponuję więc kolejną zmianę, tzn kod do liczenia dif1 zamienić na:
int dif1 = (int)(dif * jakaśStałaMiędzy0a1 + Math.random() - 0.5);
Może będzie działać lepiej.

- Rejestracja:prawie 17 lat
- Ostatnio:prawie 5 lat
Dla zabawy napisałem sobie taki programik. Zmienna dif ma praktycznie zawsze wartość 1. Co implikuje, że przesuwany suwak wymusza ruch tylko jednego suwaka. Pomoże rozwiązanie zaproponowane przez @Wibowita. Ja zastosowałem gorsze (też działające): mam suwaki w tablicy, co drugie wywołanie metody stateChanged zmieniam zwrot wędrowania po tablicy.
- Rejestracja:prawie 14 lat
- Ostatnio:ponad 7 lat
- Postów:18
Po poprawieniu tego zaokrąglania cały czas miałem problemy z wykraczaniem wartości ponad 100, więc dopisałem warunek:
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (lol.compareAndSet(false, true)) {
int dif = 100 - slider.getValue() - slider_1.getValue() - slider_2.getValue();
int dif1 = (int)(dif * 0.5 + Math.random() - 0.5);
int toSlide = 0;
if (dif < 0)
{
toSlide = (int) Math.max(-slider.getValue(), dif1);
}
else if (dif > 0)
{
toSlide = (int) Math.min((100 - slider.getValue()), dif1);
}
slider_1.setValue((slider_1.getValue() + toSlide));
slider_2.setValue((slider_2.getValue() + dif - toSlide));
if ((slider.getValue() + slider_1.getValue() + slider_2.getValue()) > 100)
{
toSlide = (slider.getValue() + slider_1.getValue() + slider_2.getValue()) - 100;
if (slider_1.getValue() > slider_2.getValue())
slider_1.setValue(slider_1.getValue() - toSlide);
else
slider_2.setValue(slider_2.getValue() - toSlide);
}
String s1 = Integer.toString(slider.getValue());
String s2 = Integer.toString(slider_1.getValue());
String s3 = Integer.toString(slider_2.getValue());
String s4 = Integer.toString(slider.getValue() + slider_1.getValue() + slider_2.getValue());
lbl1.setText(s1);
lbl2.setText(s2);
lbl3.setText(s3);
lbl4.setText(s4);
lol.set(false);
}
}
});


- Rejestracja:około 20 lat
- Ostatnio:około 12 godzin
Nie działa identycznie jak na tej stronie, ale ten stan rzeczy mnie satysfakcjonuje póki co. Dziwi tylko trochę fakt, że to jak szybko poruszam sliderem wpływa na to jak procentowo rozkłada się zmiana na innych.
Ten kod który podałem rozkłada różnicę w stałym podziale pomiędzy pozostałe slidery. Sprawdziłem jak slidery działają na Humble Bundle - tam rozkład nie jest stały. Na Humble Bundle rozkład różnicy na pozostałe slidery jest taki sam jak rozkład wartości na pozostałych sliderach.
Jeśli chcesz mieć zachowanie jak na Humble Bundle to musisz zmienić linijkę:
int dif1 = (int)(dif * 0.5 + Math.random() - 0.5);
Na:
double factor;
if (slider1.value() + slider2.value() == 0) { // tzn oba są zero
factor = 0.5;
} else {
factor = slider1.value() / (slider1.value() + slider2.value());
}
int dif1 = (int)(dif * factor + Math.random() - 0.5);
Ps:
if (dif < 0)
{
toSlide = (int) Math.max(-slider.getValue(), dif1);
}
else if (dif > 0)
{
toSlide = (int) Math.min((100 - slider.getValue()), dif1);
}
Po co rzutujesz inta na inta?

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.