課題A4

課題A4では, JHotDrawの図形の選択機能について見ていきます.
JHotDrawはオープンソースの図形描画ツールで, Javaで書かれております.
ワークスペース内のjhotdraw7が、JHotDrawを構成するプロジェクトです。


前準備

課題A3が終了した直後は下図のような状態になっているはずです.

ここで, ステップバックオーバーを2回押してから, ステップオーバーを1回押してください.
そのあと, 変数ビュー上で「呼び出し後」を開いて, 戻り値を右クリックしてください.
右クリックするとポップアップメニューが現れるので, 「オブジェクトの追加時点に飛ぶ」を選択してください.

「オブジェクトの追加時点に飛ぶ」を選択すると, selectedFigures に この RectangleFigure クラスのインスタンス (id = 1952912699) が追加された時点である
DefaultDrawingView クラスの addToSelection(Figure) メソッドの780行目にまで現在の実行時点が遡ります.
下図の状態になっていれば前準備は終了です.


課題A4

ブレークポイントを置いた行は、図形を選択するたびに実行されます.

先ほどの前準備にしたがって進めていくと, 下図のように DefaultDrawingView クラスの
addToSelection(Figure) メソッド内の780行目で一時停止している状態になっているはずです.
この状態になっていれば, ここから時間計測を開始してください.

まずは,「実行時点の登録」ビューの追加ボタンをクリックして実行時点の登録を行ってください.
ここで, ソースコードと変数ビューを見ると, DefaultDrawingView クラスのインスタンス (id = 150367587) が保持するフィールド selectedFigures へは
RectangleFigure クラスのインスタンス (id = 1952912699) が追加されていることがわかります.
課題A4では, このオブジェクトの追加に関わっている DefaultDrawingView クラスのインスタンスと RectangleFigure クラスのインスタンスについて見ていきます.

まずは RectangleFigure がどこから来たのかを見るために, 呼び出しスタック上で1つ呼び出し元をクリックしてください.
ここで, ソースコードを見ると, 先ほど呼び出されていた addToSelection(Figure) メソッドは, ローカル変数 view で参照されているインスタンスに対する呼び出しであり,
その実引数としてフィールド anchorFigure の値が渡されていることがわかります.
また, 変数ビュー上の this を開くと, このフィールドは DefaultDragTracker クラスのインスタンス (id = 758826749) が保持していることがわかります.

ここでは, いったんローカル変数 view の値がどこから来たのかを見ていきます.
ステップバックオーバーを4回押して98行目に戻ってください.
ソースコードを見ると, getView() メソッドの戻り値を ローカル変数 view に代入していることが確認できます.
ここで, この戻り値がどうなっているのかを確認するために, ステップインを1回押して getView() メソッドの中に前から入ってください.

AbstractTool クラスの getView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDragTracker クラスのインスタンス (id = 758826749) が
DefaultDraingEditor クラスのインスタンス (id = 1859859960) を保持していることがわかります.
これを確認したら, ステップインを3回押して DefaultDrawingEditor クラスの getAcitiveView() メソッドの中に前から入ってください.

DefaultDrawingEditor クラスの getAcitiveView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDrawingEditor クラスのインスタンス (id = 1859859960) が
DefaultDrawingView クラスのインスタンス (id = 150367587) を保持していることがわかります.

先ほどの結果から, DefaultDrawingView クラスのインスタンス (id = 150367587) は
DefaultDrawingEditor クラスのインスタンス (id = 1859859960) が保持していることがわかりました.
呼び出しスタック上で2つ呼び出し元である DefaultDragTracker クラスの mousePressed(MouseEvent) メソッドをクリックしてください.

現在は, 呼び出し元である DefaultDragTracker クラスの mousePressed(MouseEvent) メソッドの98行目を見ています.
今までの結果から, DefaultDrawingView クラスのインスタンス (id = 150367587) がどのようにして来たのかがわかりました.
ここからは, RectangleFigure クラスのインスタンス (id = 1952912699) がどこから来たのかを見ていきます.
ここで, 変数ビュー上の this を開き, その中にある anchorFigure を右クリックしてください.
右クリックするとポップアップメニューが現れるので, 「値の代時点に飛ぶ」を選択してください.

