Verursacher für Event herausfinden ?

  • Themenstarter Themenstarter Guest
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo!
Ich habe folgendes Problem mit dem Eventhandling bei Swing:

Für einen Scrollbar nutze ich einen JScrollbar, sowie für einen Zoomregler einen JSlider.
Der Scrollbar verschiebt den Inhalt eines Canvas-Objektes, indem ich mit einem AdjustmentListener an ihm lausche und das AdjustmentEvent abfange.
Am Zoomregler lauscht ein ChangeListener und fängt das ChangeEvent ab.
Wenn am Zoomregler nun das ChangeEvent auftaucht, da der Anwender am Zoom gedreht hat, soll entsprechend auch der JScrollbar-Value geändert werden. Dies tue ich durch den Aufruf "scrollbar.setValue(neuerWert)".
Dieser Aufruf löst jedoch ein AdjustmentEvent am Scrollbar aus, welches für mich absolut nicht zu unterscheiden ist, von einem solchen, das direkt durch Bewegen des Scrollbars entsteht.
Dort liegt jedoch für mich das Problem, da ich in diesem Fall im AdjustmentListener ein anderes Verhalten (insbesondere kein erneutes 'Verschieben') veranlassen möchte.

Daher meine Frage:
Kann man von einem Event herausfinden, wer es geschickt hat ? Hier also, ob es von JSlider's ChangeEventListener heraus erzeugt wurde, oder direkt vom JScrollbar ?
Alternativ: Gibt es anstelle von "scrollbar.setValue(wert)" auch sowas wie "scrollbar.setValue(wert, custumParameters)", so dass die customParameters den Listenern des Scrollbars zugänglich werden können ?
Oder weiss jemand eine andere Lösung ?

Danke!
kopfsalat
 
Ich hoffe, ich habe meine Frage nicht zu umständlich geschrieben.
Die war übrigens von mir (ich war nicht eingeloggt).
 
kopfsalat hat gesagt.:
Ich hoffe, ich habe meine Frage nicht zu umständlich geschrieben.
Das könnte eine Ursache sein, warum ich die Frage zuerst falsch verstanden habe ;-)

Vielleicht arbeite ich aber auch nur zu lange ;-)
 
mit event.getSource() kommst du wohl nicht weit oder?

ich setze in solchen Fällen immer eine Variable:
Code:
listener() {

if (reagiereAufEvent) {
   reagiereAufEvent = false;
   doSomething();
   reagiereAufEvent = true;
}

}
 
@SlaterB
So ähnlich hatte ich das auch bisher gemacht, hier ein Beispiel:
Code:
package swingEventTest;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;


public class TestFrame extends JFrame {
	JScrollBar	scrollbar;
	JSlider		slider;
	JTextArea	outText;
	
	boolean scrollbarlocked = false;
	
	public TestFrame() {
		super("Move the slider and the horizontal scrollbar");
		
		scrollbar = new JScrollBar(JScrollBar.HORIZONTAL, 50, 10, 0, 100);
		slider = new JSlider(0, 100, 50);
		outText = new JTextArea();
		outText.setAutoscrolls(true);
		
		scrollbar.addAdjustmentListener(new AdjustmentListener () {
			public void adjustmentValueChanged(AdjustmentEvent e) {
				if (scrollbarlocked == false) {
					outText.append("!!scrollbar driven by itself!!\n");
				} else {
					outText.append(">>scrollbar driven by slider<<\n");
				}
			}
		});
		
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				scrollbarlocked = true;
				scrollbar.setValue(slider.getValue());
				scrollbarlocked = false;
			}
		});
		
		setLayout(new BorderLayout());
		add(scrollbar, BorderLayout.NORTH);
		add(slider, BorderLayout.SOUTH);
		add(new JScrollPane(outText), BorderLayout.CENTER);
		
		setSize(750,400);		
		setVisible(true);
	}
	
	public static void main(String [] args) {
		new TestFrame();
	}
}

