-
November 15th, 2001, 05:59 PM
#1
How to send an event to child's parent class
I am very much a beginner in Java. In my application I would like the child class to send an event to the parent class (both are JPanel classes). I looked in a number of books, checked the java tutorials at Sun and have not found an example. Is it possible?
Mike
-
November 15th, 2001, 06:35 PM
#2
Re: How to send an event to child's parent class
Yes, it is possible, but it could be a lot of hard code for a beginner. Perhaps there would be a simpler way if you would be more specific in your question. Like what object has what type of event you want to pass.
One way would be to use the addListenerXXX interface. Add an addXXXListener(XXXListener) method to the child class and have it save the reference to the XXXListener. Create a XXXListener interface with a method such as xxxHappended(). Have the parent class implement the XXXListener interface and call the child's addXXXListener(this); Then when the child has an XXX event, it can call all the listeners' xxxHappenened() method with an XXXEvent object.
I don't think a beginner really wants to do all this.
Norm
Norm
-
November 15th, 2001, 06:54 PM
#3
Re: How to send an event to child's parent class
Norm,
Thanks for the quick reply. Only a beginner in JAVA, not a beginner in programming.
In the JAVA docs I did notice the many mouse and item listeners, and there are some in my code as well.
I'll be more specific. My parent class has two child classes. One child class has sliders used in creating a set of data. The other child class is to display the data. The two child classes don't know about each other. I would like the display child class to update its display when the slider child class has created new data. I thought sending an event to the parent class would be the best approach to this. Make sense?
Which addXXXListener interface do I use?
Mike
-
November 15th, 2001, 07:54 PM
#4
Re: How to send an event to child's parent class
Sliders don't themselves create data, they just select values. If these values are the data you want to pass to the data display panel, then make the data display panel implement the ChangeListener interface and add itself to the sliders using addChangeListener() (or have it create an anonymous change listener and pass it to the sliders using addChangeListener()).
This way the display panel will get notified when the slider values change.
If the slider values are not the data you had in mind, perhaps you could explain a bit more about how these data are created from the slider values...
Dave
Please use [CODE]...your code here...[/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.
-
November 16th, 2001, 09:41 AM
#5
Re: How to send an event to child's parent class
You could have the display class be a listener to the slider class. The display class would implement a XXXListener interface. When an XXX event takes place in the Slider, it calls its listener(Display) to report it:
// in parent class
Slider s = new Slider(); // generates XXX events
add(s);
Display d = new Display(); // implements XXXListener
add(d);
s.addXXXListener(d); // Slider to notify Display when XXX event
Norm
Norm
-
November 16th, 2001, 10:00 AM
#6
Re: How to send an event to child's parent class
Dave,
The value of the sliders are used in the computation of data that gets placed into a Vector based class.
I want to avoid interaction between the slider class and display class as that will make one dependent on the other. Can't have that.
Mike
-
November 16th, 2001, 10:20 AM
#7
Re: How to send an event to child's parent class
Thanks again for responding.
I think I need to explain further what I am doing.
I have a JPanel(parent) class. It is a parent to another JPanel(sliders) class which has 12 sliders (and has a data class that extends Vector). The parent JPanel is also a parent to another JPanel(display) class. The display class is passed the vector class by the parent:
parent.displayClass.SetData(parent.sliderClass.GetData());
Each time one of the sliders change in the slider class, new XYZ data is generated in response to the the Vector class.
When new data is generated (because a slider changed) I would like the display class to redraw the data. Currently I'm doing it by responding to a button click in the display class panel.
I don't see how adding the display class as a Listener to the slider class would work. Is addXXXListener a new class that I need to create?
Hopefully I provided enough details.
Mike
-
November 16th, 2001, 11:17 AM
#8
Re: How to send an event to child's parent class
OK, that sounds sensible. In that case, you need a calculator object that listens to the sliders, performs the calculations, and is, in turn, listened to by the display class.
It's not such a big deal to make a listenable object, you just give it an EventListenerList, methods to add and remove listeners, and methods to fire events. The JavaDoc for EventListenerList shows examples. You can reuse ChangeListener and ChangeEvent for the calculator class, perhaps something like thisublic class MyCalculator implements ChangeListener {
// Hold listeners here
EventListenerList listenerList = new EventListenerList();
ChangeEvent changeEvent = null; // To be sent to listeners
private Data data = null; // Data to be calculated
public Data getData() {
return data;
}
// Handle slider value changes and fire data change event to display
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
int value = (int)source.getValue();
data = new Data(value); // calculate the data from the value
fireChangeEvent(); // notify listeners of change
}
}
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
protected void fireChangeEvent() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[ i ]==ChangeListener.class) {
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((ChangeListener)listeners[ i+1 ]).stateChanged(changeEvent);
}
}
}
public class DataDisplay implements ChangeListener {
public void stateChanged(ChangeEvent event) {
MyCalculator mc = (MyCalculator)event.getSource();
display(mc.getData());
}
}
// somewhere in your application:
...
DataDisplay display = new DataDisplay(...);
MyCalculator calculator = new MyCalculator();
calc.addChangeListener(display);
slider.addChangeListener(calculator);
...
Note: this is uncompiled, untested code.
It may look a bit complicated for such a simple requirement, but it can cater for any number of listeners without close coupling between them. In this kind of situation, I might be inclined to abstract the ChangeListener implementation code into a superclass that MyCalculator (and other classes that might need it) could extend. Alternatively, for a more OO solution, see the way it's done in the JSlider.java code.
Dave
Please use [CODE]...your code here...[/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.
-
November 16th, 2001, 11:28 AM
#9
Re: How to send an event to child's parent class
Dave,
Excellent! Thanks much for the contribution to my skill set. I'll look this over and see how I can put it to use in my code. This is my first Java application.
Mike
-
November 17th, 2001, 09:41 AM
#10
Re: How to send an event to child's parent class
My idea was the slider class is a source of an event (DataChanged) that the display class wants to know about. So you have the display class register itself with the slider class as a Listener for DataChanges. When there is a DataChnage event (slider moved) the slider class calls its listener with a DataChangedEvent telling the display class about the change.
Here's some code from a textbook I have showing how to create your own custom event. One of the things about it that's important is that the callback to the listener is done on a separate AWT-engine thread instead of your event source's thread.
/* Create a CustomEvent: TimerEvent and use it to control the drawing
of a horizontal bar in a small frame.
* Cay S. Horstmann & Gary Cornell, Core Java
* Published By Sun Microsystems Press/Prentice-Hall
* Copyright (C) 1997 Sun Microsystems Inc.
* All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for NON-COMMERCIAL purposes
* and without fee is hereby granted provided that this
* copyright notice appears in all copies.
*
* Minor modifications by Norm Radder
*/
/**
* @version 1.10 25 Mar 1997
* @author Cay Horstmann
*/
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
public class CustomEventTest extends Frame implements TimerListener{
private int ticks = 0; // Count number of timeElapsed
// Constructor
public CustomEventTest() {
Timer t = new Timer(1000); // Call me in 1 sec
t.addTimerListener(this);
setTitle("CustomEvent test");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
setLocation(200, 200);
setSize(100, 50);
} // end Constructor
// Here is the callback routine for the Timer
// It draws a lengthening line left to right
public void timeElapsed(TimerEvent evt) {
Graphics g = getGraphics();
g.translate(getInsets().left, getInsets().top);
g.drawRect(0, 0, ticks, 10);
ticks++;
}
// Start the test
public static void main(String[] args) {
CustomEventTest f = new CustomEventTest();
f.show();
}
} // end class CustomEventTest
// ------------------------------------------------------------------------
// Following are interface and classes to define the Timer:
// Define the TimerListener Interface
interface TimerListener {
// Call this routine when time elapses
public void timeElapsed(TimerEvent evt);
}
//------------------------------------------------------------
// Define the Timer class
// Only room for 1 listener
// Continually creates TimerEvents every interval
class Timer extends Component implements Runnable {
private int interval;
private TimerListener listener; // NB only 1 listener allowed
private static EventQueue evtq;
// Constructor
public Timer(int period) {
interval = period;
Thread t = new Thread(this);
t.start();
evtq = Toolkit.getDefaultToolkit().getSystemEventQueue();
enableEvents(0); // Enable events to come here
}
// Add the TimerListener (only room for one)
public void addTimerListener(TimerListener l) {
listener = l;
}
// Forever loop to return a event every interval
public void run() {
while (true){
try { Thread.sleep(interval); }
catch(InterruptedException e) {} // Ignore
TimerEvent te = new TimerEvent(this);
System.out.println("Before post of " + te + " on " + Thread.currentThread());
evtq.postEvent(te); // Post new event to be processed below
System.out.println("After post of " + te+ " on " + Thread.currentThread());
}
}
// Check for and process our TimerEvent
// This method is called when the event is removed from the queue
// It runs on a thread from the queue processor
public void processEvent(AWTEvent evt) {
if (evt instanceof TimerEvent) {
if (listener != null) {
System.out.println("Processing of " + evt + " on " + Thread.currentThread());
//Call the callback routine
listener.timeElapsed((TimerEvent)evt);
}
}else {
// If not ours, pass it on
super.processEvent(evt);
}
}
} // end class Timer
//--------------------------------------------------------------
// Define the TimerEvent and give it a unique id (hopefully)
class TimerEvent extends AWTEvent {
public static final int TIMER_EVENT = AWTEvent.RESERVED_ID_MAX + 5555;
long time;
public TimerEvent(Timer t) {
super(t, TIMER_EVENT);
time = System.currentTimeMillis();
}
// Show something for debugging output
public String toString() {
return "TimerEvent at " + time;
}
} // end class TimerEvent
/* Output:
Running: java CustomEventTest
Before post of TimerEvent at 1006006144980 on Thread[Thread-1,5,main]
Processing of TimerEvent at 1006006144980 on Thread[AWT-EventQueue-0,6,main]
After post of TimerEvent at 1006006144980 on Thread[Thread-1,5,main]
Before post of TimerEvent at 1006006146030 on Thread[Thread-1,5,main]
Processing of TimerEvent at 1006006146030 on Thread[AWT-EventQueue-0,6,main]
After post of TimerEvent at 1006006146030 on Thread[Thread-1,5,main]
Before post of TimerEvent at 1006006147020 on Thread[Thread-1,5,main]
Processing of TimerEvent at 1006006147020 on Thread[AWT-EventQueue-0,6,main]
After post of TimerEvent at 1006006147020 on Thread[Thread-1,5,main]
0 error(s)
*/
Norm
Norm
-
November 19th, 2001, 11:56 AM
#11
Re: How to send an event to child's parent class
Norm,
Thanks for the extensive help. I have my code working the way I want now. Thanks much.
Mike
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|