Elegante Lösung für mehrere Listener

Hallo zusammen,
Das ganze ist mehr oder weniger theoretisch weil ich es (zumindest momentan) nicht brauche, aber das Thema an sich finde ich recht interessant. Folgende Sachlage:

Ich habe eine Klasse „SelectionPanel“, auf welcher der Nutzer verschiedene Auswahlmöglichkeiten hat. Darin rufe ich mehrmals die Klasse „SliderPanel“ auf, die ich selbst erstellt habe und die Klasse JPanel erweitert:

public JPanel createWertePanel(){
		JPanel getriebeWerte = new JPanel();
		getriebeWerte.setLayout(new GridLayout(0, 2));
		getriebeWerte.setBorder(new TitledBorder("Wertebereich eingrenzen"));
		
		nWert = new SliderPanel(this, "Drehzahl", 5, 0, 10000);
		nWert.setEnabled(false);
		getriebeWerte.add(nWert);
		getriebeWerte.add(new JLabel(""));
		
		mWert = new SliderPanel(this, "Moment", 6, 0, 100000);
		mWert.setEnabled(false);
		getriebeWerte.add(mWert);
		getriebeWerte.add(new JLabel(""));
		
		pWert = new SliderPanel(this, "Leistung", 6, 0, 100000);
		pWert.setEnabled(false);
		getriebeWerte.add(pWert);
		getriebeWerte.add(new JLabel(""));
		
		return getriebeWerte;
	}

Das SliderPanel enthält einen RangeSlider (JIDE), eine Checkbox, zwei Textboxen sowie eine ComboBox.

public SliderPanel(SelectionPanel select, String name, int stellen, int min, int max){
		/************************************************************
		 * Konstruktor mit dem Namen des Panels, der Stellenzahl der
		 * NumberTextFields, dem Minimal- und Maximalwert des Sliders
		 ***********************************************************/
		this.select = select;
		
		//Größe der NumberTextFields festlegen
		minVal = new NumberTextField(stellen);
		maxVal = new NumberTextField(stellen);
		
		//Werte der NumberTextFields festlegen
		minVal.setText(String.valueOf(min));
		maxVal.setText(String.valueOf(max));
		
		//Name des SliderPanels im Border festhalten:
		border = new TitledBorder(name);
		
		//Slider erstellen
		slider = new RangeSlider(min, max, min, max);	
		
		//der Boolean-Wert ist standardmäßig auf "false" gesetzt
		active = false;
		
		//das Panel selbst erstellen:
		createPanel();
	}

Die Werte der Textboxen passen sich dabei den Werten der SliderThumbs an (und umgekehrt) via Documentlistenern auf den Textboxen und einem ChangeListener auf dem RangeSlider. Die Methoden haben ungefähr folgendes Schema:

public void changedUpdate(DocumentEvent e) {
		slider.removeChangeListener(this);
		slider.setLowValue(	minVal.getText().equals("")? 	slider.getMinimum() : Integer.parseInt(minVal.getText()));
		slider.setHighValue(maxVal.getText().equals("")? 	slider.getMaximum() : Integer.parseInt(maxVal.getText()));
		slider.addChangeListener(this);
	}

Soviel zur Einleitung. Jetzt das Ding: Die Slider stellen Wertebereiche von Drehzahl, Drehmoment und Leistung dar. Diese Werte sind aber abhängig, d.h. wenn ich Drehzahl und -moment festlege, so auch die zugehörige Leistung (Daher auch die Checkbox mit boolean „active“, damit nicht mehr als 2 auf einmal eingestellt werden können).

Wenn ich nun also z.B. Drehzahl und Drehmoment ändere, so soll automatisch der Leistungswert mitgeändert werden. Dazu müsste ich aber Listener in der Klasse SelectionPanel legen. Das würde aber dazu führen, dass ich in der Klasse SliderPanel diese Listener ebenfalls ausschalten muss (wie oben), damit keine Schleifen entstehen.

Das fände ich aber ehrlich gesagt sehr hässlich, mir fällt aber leider keine schönere Methode ein.


Natürlich könnte ich z.B. alle Listener in SelectionPanel legen, aber schöner wäre das ja nicht :O. Vor allem weil ich ja dann immer abfragen muss, welches SliderPanel bedient wird.

Vielleicht fällt ja einem von euch noch was dazu ein. Ich versuche in letzter Zeit viel darauf zu achten dass der Code nicht nur funktioniert, sondern auch möglichst einfach und elegant ist. :slight_smile:

Habe es vielleicht nicht in der “angebrachten” Tiefe nachvollzogen, aber … für das Problem der “Schleifen”, wie du es nennst (also unendliche gegenseitige Benachrichtigungen), gibt es im wesentlichen 2 Lösungen:

  1. Die beste: Es werden nur Events rausgeschickt, wenn sich WIRKLICH etwas ändert. Also sinngemäß nicht
public void setValue(int value)
{
    this.value = value;
    notifyListeners();
}

sondern

public void setValue(int value)
{
    if (this.value != value)
    {
        this.value = value;
        notifyListeners();
    }
}

Damit sollten die benachrichtigungen irgendwann aufhören, und “immer ein Konsistenter Zustand” hergestellt werden.

  1. Die Alternative, die wohl ähnlich zu dem ist, was du da mit dem add/remove schon angedeutet hast: Es gibt ein Flag, wie etwa ‘boolean isCurrentlyUpdating’, das entsprechend gesetzt und abgefragt wird (läßt sich aber nicht so leicht so allgemein beschreiben).

Ich bin mir nicht ganz sicher ob das den Kern meines Problems trifft…Ich versuche es nochmal etwas exakter zu formulieren (Ist gar nicht mal so einfach, habe diesen Post 3Mal von vorne angefangen :smiley: ):

Die SliderPanel passen ihre Werte mit ihren eigenen Listenern an (also die Boxen an den Slider und umgekehrt, je nachdem welcher verändert wird).

Wir nehmen an, ich hätte „Drehzahl“ und „Moment“ aktiviert. Wenn ich jetzt den unteren Regler bei „Drehzahl“ ändere, dann soll der untere Wert von „Leistung“ sich ebenfalls ändern (Leistung = 2Pi * Moment * Drehzahl).
Ich kann das aber nicht von einem Listener im SliderPanel aus ausführen. Ich muss also einen Listener im SelectionPanel setzen. Wenn ich mit diesem jetzt aber Werte in „Leistung“ ändere, dann muss ich vorher die Listener in „Leistung“ deaktivieren (zumindest einen der beiden).

Ich schau mir das mit dem isCurrentlyUpdating mal an, vielleicht hilft mir das ja doch weiter.
Je länger ich darüber nachdenke desto hinfälliger kommt mir die ganze Fragestellung vor…Ich glaube ich hab da einfach etwas zu kompliziert gedacht.


Mein Hauptproblem war eigentlich, dass ich nicht einfach einen Listener auf das Panel legen kann…

Aber wenn ich einen Listener auf jeden der slider lege, dann kann ich im SelectionPanel abfragen ob genau 2 aktiv sind und dann dem inaktiven einfach neue in dessen Slider setzen. Die Listener im SliderPanel übernehmen dann den Rest.

Ich hoffe das war für „Außenstehende“ noch verständlich. Ich glaube ich weiß jetz aber wie man das relativ einfach löst. Manchmal hilft es einfach ungemein wenn man sich einfach nur über seine Problemchen auslassen kann :).
Danke aber für die Hilfe!

Du brauchst für deine 3 Slider ein Model, was die 3 Werte speichert und ggf. beim ändern eines Wertes die anderen Werte korrigiert.