Slidery zależne od siebie

Slidery zależne od siebie
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

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ć.

SH
  • Rejestracja:ponad 16 lat
  • Ostatnio:ponad 4 lata
0

Musisz sprawdzić, który właśnie suwak się zmienił w listenerze, sprawdzić o ile się zmienił, jeśli np. o 40 się zwiększył, to pozostałe suwaki zmniejszasz o 20.


C++ to wyjątkowy język - wysokopoziomowy z niskopoziomowymi mechanizmami, którymi można rozwalić w drobny mak te wysokopoziomowe.
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

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.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
SH
  • Rejestracja:ponad 16 lat
  • Ostatnio:ponad 4 lata
0

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.


C++ to wyjątkowy język - wysokopoziomowy z niskopoziomowymi mechanizmami, którymi można rozwalić w drobny mak te wysokopoziomowe.
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

Ale te przesuwane programowo suwaki też wygenerują zdarzenie.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
SH
  • Rejestracja:ponad 16 lat
  • Ostatnio:ponad 4 lata
0

Po to listenery mają fajną możliwość ich podłączania i odłączania, by z tego skorzystać w odpowiedniej chwili, kiedy nie chcemy reagować na zmiany.


C++ to wyjątkowy język - wysokopoziomowy z niskopoziomowymi mechanizmami, którymi można rozwalić w drobny mak te wysokopoziomowe.
bogdans
Ja to wiem, ale Ty w pierwszym poście o tym nie wspomniałeś;).
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Mam takie coś:

Kopiuj
 
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.

edytowany 1x, ostatnio: m4tius
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 12 godzin
0

No to działa dokładnie tak jak zaprogramowałeś. Jeśli chcesz by oba naraz się przesuwały to:

  1. Najpierw oblicz różnicę sumy, tzn difference = 100 - (slider1.value() + slider2.value() + slider3.value());
  2. 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].
  3. Nastepnie dodaj difference1 do slider1 i difference2 do slider2.

"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Heh, wszystko fajnie przy pierwszym sliderze, ale gdy już edytuję pozostałe, to albo wariują z wartościami, albo się blokują. Problem nie jest jakiś nietypowy, ale nie mogę znaleźć jakiegoś przykładu.

SH
  • Rejestracja:ponad 16 lat
  • Ostatnio:ponad 4 lata
0

@m4tius Może nie odłączasz listenerów przed wywoływaniem set, o czym pisaliśmy wyżej?


C++ to wyjątkowy język - wysokopoziomowy z niskopoziomowymi mechanizmami, którymi można rozwalić w drobny mak te wysokopoziomowe.
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Mam użyć removeChangeListener?

SH
  • Rejestracja:ponad 16 lat
  • Ostatnio:ponad 4 lata
0

@m4tius Tak, użyj remowe na suwakach, dla których robisz set, później przyłącz listenery z powrotem. Najlepiej jakbyś nie robił anonimowych klas w tym wypadku, ale jak lubisz.


C++ to wyjątkowy język - wysokopoziomowy z niskopoziomowymi mechanizmami, którymi można rozwalić w drobny mak te wysokopoziomowe.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 12 godzin
2

Ewentualnie możesz przekazać do wszystkich listenerów jeden i ten sam AtomicBoolean i zrobić metodę stateChanged w tym stylu:

Kopiuj
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.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

^ 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:

Kopiuj
				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);
					}

			}
		});
edytowany 1x, ostatnio: m4tius
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 12 godzin
0

Bo nie zrobiłeś tak jak napisałem. A napisałem tak:

Jeśli chcesz by oba naraz się przesuwały to:

  1. Najpierw oblicz różnicę sumy, tzn difference = 100 - (slider1.value() + slider2.value() + slider3.value());
  2. 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].
  3. Nastepnie dodaj difference1 do slider1 i difference2 do slider2.

A więc zamiast :

Kopiuj
 int dif = (100 - slider.getValue());
 slider_1.setValue(dif/2);
 slider_2.setValue(dif/2);

Powinieneś zrobić coś mniej więcej takiego:

Kopiuj
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.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 3x, ostatnio: Wibowit
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0
Kopiuj
 
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.

edytowany 3x, ostatnio: m4tius
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 12 godzin
0

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.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

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.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Po poprawieniu tego zaokrąglania cały czas miałem problemy z wykraczaniem wartości ponad 100, więc dopisałem warunek:

Kopiuj
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);
					}

			}
		}); 
edytowany 2x, ostatnio: m4tius
Wibowit
Trochę dziwne dla mnie, że czasem wychodzi poza 100. A tak ogólnie to się dobrze sprawuje? Tzn działa podobnie jak na Humble Bundle?
M4
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.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 12 godzin
0

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:

Kopiuj
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:

Kopiuj
                                        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?


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
M4
To albo naknociłem w Twoim kodzie, albo tak nie jest, bo pozostałe slidery nigdy nie zmieniają się po równo. O tym rzutowaniu musiałem zapomnieć, pewnie wcześniej miałem toSlide jako double.
Wibowit
Spróbuj zwiększyć precyzję sliderów, tzn zamiast maximumValue == 100, dać np maximumValue == 1000, a potem w reszcie kodu sobie odpowiednio przeskalować stałe. Powinny wtedy działać bardziej równo.

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.