420 likes | 436 Views
This article explains the structure and functionality of interactive software window systems. It covers window hierarchy, window redraw, graphics objects, drawing techniques, input events, and event-driven programming.
E N D
Window and Events The structure of Interactive Software
Window Systems Windowing System Graphics View EssentialGeometry Model Controller Input
Graphical Presentation Windowing System Graphics View EssentialGeometry Model Controller Input
Windows • Window • Rectangular area of screen • Overlapping • Drawing order front to back • Window Hierarchy • Window system has composition of windows and redraws appropriately
Window Hierarchy Top folder Calculator pad Menu Icon1 Icon2 Icon1
close box title bar folder scroll bar size control Windows and Widgets
Hierarchy • Applications decomposed into different windows • Hierarchy used to determine drawing on screen • Redrawing managed by windowing system rather than application
Redraw Area to be Redrawn
Redrawing • Each widget implements • This should be controlled by windowing system although you may need to write routines that respond to this to draw widget in its entirety redraw(Graphics G) Graphics ContextA handle allowing access to the underlying drawing primitives
class DrawModel { int getNumberOfLines() { . . . } Point getEndPoint1(int lineIndex) { . . . } Point getEndPoint2(int lineIndex) { . . . } . . . other model methods . . . } class DrawView extends Widget { DrawModel myModel; public void redraw(Graphics G) { for (int i=0;i<myModel.getNumberOfLines(); i++) { G.drawLine(myModel.getEndPoint1(i), myModel.getEndPoint2(i)); } } }
Graphics object • Graphics object • Device interface, grpahics context, canvas, sheet etc.. • Object to allow access to the actually drawing device • Defines basic set of drawing methods to be used that abstact from hardware etc.. • Manages to make drawing efficient using techniques such as clipping
Clipping • Each drawing object has a clipping region • The underlying window extent. • Used to make drawing efficient and well behaved. public void redraw(Graphics G) { Region clip=G.getClipRegion(); for (int I=0;I<myModel.getNumberOfLines(); I++) { Point E1=myModel.getEndPoint1(i); Point E2=myModel.getEndPoint2(i); if (! clip.intersects(new Rectangle(E1,E2) ) { G.drawLine(E1,E2); } } }
Window Systems Windowing System Graphics View EssentialGeometry Model Controller Input
Processing input events • Receiving events from the user and dispatching them to the correct application/window. • Associating Event with application code • Ensuring event causes the code the developer has associated with a particular widget to be run. • Notifying the view and the windowing system of model changes so that the presentation can be correctly redrawn.
Input event dispatch • Windowing system needs to dispatch to the correct application • Window tree used to map from mouse click to widget • Bottom up • Lowest in the tree then passed up • Top down • maps to top of tree and dispatches this is the sent down tree x1,y1 Mouse(x,y) x2,y2
Focus • For many inputs windowing system needs to know where to send event • Key Focus • Windowing system keeps pointer to the widget that has focus and directs keyboard events to this widget. • getKeyFocus() used to aquire focus by a widget (reflected in caret on screen) • Mouse Focus • Mouse movements can be fine so mouse focus maps to restricted actions
Event-Driven Programming • All generated events go to a single event queue • provided by operating system • ensures that events are handled in the order they occurred • hides specifics of input from apps Mouse Software Event Queue Keyboard Software
Receiving Events • Events placed on an event queue by operating system • Windowing system removes events and dispatches them • In early systems handled by applications • Both user generated and windowing events handled by the same mechanism
Input events • Button Events • mouseDown, mouseUP click, doubleClick • mouseDown, mouseUP doubleClick • mouseDown, mouseUP, mouseDown, mouseUP doubleClick • Mouse Movement Events • mouseMove – whenever movement happens • mouseEnter, mouseLeave – entry and exit to window • Keyboard Events • keyInput – event when a key is pressed • Window Events • windowOpen, windowClose, windowResize, windowIconify. • Many events have “payloads” that give details • mouseMove -> x,y • keyInput -> character
Event/ Code binding • Number of different approaches used to map from the event to the code to be run in response to the event • Event Queue and type selection • Window event tables • Callback event handling • WindowProc event handling • Inheritance event handling • Interpreted Expressions
Event Queue and type selection • early Macintosh – programmer managed everything through a switch statement • Efficient and still used in mobile devices public void main() { // perform any setup of widgets including layout, setting of properties // and assignment to container widgets. while (not time to quit ) { Event evnt = getInputEventFromSystem() switch ( evnt.type ) { case MOUSEDOWN: . . . case MOUSEUP: . . . . . . . . } } }
Window event tables • Screen widgets linked to tables of procedures • Each Procedure table indexed by event type • Tree traversed to find event table • Event table indexed by Event Type
Window event tables • Sun Workstation – GIGO • Uses pointers to procedures in C • All widget carry pointer to procedure to handle the event Public void main() { initialize the windows and for each window create a procedure pointer table to handle any events that should be sent to that window while (not time to quit) { Event evnt=getInputEventFromSystem() handleWindowEvent(rootWindow, evnt); } } public void handleWindowEvent( Window curWindow, Event evnt) { foreach Window CW in curWindow.children in front to back order { if( CW.bounds.contains(evnt.mouseLocation)) { handleWindowEvent(CW,evnt); return; } } invoke procedure at curWindow.eventTable[evnt.type]; }
Inheritance event handling • All widgets must share a common interface • This is the root class that all others hang off- component public class Widget { methods and members for Bounds public void mousePressed(int x, int y, int buttonNumber) { default behavior } public void mouseReleased(int x, int y, int buttonNumber) { default behavior } public void mouseMoved(int x, int y) { default behavior } public void keyPressed(char c, int x, int y, int modifiers) { default behavior } public void windowClosed() { default behavior } public void redraw( Graphics toDraw) { default behavior } and a host of other event methods }
Inheritance event • Screen components all inherit from base widget • When input event occurs correspond method is invoked • Event is either handled on passed on to child object in the tree • Writing code to handle events involves writing the methods to handle the core set of widget events.
Listeners • Raw user input events only one part of the story • Many events are generated from other sources as a consequence of more primitive user actions • windowing system -> windowing events (open, close, move etc..) • Operating systems -> device plugged in etc.. • This led to scaling up of events and event types needed to be able to handle many thousands of types of event • Listener model evolved from inheritance based approaches in order to handle issues of scale.
Listener Class Structure • Set of objects that can produce events (Generators) • JButton generates ActionEvents whenever the button is pressed • Set of objects that want to be notified of events (Listeners) • Listeners implements an interface in order to handle the event • E.g
class ActionEvent { information about the action event } interface ActionListener { public void actionPerformed(ActionEvent e); } class JButton { lots of other methods and fields …. private Vector actionListenerList; public void addActionListener(ActionListener listener) { actionListenerList.add(listener); } public void removeActionListener(ActionListener listener) { actionListenerList.remove(listener); } protected void sendActionEvent(ActionEvent e) { for (I=0;I<actionListenerList.size();I++) { ActionListener listen= (ActionListener) actionListenerList.get(I); listen.actionPerformed(e); } } …… }
class ActionEvent { information about the action event } interface ActionListener { public void actionPerformed(ActionEvent e); } class JButton { lots of other methods and fields …. private Vector actionListenerList; public void addActionListener(ActionListener listener) { actionListenerList.add(listener); } public void removeActionListener(ActionListener listener) { actionListenerList.remove(listener); } protected void sendActionEvent(ActionEvent e) { for (I=0;I<actionListenerList.size();I++) { ActionListener listen= (ActionListener) actionListenerList.get(I); listen.actionPerformed(e); } } …… } Builds a list of ActionListener objects
class ActionEvent { information about the action event } interface ActionListener { public void actionPerformed(ActionEvent e); } class JButton { lots of other methods and fields …. private Vector actionListenerList; public void addActionListener(ActionListener listener) { actionListenerList.add(listener); } public void removeActionListener(ActionListener listener) { actionListenerList.remove(listener); } protected void sendActionEvent(ActionEvent e) { for (I=0;I<actionListenerList.size();I++) { ActionListener listen= (ActionListener) actionListenerList.get(I); listen.actionPerformed(e); } } …… } Traverses through and passes the event onto all registered action listeners
To create a generator for event Evt • Create an Evtclass to contain information about the event. • Create an EvtListener interface that contains all of the methods associated with this listener structure. • Create a private member of your generator class that can hold all of the listeners for the event. • Create the addEvtListener(EvtListener) and removeEvtListener(EvtListener) methods to allow others to add and remove listeners. • Create private methods to send events, which will loop through the listeners invoking each of their event methods. • To create a listener that can receive Evtevents one should: • Implement the EvtListener interface • Add the object to the event generator using addEvtListener().
Event Delegation • Each scrollbar can generatean AdjusmentEvent • Text needs to scroll appropriately • Could implement one ActionListener but needs to disambiguate making code more complex • Better with separate method for scrolling in X direction and scrolling in Y direction • To handle this issue Java handles this with either anonymous or inner classes
public class Tempcontroller { • public Tempcontroller() { • // configure GUI • // register event listener • upButton.addActionListener(new UpButton()); • downButton.addActionListener(new DownButton()); • // arrange components in GUI • // display GUI • } • class UpButton implements ActionListener{ • public UpButton() { /*constructor*/ } • public void actionPerformed(ActionEvent e) { • if ( temperature <MAX_TEMP) temperature= temperature +1; • tempValue.setText(String.valueOf(temperature)); • } • } • class DownButton implements ActionListener{ • public DownButton() { /*constructor*/ } • public void actionPerformed(ActionEvent e) { • if ( temperature >MIN_TEMP) temperature= temperature -1; • tempValue.setText(String.valueOf(temperature)); • } • } • }
Model/View notification • In addition to events from the view we also need to consider updates that result from changes in the model. public class LineDrawModel { private Line [] linesToDraw; public int addLine( int x1, int y1, int x2, int y2) // add line and return its index { . . . . } public void moveLine(int index, int newX1, int newY1, int newX2, int newY2) { . . . . } public void deleteLine(int index) { . . . . } public int nLines() { return linesToDraw.length; } public Line getLine(int index) // return a line from the model } public class Line { int x1, int y1, int x2, int y2 }
Model Listeners • Handle changes to the model by defining a model listener interface • Model will generate events when significant changes have occurred • Views will register objects that implement listeners to handle the updates public interface LineDrawListener { public void lineWillChange( int index, int newX1, int newY1, int newX2, int newY2); // a particular line will changed. Assumes that the old line still in the model public void modelHasChanged(); // a major change has occurred to the whole model }
public class LineDrawModel { private Line [] linesToDraw; public int addLine( int x1, int y1, int x2, int y2) // add line and return its index { notifyLineWillChange(linesToDraw.length,x1,y1,x2,y2); . . . code to add the line . . . } public void moveLine(int index, int newX1, int newY1, int newX2, int newY2) { notifyLineWillChange(index,newX1, newY1, newX2, newY2); . . . code to change the line . . . } public void deleteLine(int index) { . . . code to delete the line . . . notifyModelHasChanged(); } private Vector listeners; public void addListener(LineDrawListener newListener) { listeners.add(newListener); } public void removeListener(LineDrawListener listener) { listeners.remove(listener); } private void notifyLineWillChange( int index, int newX1, int newY1, int newX2, int newY2) { for each LineDrawListener listen in listeners listen.lineWillChange(index, newX1, newY1, newX2, newY2); } private void notifyModelHasChanged() { for each LineDrawListener listen in listeners listen.modelHasChanged(); } . . . other methods . . . } Listener List and dispatch
Handling View updates • reDraw() is an update that is called from the windowing system • View Events need to be handle particular updates by implementing the interfaces defined by the model classes to handle events.
public class LineDrawView extends Widget implements LineDrawListener { private LineDrawModel myModel; public LineDrawView(LineDrawModel model) { myModel=model; myModel.addListener(this); 3-30 Principles of Interactive Systems } public void redraw(Graphics g) { for (int i=0;i<myModel.nLines();i++) { Line line=myModel.getLine(i); g.drawLine(line.x1,line.y1, line.x2, line.y2 ); } } public void lineWillChange( int index, int newX1, int newY1, int newX2, int newY2) { Line line=myModel.getLine(index); if (line!=null) { Rectangle oldRegion =new Rectangle(line.x1, line.y1, line.x2-line.x1+1, line.y2-line.y1+1); this.damage(oldRegion); } Rectangle newRegion=new Rectangle(newX1,newY1, newX2-newX1+1, newY2-newY1+1); this.damage(newRegion); } public void modelHasChanged() { this.damage(); } }
Essential Geometry Step Left Drag Step Right • Maps from lower level graphics to higher level semantics • Separating essentially geometry allows us to simply testing and debugging Page Right Page Left
Summary • Introduced basics of windowing systems • Outlined the use of events and different techniques for handling events in interactive programming • Next • Discussion of principles of widgets • Development of a swing application demonstrating the use of events • Reading • Chapter 3 and 4 of Olsen