AnObservableLine.java |
package lectures.mvc.properties.atomic; import util.annotations.WebDocuments; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import util.misc.ThreadSupport; import lectures.graphics.ALine; import lectures.graphics.Line; import lectures.mvc.properties.PropertyListenerSupport; import bus.uigen.OEFrame; import bus.uigen.ObjectEditor; /** * This class is a subclass of the one we just left that performs the same task * in a different (better?) way. * * It overrides the write methods (re-implements the two setter methods). * * A write method is one that changes object state. In a Bean, setters are write * methods. * * (T/F) The method getX() inherited by AnObservableLine is a write method. * * Study the code below. * * Study also the class, APropertyListenerSupport, used in this code. * * Then skip down to the instructions at the bottom of this page and start there. * */ @WebDocuments({"Lectures/MvcPropertiesAtomic.pptx", "Lectures/MvcPropertiesAtomic.pdf", "Videos/MvcPropertiesAtomic.avi"}) public class AnObservableLine extends ANonObservableLine implements ObservableLine { PropertyListenerSupport propertySupport = new APropertyListenerSupport(); public AnObservableLine (int initX, int initY, int initWidth, int initHeight) { super(initX, initY, initWidth, initHeight); } @Override public void setX(int newVal) { int oldVal = getX(); // save old value of X super.setX(newVal); // change x /* * * Hover over PropertyChangeEvent to see the associated documentation. * * After looking at this call, go into APropertyListenerSupport, look at the * notifyAllListeners() method, and answer the questions in it. * * A setter in an observable notifies observers about (choose all that apply): * (a) the name of the property that changed. * (b) the old value of the property before the setter was called. * (c) the new value of the property set by the method. * (d) the original value of the property, right after the object was * initialized by its constructor * */ propertySupport.notifyAllListeners(new PropertyChangeEvent(this, "X", oldVal, newVal)); } @Override public void setY(int newVal) { int oldVal = getY(); super.setY(newVal); propertySupport.notifyAllListeners(new PropertyChangeEvent(this, "Y", oldVal, newVal)); } @Override public void setWidth(int newVal) { int oldVal = getWidth(); super.setWidth(newVal); propertySupport.notifyAllListeners(new PropertyChangeEvent(this, "Width", oldVal, newVal)); } @Override public void setHeight(int newVal) { int oldVal = getHeight(); super.setHeight(newVal); propertySupport.notifyAllListeners(new PropertyChangeEvent(this, "Height", oldVal, newVal)); } /** * This is the observer registration method. * * Its header is a standard header, meaning that it has to have a particular * form, much like the main method header. * * Unlike the main method, the form is defined by the Bean framework rather than Java. * * Since it is an instance method, we can put it in an interface. * * However, the Bean framework does not define such an interface. * * The OE library defines such an interface, called PropertyListenerRegister. * * Since it is a standard method, ObjectEditore understands it and calls it * from edit(). * * The header of the observer registration code in AnObservableLine is: * (a) a standard header defined by Java. * (b) a standard header defined by the Bean framework. * (c) a non standard method. */ @Override public void addPropertyChangeListener(PropertyChangeListener aListener) { /* * Put breakpoint here and debug-run. * * Look at the bottom two methods in the stack (in the debug window). Each method * in the stack was called by the method below it, so looking at the bottom can help * you see how you got to this break point. * * Now, hover over the parameter, aListener, to determine the class of the * object assigned to it. * * The method, addPropertyChangeListener, in AnObservableLine, is called: * (a) each time a setter is invoked in AnObservableLine. * (b) when the main method is invoked in AnObservableLine. * (c) each time ObjectEditor.edit() is called. * * The class of the argument of addPropertyChangeListener is an instance of: * (a) AnObservableLine * (b) APropertyChangeSupport * (c) PropertyChangeEvent * (b) LineAdapter * * * Step into the add method. * * The method addPropertyChangeListener: * (a) prints the observer passed as an argument. * (b) stores the observer in a history collection implemented by AnObservableLine. * (c) stores the observer in a history collection implemented by APropertyListenerSupport. */ propertySupport.add(aListener); // } /** * Creates an animation displayed in arbitrary number of editors */ public static void animateLine (Line aLine) { for (int i = 0; i < NUM_STEPS; i++) { int newX = aLine.getX() + X_STEP; aLine.setX(newX); ThreadSupport.sleep(SLEEP_TIME); } } /* * Supplies the parameters to animateLine */ public static void main(String args[]) { Line aLine = new AnObservableLine(10, 10, 30, 30); OEFrame editor1 = ObjectEditor.edit (aLine); OEFrame editor2 = ObjectEditor.edit (aLine); // OEFrame editor3 = ObjectEditor.edit (aLine); animateLine (aLine); } /* * * * Uncomment the code to create editor3 and change animateLine, if necessary, * to refresh all three editors (hint: does animateLine in this situation need * to know about any of the editors displaying the line?) . * * (T/F) Code animating an instance of AnObservableLine must know about the * user-interface objects displaying it. * * What is causing the line to be updated? The answer lies in the new setX() * method: it notifies each object editor frame that it has changed. * * This code illustrates the observer pattern for connecting objects. In this * pattern, an "observable" object defines a method to register one or * more observer objects. Here, the registered observer objects are stored in the * propertySupport variable, which is of type APropertySupport. * * Each write method of the observable calls a "notification method" in each * "observer" to notify it about the change. Here, this is done through the * APropertyListenerSupport object. * * * In this code, the instance methods implement the observer behavior and the static * main method calls ObjectEditor.edit() to display an instance of this class. * * The edit() method inside ObjectEditor creates appropriate observers and registers them * with the displayed observable. Whenever the observable changes due to the invocation * of a write method, it informs ObjectEditor of the change, which updates its display. * * Now, to see more details of how this pattern is implemented, go and follow the * instructions in the setX() and addPropertyChangeListener() methods. * * The observer registration method in AnObservableLine is a method named: * (a) setX * (b) propertyChange * (c) animateLine * (d) addPropertyChangeListener * */ }