「値の追加時点に飛ぶ」を選択すると, DefaulatDragTracker クラスのインスタンス (id = 758826749) に
この RectangleFigure クラスのインスタンス (id = 1952912699) が追加された時点である
DefaultDragTracker クラスの setDraggedFigure(Figure) メソッドの218行目にまで現在の実行時点が遡ります.
まずは, 「実行時点の登録」ビューの追加ボタンをクリックして実行時点の登録を行ってください.
ここでは, DefaultDragTracker クラスのフィールド anchorFigure に仮引数 f の値を代入していることが確認できます.
仮引数 f の値がどこから来たのかを見るために, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である SelectionTool クラスの getDragTracker() メソッド見ています.
ここで 変数ビュー上の 「呼び出し前」および this を開くと, 先ほどの setDraggedFigure (Figure) メソッドが呼び出されている
DefaultDragTracker クラスのインスタンス (id = 758826749) は DelegationSelectionTool クラスのインスタンス (id = 5999587451) が保持していることがわかります.
引き続き, 仮引数 f の値がどこから来ているのかを見るために, 呼び出しスタック上でさらに1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である DelegationSelectionTool クラスの mousePressed(MouseEvent) メソッドを見ています.
ここで, ソースコードを見ると, ここではローカル変数 figure の値が実引数として渡されていることが確認できます.

今度はこのローカル変数 figure の値がどこから来ているのかを見るために, ステップバックオーバーを3回押して270行目に戻ってください.
270行目では, ローカル変数 view で参照されるインスタンスに対して findFigure(Point) メソッドが呼び出され,
その戻り値がローカル変数 figure に代入されていることが確認できます.
この戻り値がどうなっているのかを確認するために, ステップインでこのメソッドの中に前から入ってください.

DefaultDrawingView クラスの findFigure(Point) メソッドに入りました.
ここで, ソースコードを見ると, このメソッドでは getDrawing() メソッドで取得してきたインスタンスに対して,
findFigure(Double) メソッドが呼び出され, その戻り値を返していることが確認できます.
これを確認したら, ステップインを2回押して, getDrawing() メソッドの中に前から入ってください.

DefaultDrawingView クラスの getDrawing() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDrawingView クラスのインスタンス (id = 150367587) が
フィールド drawing として QuadTreeDrawing クラスのインスタンス (id = 1583174451) を保持していることがわかります.
これを確認したら, ステップリターンを1回押して呼び出し元に戻ってください.

DefaultDrawingView クラスの findFigure(Point) メソッドに戻ってきました.
ここでは, まずステップネクストを1回押して viewToDrawingPoint(Point) メソッドを飛ばし,
それから, ステップインを1回押して QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドの中に前から入ってください.

QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドに入りました.
ここでは, ステップインを3回押して QuadTree クラスの findContains(Point2D$Double) メソッドの中に前から入ってください.

QuadTree クラスの findContains(Point2D$Double) メソッドに入りました.
ここで, 変数ビュー上の this を開くとQuadTree クラスのインスタンス (id = 808853315) がフィールド root として
QuadTree の内部クラス QuadNode クラスのインスタンス (id = 2120356010) を保持していることがわかります.
ここでは, ステップオーバーを1回押して83行目に進んだあと, ステップインを2回押して,
QuadTree$QuadNode クラスの findContains(Point2D$Double) メソッドの中に前から入ってください.

QuadTree$QuadNode クラスの findContains(Point2D$Double) メソッドに入りました.
ここで, 変数ビュー上の this を開くと, QuadTree$QuadNode クラスのインスタンスは
フィールド objects として HashMap を保持していることがわかります.

