The
MoveObjectInteractor class
defined in this example allows you to move an object using the mouse,
moving it to where you release the mouse button. You can see the complete
code of the example in
MoveObjectInteractor.java located
at
codefragments/interactors/moveobjinter/src/MoveObjectInteractor.java in
the installed product. For details, see
<installdir>
/jviews-framework89/codefragments/interactors/moveobjinter/index.html.
public class MoveObjectInteractor extends IlvObjectInteractor
{
private IlvRect mrect;
private float dx, dy;
private boolean dragging = false;
/** Creates an moveObjectInteractor. */
public MoveObjectInteractor()
{
super();
}
...
}
The MoveObjectInteractor
extends
the IlvObjectInteractor
class and defines
the following attributes:
The attribute mrect
specifies
the future bounding rectangle of the graphic object. This data is
updated each time the object is dragged.
The dx
and dy
attributes
represent the translation from the original clicked point and the
current top-left corner of the graphic object.
The Boolean value dragging
is
set to true
when the user starts dragging
the object.
Events are processed by the processEvent
method
as follows.
protected boolean processEvent(IlvGraphic obj, AWTEvent event,
IlvObjectInteractorContext context)
{
switch (event.getID())
{
case MouseEvent.MOUSE_PRESSED:
return processButtonDown(obj, (MouseEvent)event, context);
case MouseEvent.MOUSE_DRAGGED:
return processButtonDragged(obj, (MouseEvent)event, context);
case MouseEvent.MOUSE_RELEASED:
return processButtonUp(obj, (MouseEvent)event, context);
default:
return false;
}
}
The
processEvent
method dispatches
events to three different methods depending on their type. The
processEvent
method
takes a graphic object, an event, and a context as its parameters.
The context
IlvObjectInteractorContext is an interface that must be implemented by classes
allowing the use of an object interactor. The class
IlvManager takes care of that and passes a context object to
the object interactor. From a context, you can get a transformer,
change the mouse cursor, and so on.
In the processButtonDown
method,
the distance between the clicked point and the current top-left corner
of the graphic object is stored in the attributes dx
and dy
.
Note that the positions are stored in the view coordinate system.
The top-left corner of the graphic object is extracted from the bounding
rectangle of the object, which is computed using the boundingBox
method.
The invalidateGhost
method is then called.
This method requests the interactor context to redraw the region corresponding
to the current bounding rectangle (stored in mrect
).
public boolean
processButtonDown(IlvGraphic obj,
MouseEvent event,
IlvObjectInteractorContext context)
{
if ((event.getModifiers() & InputEvent.BUTTON2_MASK) != 0 ||
(event.getModifiers() & InputEvent.BUTTON3_MASK) != 0)
return true ;
if (dragging)
return true ;
dragging = true;
IlvPoint p = new IlvPoint(event.getX(), event.getY());
mrect = obj.boundingBox(context.getTransformer());
dx = p.x - mrect.x;
dy = p.y - mrect.y;
invalidateGhost(obj, context);
return true;
}
The invalidateGhost
method
is implemented as follows..
private void
invalidateGhost(IlvGraphic obj,
IlvObjectInteractorContext context)
{
if (obj == null || context == null)
return;
if (mrect == null || mrect.width == 0 || mrect.height == 0)
return;
IlvRect invalidRegion = new IlvRect(mrect);
context.repaint(invalidRegion);
}
The principle for drawing and erasing the ghost is as
follows: the interactor invalidates regions of the context (the bounds
of the ghost before and after any position change), while the drawing
of the ghost is only performed when requested by the drawing system.
Indeed, the method handleExpose
, defined
on the base class IlvObjectInteractor
,
is called only when the view is redrawn. This method, whose implementation
in the base class does nothing, is overridden as follows.
public void handleExpose(IlvGraphic obj,
Graphics g,
IlvObjectInteractorContext context)
{
drawGhost(obj, g, context);
}
The actual drawing of the ghost is done by the following drawGhost
method..
protected void drawGhost(IlvGraphic obj,
Graphics g,
IlvObjectInteractorContext context)
{
if (mrect != null) {
g.setColor(context.getDefaultGhostColor());
g.setXORMode(context.getDefaultXORColor());
IlvTransformer t = context.getTransformer();
IlvRect r = obj.boundingBox(t);
IlvTransformer t1 = new IlvTransformer(new IlvPoint(mrect.x - r.x,
mrect.y -r.y));
t.compose(t1);
obj.draw(g, t);
}
}
The Graphics
object that is
passed as an argument is set to XOR mode using the default XOR color
and ghost color defined in the context. Next, a transformer is computed
that will draw the object in the desired location given by mrect
.
Note that the object is not translated, only drawn at another location.
The method does nothing if mrect
is null
.
This prevents the ghost from being drawn if the drawGhost
method
happens to be called after the end of the interaction.
Mouse dragged events are handled as follows.
protected boolean
processButtonDragged(IlvGraphic obj, MouseEvent event,
IlvObjectInteractorContext context)
{
if (!dragging || mrect == null)
return false;
IlvPoint p = new IlvPoint(event.getX(), event.getY());
invalidateGhost(obj, context);
mrect.move(p.x - dx, p.y - dy);
IlvTransformer t = context.getTransformer();
if (t != null)
t.inverse(mrect);
context.ensureVisible(p);
t = context.getTransformer();
if (t != null)
t.apply(mrect);
invalidateGhost(obj, context);
return true;
}
First the current ghost is invalidated by a call to invalidateGhost
.
The new required location is changed to the position of the mouse,
translated with the original translation.
mrect.move(p.x - dx, p.y - dy);
Then ensureVisible
is called
on the context. If the current dragged point is outside the visible
area of the view, this will scroll the view of the manager so that
the dragged point becomes visible. This operation may change the transformer
of the view, as the value of mrect
is stored
in the coordinate system of the view. Before ensureVisible
is
called, the value of mrect
is transformed
to the manager coordinate system as follows.
IlvTransformer t = context.getTransformer();
if (t != null) t.inverse(mrect);
After the call to ensureVisible
,
the value of mrect
is transformed back
to the view coordinate system as follows.
t = context.getTransformer();
if (t != null) t.apply(mrect);
The actual moving of the graphic object is done when
the mouse button is released. The mouse released event is handled
like this:
protected boolean
processButtonUp(IlvGraphic obj,
MouseEvent event,
IlvObjectInteractorContext context)
{
if (!dragging || mrect == null)
return true;
dragging = false;
invalidateGhost(obj, context);
doMove(obj, context);
mrect = null;
return true;
}
First the ghost is invalidated by calling the invalidateGhost
method.
Then the doMove
method is called. This
method updates the position of the graphic object according to the
final coordinates of mrect
. After moving
the object, mrect
is set to null
to
prevent further drawing of the ghost.
The implementation of the method doMove
is
as follows
void doMove(IlvGraphic graphic,
IlvObjectInteractorContext context)
{
if (mrect == null)
return;
IlvTransformer t = context.getTransformer();
if (t != null)
t.inverse(mrect);
graphic.getGraphicBag().moveObject(graphic, mrect.x,
mrect.y, true);
}
The value of mrect
is translated
to the coordinate system of the manager as follows.
IlvTransformer t = context.getTransformer();
if (t != null)
t.inverse(mrect);
You should never try to change the position or the shape
of a managed graphic object directly (or, more precisely, to modify
its bounding box), for example by calling methods of the graphic object
directly. Such changes must be done through a function, in this case
moveObject
,
which is applicable to managers and takes all the necessary precautions.
For further information, see
Modifying geometric properties of objects.