例: IlvObjectInteractor クラスの機能拡張

この例で定義した MoveObjectInteractor クラスを使用すると、マウスでオブジェクトを移動したり、マウス・ボタンを放す場所までオブジェクトを移動したりできます。この例の完全コードは、インストール済みの製品の codefragments/interactors/moveobjinter/src/MoveObjectInteractor.javaMoveObjectInteractor.java にあります。詳細については、 <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();
  }
  ...
}
MoveObjectInteractorIlvObjectInteractor クラスの機能を拡張し、次の属性を定義します。
  • 属性 mrect は、グラフィック・オブジェクトの将来の矩形領域を指定します。このデータはオブジェクトをドラッグするたびに更新されます。
  • dx 属性と dy 属性は、元のクリック・ポイントからの移動とグラフィック・オブジェクトの現在の左上隅ポイントを表します。
  • ブール型値 dragging は、オブジェクトのドラッグを開始すると、true に設定されます。
イベントは、次のように processEvent メソッドで処理されます。
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;
   }
}
processEvent メソッドは、そのタイプにより 3 つの異なるメソッドにイベントをディスパッチします。processEvent メソッドは、パラメーターとしてグラフィック・オブジェクト、イベント、コンテキストを取ります。コンテキスト IlvObjectInteractorContext は、オブジェクト・インタラクターを使用できるようにするためにクラスが実装する必要のあるインターフェースです。クラス IlvManager は、それを処理し、コンテキスト・オブジェクトをオブジェクト・インタラクターに渡します。コンテキストで、トランスフォーマーの取得、マウス・カーソルの変更などができます。
次の processButtonDown メソッドでは、クリック・ポイントとグラフィック・オブジェクトの現在の左上隅ポイント間の距離は、属性 dxdy に格納されます。位置はビューの座標系に保存されます。グラフィック・オブジェクトの左上隅はオブジェクトの矩形領域から抽出され、boundingBox メソッドで計算されます。次に invalidateGhost メソッドを呼び出します。このメソッドではインタラクター・コンテキストを要求し、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; 
}
invalidateGhost メソッドは次のように実装されます。
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);
}
ゴーストの描画および消去の原則は次のとおりです。ゴーストの描画が行われるのは描画システムによって要求される場合のみであり、インタラクターはコンテキストの領域 (位置変更前後のゴーストの範囲) を無効にします。基本クラス IlvObjectInteractor に定義されたメソッド handleExpose は、ビューが再描画されたときだけに呼び出されます。基本クラスで実装しても何も実行しないこのメソッドは、次のようにオーバーライドされます。
public void handleExpose(IlvGraphic obj, 
                         Graphics g,
                                   IlvObjectInteractorContext context) 
{ 
  drawGhost(obj, g, context);
}
ゴーストの実際の描画は、次の drawGhost メソッドで行われます。
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);
  }
}
引数として渡された Graphics オブジェクトは、デフォルトの XOR 色とコンテキストに定義されたゴーストの色を使用して XOR モードに設定されます。次に、トランスフォーマーが計算され、mrect が指定する目的の場所にオブジェクトが描画されます。オブジェクトは移動させないで、別の場所で描画されます。mrectnull の場合は、メソッドは何も行いません。これで、インタラクション終了後に drawGhost メソッドが呼び出されたときに、ゴーストが描画されないようにできます。
マウス・ドラッグされたイベントは、以下のように処理されます。
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;
}
まず、invalidateGhost を呼び出して、現行ゴーストを無効にします。新規の目的の場所が、元の位置と一緒に移動してマウスの位置に移動します。
mrect.move(p.x - dx, p.y - dy); 
次に ensureVisible がコンテキストで呼び出されます。現在のドラッグ先のポイントがビューの可視領域外の場合は、マネージャーのビューをスクロールしてドラッグ先ポイントが可視になるようにします。この操作を行うと、mrect の値がビューの座標系に保存されるため、ビューのトランスフォーマーが変わることがあります。ensureVisible を呼び出す前に、次のように mrect の値をマネージャー座標系に変換します。
IlvTransformer t = context.getTransformer();
if (t != null) t.inverse(mrect);
ensureVisible を呼び出した後、次のように mrect の値を変換してビューの座標系に戻します。
t = context.getTransformer(); 
if (t != null) t.apply(mrect);
グラフィック・オブジェクトの実際の移動は、マウス・ボタンを放したときに行われます。マウスを放して行うイベントは、次のように処理します。
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; 
}
まず、invalidateGhost メソッドを呼び出して、ゴーストを無効にします。次に、doMove メソッドを呼び出します。このメソッドは、mrect の最終座標に基づいてグラフィック・オブジェクトの位置を更新します。オブジェクトを移動後、mrectnull に設定し、ゴーストをそれ以上描画できないようにします。
メソッド doMove の実装は次のとおりです。
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);
}
mrect の値は、次のようにマネージャーの座標系に変換されます。
IlvTransformer t = context.getTransformer();
if (t != null) 
  t.inverse(mrect);
グラフィック・オブジェクトのメソッドを直接呼び出して、管理済みグラフィック・オブジェクトの位置または形状を直接変更することのないようにしてください (より正確にいえば、バウンディング・ボックスを変更しないでください)。そのような変更は関数で行う必要があります。この場合は moveObject で、マネージャーに適用され、必要な予防措置をすべて実行します。詳細については、「オブジェクトのジオメトリー・プロパティーの変更」を参照してください。