Was mich hierbei aber stört, ist:
a) es ist nicht sonderlich schön, diesen Umweg über eine externe Variable zu gehen. Für die Informationstrennung wäre es 'schöner', wenn man direkt beim Event dessen Verursacher erkennen könnte. Hier also, wenn man innerhalb von adjustmentValueChanged() einen Aufruf e.getCaller() hätte, der hier ggf. die Instanz des ChangeListeners zurückliefert, von dem aus setValue() auf scrollbar aufgerufen wurde. Alternativ wäre es hilfreich, einen Aufruf scrollbar.setValue(slider.getValue(), EVENENTPARAMETER) machen zu können, so dass EVENTPARAMETER in das AdjustmentEvent hineinkopiert wird.

b) Obiges Beispiel funktioniert, da das nach dem Aufruf von scrollbar.setValue(slider.getValue()); die AdjustmentListener mit ihren Events komplett abgearbeitet werden, bevor im ChangeListener mit der nächsten Zeile fortgefahren wird. Ich denke aber nicht, dass man sich darauf verlassen kann - an sich ist doch das Event-System durchaus völlig asynchron angelegt ?

Fällt vielleicht noch jemandem eine andere Lösung ein ? Deine Variante ist ja auch etwas anders. Wenn reagiereAufEvent einmal von außen auf false gesetzt wurde, dann wird es selbständig nicht wieder true - es muss erst von außen wieder auf true gesetzt werden. Ich sehe aber nicht, wie ich das in obiges Beispiel sinnvoll einsetzen könnte.
 
Hi!
Ich hätte jetzt eine Lösung - wenn sie funktionierte:

Ich sende einfach mein eigenes AdjustmentEvent an den JScrollBar.
Dann sollte dieser sich doch eigentlich nach dem neuen Wert einstellen und dann dieses Event an den Listener weiterleiten, wo das Event weiter ausgewertet werden kann.
So könnte ich sogar von AdjustmentEvent erben und noch viel mehr Daten an den Listener schicken.

Problem:
Wie sende ich ein Event manuell an scrollbar ? Irgendwie klappt das mit scrollbar.dispatchEvent(AWTEvent) nicht.
Was mache ich falsch ?

Code:
package swingEventTest;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;


public class TestFrame2 extends JFrame {
	JScrollBar	scrollbar;
	JSlider		slider;
	JTextArea	outText;
	
	public static final int SLIDERSOURCE = AdjustmentEvent.ADJUSTMENT_LAST + 1;
	
	public TestFrame2() {
		super("2nd test: Move the slider and the horizontal scrollbar");
		
		scrollbar = new JScrollBar(JScrollBar.HORIZONTAL, 50, 10, 0, 100);
		slider = new JSlider(0, 100, 50);
		outText = new JTextArea();
		outText.setAutoscrolls(true);
		
		scrollbar.addAdjustmentListener(new AdjustmentListener () {
			public void adjustmentValueChanged(AdjustmentEvent e) {
				if (e.getID() == SLIDERSOURCE) {
					outText.append(">>scrollbar driven by slider<<\n");
				} else {
					outText.append("!!scrollbar driven by itself!!\n");
				}
			}
		});
		
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				scrollbar.dispatchEvent(new AdjustmentEvent(scrollbar, SLIDERSOURCE, 0, slider.getValue()));
			}
		});
		
		setLayout(new BorderLayout());
		add(scrollbar, BorderLayout.NORTH);
		add(slider, BorderLayout.SOUTH);
		add(new JScrollPane(outText), BorderLayout.CENTER);
		
		setSize(750,400);		
		setVisible(true);
	}
	
	public static void main(String [] args) {
		new TestFrame2();
	}
}
 
Sorry für das Pushen, aber hat jemand noch eine Idee zu meinem letzten Posting ?
Das ist inhaltlich auch völlig unabhängig zu allem vorher Geschriebenen, so dass man dieses Topic gar nicht komplett lesen muss.

Zentrale Frage nochmal: Warum klappt das dispatchEvent() in Zeile 37 nicht so, wie ich dachte ?
 
So, ich habe nun endlich eine erste Lösung gefunden, auch wenn die etwas kompliziert erscheint.

Zum einen muss ich dazu von JScrollBar erben, um die fireAdjustmentValueChange()-Methode public zu machen. fireAdjustmentValueChange() schickt dann zwar das Event an die Listener, ändert aber nicht den Wert des Scrollbars (der im BoundedRangeModel gespeichert ist).
Daher muss ich noch den Wert des Scrollbars im BoundedRangeModel ändern können, ohne dass erneut von diesem aus ein AdjustmentEvent gefeuert wird, wozu ich von ihm erben muss und einige Methoden überschreiben.

