
グラフの自動レイアウトに挑戦 #2 Windows Formで表示
ソースコード
今回の中間ソースコードのダウンロード (zip/tar, 13.6KB)
今回の完成ソースコードのダウンロード (zip/tar, 14.1KB)
はじめに
前回は「Eadesのばねモデル」を使ってノードにかかる力を計算するところまで実装した。
今回はWindows Formを使ってアニメーション表示してみたいと思う。
ただし、今回は「やってはいけない」アンチパターンとして、わざとVisual Studioにおまかせ状態で、頭を使わずに書いてみる。
おすすめパターンは、次回にとっておくのでそのつもりで。
初期化ロジック
プロジェクトを「Windows フォーム アプリケーション」に変更し、MainForm.csを追加する。そして、このフォームのプライベートフィールドとして、前回作ったノードコレクションを置く。
このままだとnodesフィールドがnullなので、どこかで初期化しないといけない。ってことで、MainFormのコンストラクタに書く。
ついでに初期配置もしておこう。初期状態だと、ノード間の距離が0になってしまうのでいろいろ不都合なのだ。とりあえず円形に並べておく。
描画ロジック
描画のため、MainFormのPaintイベントにイベントハンドラを書く。
ノードは円、エッジは線で表現した。なお、ノードの座標を画面上の座標に変換するためのメソッドを用意した。
物理シミュレーション作動
MainFormにはボタンとタイマーを追加する。

ボタンのClickイベントでタイマーの開始/停止を制御する。タイマーのTickイベントでnodesを動かして画面を再描画する。
この段階が、冒頭に示した中間ソースコードである。
実行するとノードが動き出した。エッジはばねでできており、ノード同士には反発力が働くというEadesのばねモデルの通りに動いているように見える。

しかし、ノードの動きが平衡状態に近づいても、結果として得られたレイアウトは美しいとは言いがたい。エッジが絡まっているからだ。シミュレーション実行中に、ノードの位置を自由に変更できないだろうか。
ノードをドラッグできるようにする
マウスの左ボタンを押している間は、マウスカーソルに最も近かったノードの位置を自由に変更できるようにしよう。ドラッグしているノードはばねモデルに従わずに、マウスカーソルの位置に追随する。左ボタンを離せば、ノードは再びばねモデルにしたがって動き出す。
これを実装するためにソースコードを変更する。まずはノードコレクション。ノードをロック/ドラッグ/アンロックするメソッドを実装した。
そして、ロックされたノードがばねモデルに従わないようにMoveAllメソッドを修正する。
次はMainForm。マウスの左ボタンのアップダウンイベント、およびマウスカーソルの移動イベントでノードコレクションにメッセージを送る。
ついでに、ロックされたノードは赤い円で描画するようにしよう。
この段階が、冒頭に示した完成ソースコードである。
今度は、実行中にノードを「引っ張る」ことができる。

適当に引っ張っていたら、エッジが絡まないように配置できた。

次回は、Model-View-Controller(MVC)パターンに適合するように、このプログラムをリファクタリングしてみたいと思う。