ここでは, ステップオーバーを3回押して226行目まで進んだあと, ステップネクストを2回押してください.
ソースコードを見ると, 224行目の拡張for文で 先ほど確認した HashMap から取得してきた要素を用いて,
226行目ではそのうちのキー要素だけを取り出して, それを仮引数 result で参照されているセットに追加していることが確認できます.
ここで, 変数ビュー上の「呼び出し後」および「呼び出し前」を開くと,
実際に RectangleFigure クラスのインスタンス (id = 1952912699) を取得してから追加していることを確認できます.
これを確認したら, ステップオーバーを4回押して呼び出し元に戻ってください.

呼び出し元である QuadTree クラスの findContains(Point2D$Double) メソッドの84行目に戻ってきました.
ここでは, ステップオーバーを1回実行し, このメソッド内ではローカル変数 result に何もオブジェクトが追加されず,
89行目の return result に現在の実行時点が移ることを確認してください.
これを確認したら, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドを見ています.
ここでは, まずステップオーバーを2回押して129行目まで進んでください.
129行目で「実行時点の登録」ビューの追加ボタンをクリックして実行時点の登録を行ってください.

現在は QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドの129行目にいます.
そのあと, ステップネクストを3回実行すると, 現在の実行時点が130行目に移ります.
ここで, 変数ビュー上の「呼び出し後」を開き, 戻り値として RectangleFigure クラスのインスタンス (id = 1952912699) があることを確認してください.
これを確認したら, 呼び出しスタック上で2つ呼び出し元をクリックしてください.

ここまでの結果から RectangleFigure クラスのインスタンスに関わる各オブジェクトの関係について, 以下のことがわかりました.

  1. RectangleFigure クラスのインスタンス (id = 1952912699) は QuadTree の内部クラス QuadNode クラスのインスタンス (id = 2120356010) が保持している.
  2. QuadTree の内部クラス QuadNode クラスのインスタンス (id = 2120356010) は QuadTree クラスのインスタンス (id = 808853315) が保持している.
  3. QuadTree クラスのインスタンス (id = 808853315) は QuadTreeDrawing クラスのインスタンス (id = 1583174451) が保持している.
  4. QuadTreeDrawing クラスのインスタンス (id = 1583174451) は DefaultDrawingView クラスのインスタンス (id = 150367587) が保持している.
ここからは, DefaultDrawingView クラスのインスタンス (id = 150367587) がどこから来たのかを見ていきます.
現在は, 呼び出し元である SelectionTool クラスの mousePressed(MouseEvent) メソッドの270行目を見ています.
ここで, ソースコードを見ると, このDefaultDrawingView クラスのインスタンスはローカル変数 view で参照されていることが確認できます.

このローカル変数 view の値がどこから来たのかを見るために, ステップバックオーバーを10回押して228行目にまで戻ってください.
228行目では, ローカル変数 view に getView() メソッドの戻り値を代入していることが確認できます.
ここで, この戻り値がどうなっているのかを確認するために, ステップインを1回押して getView() メソッドの中に前から入ってください.

AbstractTool クラスの getView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DelegationSelectionTool クラスのインスタンス (id = 599587451) が
DefaultDraingEditor クラスのインスタンス (id = 1859859960) を保持していることがわかります.
これを確認したら, ステップインを3回押して DefaultDrawingEditor クラスの getAcitiveView() メソッドの中に前から入ってください.

DefaultDrawingEditor クラスの getAcitiveView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDrawingEditor クラスのインスタンス (id = 1859859960) が
DefaultDrawingView クラスのインスタンス (id = 150367587) を保持していることがわかります.

先ほどの結果から, DefaultDrawingView クラスのインスタンス (id = 150367587) は
DefaultDrawingEditor クラスのインスタンス (id = 1859859960) が保持していることがわかりました.
呼び出しスタック上で2つ呼び出し元をクリックしてください.
ここで, 課題A4は終了です. 時間計測を終了してください.