Dann aber erhalte ich in etwa das gewünschte Verhalten: Nun können im AdjustmentEvent-Listener auch eigene AdjustmentEvents mit eigenen Typen ankommen, so dass in Abhängigkeit davon ein Verhalten gewählt werden kann. Dabei kann auch der Wert des Scrollbars gesetzt werden, ohne dass ein weiteres AdjustmentEvent geschickt wird.

Hier der Source:
Code:
package swingEventTest;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.event.*;

public class TestFrame3 extends JFrame {

	static class MyJScrollBar extends JScrollBar {
		private MyBoundedRangeModel myModel;
		
		public MyJScrollBar() {
			super();
			myModel = new MyBoundedRangeModel();
			setModel(myModel);
		}

		public MyJScrollBar(int orientation) {
			super(orientation);
			myModel = new MyBoundedRangeModel();
			setModel(myModel);
		}

		public MyJScrollBar(int orientation, int value, int extent, int min, int max) {
			super(orientation, value, extent, min, max);
			myModel = new MyBoundedRangeModel(value, extent, min, max);
			setModel(myModel);
		}
		
		public void setValueWithoutFiringEvent(int n) {
			myModel.setValueWithoutFiringEvent(n);
			updateUI();
		}
		
		public void fireAdjustmentValueChanged(int id, int type, int value) {	// overrides protected visibility 
			super.fireAdjustmentValueChanged(id, type, value);
		}
	}
	
	static class MyBoundedRangeModel extends DefaultBoundedRangeModel {
		private int myValue = 0; 
		
		public MyBoundedRangeModel() {
			super();
		}

		public MyBoundedRangeModel(int value, int extent, int min, int max) {
			super(value, extent, min, max);
			this.myValue = value;
		}
		
		public int getValue() {	// overrides getValue()
			return myValue;
		}
		
		public void setValue(int n) { // overrides setValue()
			super.setValue(n);
			myValue = super.getValue();
		}

		public void setValueWithoutFiringEvent(int n) {
			myValue = Math.min(getMaximum(), Math.max(n, getMinimum())); 
		}		
	}
	

	MyJScrollBar	scrollbar;
	JSlider			slider1;
	JSlider			slider2;
	JTextArea		outText;
		
	public static final int ADJUSTMENTTYPE_SLIDERSOURCE = -1;
	
	public TestFrame3() {
		super("3rd test: Move the sliders and the horizontal scrollbar");
		
		scrollbar = new MyJScrollBar(MyJScrollBar.HORIZONTAL, 50, 10, 0, 100);
		slider1 = new JSlider(0, 100, 50);
		slider2 = new JSlider(0, 100, 50);
		outText = new JTextArea();
		outText.setAutoscrolls(true);
					
		scrollbar.addAdjustmentListener(new AdjustmentListener () {
			public void adjustmentValueChanged(AdjustmentEvent e) {
				if (e.getAdjustmentType() == ADJUSTMENTTYPE_SLIDERSOURCE) {
					scrollbar.setValueWithoutFiringEvent(e.getValue());
					outText.append("Scrollbar driven by it's listener after receiving a custom AdjustmentEvent-type\n");
				} else {
					outText.append("Scrollbar driven by moving itself\n");
				}
			}
		});
		
		slider1.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				scrollbar.fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, ADJUSTMENTTYPE_SLIDERSOURCE, slider1.getValue());
			}
		});
		
		slider2.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				scrollbar.setValueWithoutFiringEvent(slider2.getValue());
				outText.append("Slider's listener moved the scrollbar without provoking any AdjustmentEvent\n");
			}
		});
		
		setLayout(new BorderLayout());
		add(scrollbar, BorderLayout.NORTH);
		add(new JScrollPane(outText), BorderLayout.CENTER);
		JPanel p = new JPanel(new GridLayout(1,2));
		p.add(slider1);
		p.add(slider2);
		add(p, BorderLayout.SOUTH);
		
		setSize(750,400);		
		setVisible(true);
	}
	
	public static void main(String [] args) {
		new TestFrame3();
	}
}

Vielleicht sieht noch jemand eine elegantere Möglichkeit ?
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben