ガントチャートを作成するときはプロジェクトを完成させるために必要なタスクを洗い出します。大まかなタスクに分けることができたら、これをさらに細かく分けて「子タスク」をつくります。今回は「子タスク」をカテゴリ分けできるようにします。またこれまではタスクは一番下に追加することしかできませんでしたが、任意の場所に追加できるようにします。

そのためにフォームの左側にカテゴリ表示用の領域をつくります。各タスクはカテゴリの右側につくられます。

それからデータ構造をはっきりとつくります。これまではタスクを作って設定することができてもこれをデータファイルとして保存することはできませんでした。将来、ファイルとして保存し読み出しができるものとして完成させるためにデータ構造をつくります。

カテゴリオブジェクトをつくってそのなかにタスクをリストとして持たせます。そしてカテゴリオブジェクトもリストに格納します。

パネルを右クリックしたらあたらしいカテゴリを追加します。そしてカテゴリのなかにタスクを自動的に追加します。

またカテゴリを右クリックしたらその上側や下側に新しいカテゴリを追加できるようにします。また一番下にタスクを追加できるようにします。タスクを右クリックしたらこれまでのようにタスクの詳細を設定できるようにするほかにこのタスクの上側や下側に新しいタスクを追加できるようにします。

まずカテゴリの表すコントロールとクラスを作成します。

まずコンテキストメニューを表示できるように、コンストラクタ内で自作メソッドInitContextMenuを実行します。CategoryUserControl上で右クリックしたら、[このカテゴリ前に新しいカテゴリを追加]、[このカテゴリ次に新しいカテゴリを追加]、[このカテゴリの一番下にタスクを追加]のメニューを表示します。

またCategoryUserControlはリストで管理するので、これを格納するリストをコンストラクタで渡します。これで新しいCategoryUserControlがどの部分に挿入されるかもわかります。

[このカテゴリ前に新しいカテゴリを追加]、または[このカテゴリ次に新しいカテゴリを追加]が選択されたら新しいCategoryAddedイベントを発生させてCategoryUserControlが挿入される場所を知らせます。実際に新しいCategoryUserControlを挿入する処理はForm1でおこないます。

以下はイベントハンドラの引数です。新しいCategoryUserControlはIndexの位置に入ります。

コンテキストメニューの[このカテゴリの一番下にタスクを追加]が選択されたときの処理を示します。新しいTaskUserControlはCategoryUserControlのなかにあるTaskUserControlsの一番最後に入ります。これもどの位置にTaskUserControlが追加されるかをイベントハンドラの引数でForm1クラスに知らせます。

以下はイベントハンドラの引数です。新しいTaskUserControlはIndexの位置に入ります。

次にTaskUserControlクラスを変更します。

まずコンストラクタの引数を変更します。TaskUserControlの親コントロールになるCategoryUserControlを引数として渡します。またCategoryUserControlが持っているTaskUserControlのリストもいっしょに渡します。

次に右クリックされたときに表示するコンテキストメニューをつくる処理を示します。

コンテキストメニュー[この下にタスク追加]が選択されたらこの下に新しいタスクをつくる処理を示します。イベントTaskInsertedを定義します。右クリックされたTaskUserControlがどれかわかればその下が上から何番目かがわかります。作成したTaskUserControlをリストに追加し、イベントハンドラで追加されたTaskUserControlをForm1クラスに伝えます。

[この上にタスク追加]が選択されたときも同じように処理をします。

Form1クラスも変更が必要です。

まずコンストラクタですが、PanelMainの幅にあわせてCategoryUserControlの幅が変化するようにしてしまうとPanelMainの高さでは収まりきらないCategoryUserControlが生成されると縦スクロールバーが現れます。するとスクロールバーが現れる前と後ではCategoryUserControlの幅が違ってくるという問題がおきるので、最初から縦スクロールバーを表示させることにします。

このとき最初からAutoScrollがtrueだとVerticalScroll.Visible = trueとやっても意味がありません。そこで最初はfalseにして、VerticalScroll.Visible = trueにしてからAutoScroll = trueにするという変な処理をしています。これでPanelMainに常に縦スクロールバーを表示されるようになります。

PanelMainを右クリックされたときに表示されるコンテキストメニューの初期化の処理ですが、[カテゴリを追加]だけにしました。

PanelMainに表示されるCategoryUserControlをリストで管理するためにCategoryUserControlのリストをつくります。そして右クリックで[カテゴリを追加]が選択されたらカテゴリを一番下に追加してそのなかにタスクをつくります。このとき追加されるCategoryUserControlとTaskUserControlはイベントに対応できるようにイベントハンドラを追加しておきます。

コントロールが追加されたらじっさいに表示させるために自作メソッドShowChartを呼び出します。そして追加されたコントロールが見えるようにPanelMainをスクロールさせます。

CategoryUserControl上で[カテゴリを(上または下に)追加する]が選択されたときの処理を示します。CategoryUserControlを生成してCategoryUserControlsとPanelMain.Controlsに追加(後者を忘れると表示されない)します。そして追加されたCategoryUserControlが表示されるようにPanelMainをスクロールさせます。

CategoryUserControl上で[タスクを追加する]が選択されたときの処理を示します。TaskUserControlを生成してCategoryUserControl.TaskUserControlsとCategoryUserControl.Controlsに追加します。これも後者を忘れると追加したコントロールが表示されません。追加したら追加されたコントロールが表示されるようにPanelMainをスクロールさせます。

TaskUserControl上で右クリックされてTaskUserControlが追加されたときの処理を示します。この場合はすでに処理はTaskUserControlクラスで行なわれているので、ここでやることは追加されたコントロールが表示されるようにPanelMainをスクロールさせるだけです。

コントロールが追加されたときは表示順が変わっているかもしれないので一番上に表示されるものから配置しなおす必要があります。そのための処理を示します。

CategoryUserControlのPanelMain上におけるX座標0でよいのですが、幅はスクロールバーが表示されるぶん、短くしています。またCategoryUserControl上に表示されるTaskUserControlのX座標はleftMarginTaskUserControl(=200)だけ右寄りとし、幅もそれだけ短くなっています。

[チャートの設定]ボタンがクリックされたときの処理もCategoryUserControlが加わったので書き直しとなります。

またこの処理をおこなうにあたって必要なGetFirstTaskUserControlメソッドですが、スクロールされていてY座標が0未満のものをつかってもなにもおきないのでTaskUserControlであり、Y座標が正で最小のものを取得しています。

それ以外のメソッドにとくに変更はありません。