InteractorChains
InteractorChains is a sample program that illustrates how to chain
interactors. It defines a class, TClickOrDragInteractor, that is
started when the mouse is clicked and runs either of two other
interactors, depending on whether the mouse is double-clicked or
moved. These two interactors are generic interactors and have no
special knowledge of TClickOrDragInteractor.
Running the sample
Execute InteractorChainsSApp, and click in the view. If the
power key is down, the SetColorInteractor is started. It will
change the color and leave it set until it is released, at which point
it will set it back. If the second power key is down (and the power
key is not), the SetPointInteractor is started. It causes the
view to report the mouse point while the mouse is held down. If
neither modifier key is down, the TClickOrDragInteractor is
started, with each of the other interactors as child interactors.
Depending on whether the next event is a double-click or a move,
either child interactor is started. A double-click starts
the set-color interactor, and a drag starts the set-point
interactor. Click Close to quit.
Files and classes
TGraphicView is defined in GraphicView.h and
GraphicView.C. It is basically the same as the version in MouseInteractors,
except it implements MouseDown to start one of the three interactors.
TClickOrDragInteractor is defined in ClickOrDragInteractor.h and
ClickOrDragInteractor.C This code illustrates how to write a root interactor
that can switch between child interactors and delegate to them.
TSetColorInteractor is defined in SetColorInteractor.h and
SetColorInteractor.C. It is a standard interactor, like the one in
MouseInteractors. It uses SetColor protocol on TGraphicView to set
the color of the view.
TSetPointInteractor is defined in SetPointInteractor.h and
SetPointInteractor.C. It is a standard interactor, like the one in
MouseInteractors. It uses SetPoint protocol on TGraphicView to
set the point that the view displays.
Notes
If you want to compose interactors, you must chain them. In this
example, once either of the two subinteractors is started, there is no
going back, so you might expect to be able to simply start them using
TEvent::StartInteractor. However, this causes an assertion
failure, so the first interactor must remain in the loop forwarding
events to the subinteractor. This makes it easier for the input
system to clean up when the interactor terminates, and makes it
possible for the first interactor to regain control from the
subinteractor in situations where that is appropriate.
In this example, the ClickOrDragInteractor starts another
interactor when the mouse is moved. However, for that interactor to
receive mouse-moved events, StartMouseMovedEvents must first be called
on its MMouseEventHandler. There are two approaches you can take.
Either the first interactor calls StartMouseMovedEvents on the second
interactor, or it constructs a TMouseDownEvent and distributes it to
the second interactor before distributing the real TMouseMovedEvent
(letting the second interactor call StartMouseMovedEvents on itself if
it chooses). Each approach requires that the first interactor knows
the semantics of the second interactor.
In order for the primary interactor to behave properly, it must
own its subinteractor and delete it when the subinteractor is finished,
which can happen after any event is dispatched to the subinteractor. It
must also handle activate and deactivate requests and distribute them
to the subinteractor.
Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.