2.0から追加されたWindowsアプリケーションのコントロール、FlowLayoutPanelとTableLayoutPanelコントロールについて説明します。これらのコントロールはコンテナとして働き、複数のコントロールを整列させたい時に使用します。注意この記事の最新版は「FlowLayoutPanelコントロールの基本的な使い方」で公開しています。FlowLayoutPanelコントロールについて、MSDNでは次のように説明されています。コントロールは、その内容を水平または垂直のフロー方向に整列させます。内容は次の行または次の列に折り返すことができます。折り返さずにクリップすることもできます。フォーム)言葉で説明するより、実際に使ってみるのが一番早いというわけで、次のURLにFlowLayoutPanelを使ったサンプル(FlowLayoutPanel1.exe)を置いておきます。(ソースコードも置いておきます。2.0がインストールされている必要があります。FlowLayoutPanelコントロールの基本的な使い方このサンプルは、フォームにFlowLayoutPanelコントロールを配置し、DockプロパティをFillとし、Buttonコントロールを15個配置したものです。フォームの大きさを変更させると、Buttonコントロールが右端で折り返されて整列することが確認できるでしょう。FlowLayoutPanelコントロールには、重要なプロパティとして、FlowDirectionとWrapContentsがあります。FlowDirectionプロパティは、整列の方向を指定するために使用します。WrapContentsプロパティは、FlowLayoutPanelに配置したコントロールを折り返して整列させるかを指定するために使用します。サンプル「FlowLayoutPanel1.exe」では、FlowDirectionとWrapContentsプロパティを試すため、メニューを使ってFlowLayoutPanelコントロールのFlowDirectionとWrapContentsプロパティの値を簡単に変更できるようになっています。実際にこれらの値を変更させるとどのように変化するのかを試してみてください。†FlowLayoutPanelコントロールに配置された子コントロールは、AnchorとDockプロパティに、通常とは少し異なる特別な役割が与えられています。これに関しては、MSDNで説明されています。コントロールで子コントロールを固定およびドッキングするこれを実際に確認するためのサンプルが次に紹介する「FlowLayoutPanel2.exe」です。FlowLayoutPanelコントロールの基本的な使い方このサンプルでは、様々な大きさのButtonコントロールがFlowLayoutPanelコントロールに配置されています。Buttonコントロールを右クリックすることにより、コンテキストメニューが表示され、ButtonのAnchorとDockプロパティを簡単に変更できるようになっています。FlowLayoutPanelのFlowDirectionプロパティがLeftToRightの時、ButtonのAnchorをTopにすると、Buttonはその列の一番上に配置されるようになります。AnchorをBottomにすると、逆に一番下に配置されます。TopとBottom両方を指定すると、列の幅いっぱいに広がります。Noneでは中央に配置されます。LeftとRightは、この場合は、関係ありません。Dockプロパティも同様に、Topで一番上、Bottomで一番下、Fillで幅いっぱいに配置されるようになります。†さらにこのサンプルでは、FlowLayoutPanelコントロールに配置されたコントロールのFlowBreakプロパティを変更することもできます。FlowBreakプロパティをTrueとすることにより、そのコントロールの次で強制的に折り返して整列されるようになります。2005のデザイナのプロパティウィンドウで変更することができますが、実際のコントロールのクラスにFlowBreakというプロパティが存在するわけではありません。実際にはFlowLayoutPanelコントロールのSetFlowBreakメソッドを使って指定します。FlowLayoutPanelコントロール「FlowLayoutPanel1」に配置されたButtonコントロール「Button1」のFlowBreakプロパティをTrueにするには、次のようにします。true);また、Button1のFlowBreakの状態を調べるには、FlowLayoutPanel.GetFlowBreakメソッドを使います。注意この記事の最新版は「FlowLayoutPanelに配置されたコントロールの順番を変更する」で公開しています。FlowLayoutPanelに配置されるコントロールの順番は、FlowLayoutPanel.Controlsコレクションの順番で決まるようです。よって、コントロールの順番を変更するには、変更するコントロール以降のコントロールをすべて削除してから、追加しなおさなければならないようです。サンプル「FlowLayoutPanel2.exe」で、コントロールを先頭に移動する例を紹介しています。以下にその抜粋を示します。currentButtonというコントロールを移動させています。注意この記事の最新版は「TableLayoutPanelコントロールの基本的な使い方」で公開しています。TableLayoutPanelコントロールは、まるでHTMLのTABLEタグのようなコントロールと言えば分かりやすいでしょうか。MSDNでは、次のように説明されています。コントロールは、実行時に比例的なサイズ変更機能を提供するため、フォームのサイズ変更に合わせてレイアウトを滑らかに変更できます。コントロールは、データ入力フォームやアプリケーションのローカライズなどに適しています。コントロールの推奨される手順」では、TableLayoutPanelコントロールをどのようなケースで使用し、どのようなケースでは使用すべきではないかが説明されています。コントロールの推奨される手順これによると、親フォームのサイズ変更や、ローカリゼーションに伴いコントロールに表示するテキストの長さが変更されるようなケースでTableLayoutPanelコントロールを使うのが有効であるということです。逆にTableLayoutPanelコントロールのDockプロパティをFillにする、TableLayoutPanelに別のTableLayoutPanelを配置して入れ子にする、TableLayoutPanelを配置したフォームを継承したフォームでさらにコントロールを追加する、列がレベルとテキストの2つしかない単純なフォームで使用するなどといったことは推奨されていません。このような推奨事項を守る限り、TableLayoutPanelコントロールの使い道はごく限られそうです。(巷に出回っているTableLayoutPanelコントロールのサンプルは、これらの推奨事項を無視しているものがほとんどですので、注意が必要です。フォーム)」などに詳しいです。Studioのフォームデザイナを使った場合の説明であり、コードによる説明はほとんどありません。そこでここでは、実行時に行うにはどうするかを中心に説明します。TableLayoutPanelコントロールの実際の挙動を確かめるためのサンプル(TableLayoutPanel1.exe)も用意しました。†MSDNでは、フォームデザイナを使った方法が次のページなどで説明されています。フォームの作成TableLayoutPanelコントロール内にコントロールを配置するには、Controls.Addメソッドを使います。このメソッドではコントロールを挿入するセルの位置を指定することができます。メソッドTableLayoutPanelコントロールは一つのセルに一つのコントロールしか入れることができません(セルにPanelを配置し、そこに複数のコントロールを配置することはできます)。よって指定した挿入位置にすでにコントロールがあるときは、それ以降のコントロールが押し出されるように次のセルに移動します。Controls.Addでは挿入位置を指定しなくても大丈夫です。挿入位置を指定しなかった場合は、右上の空いているセルから順番に配置されます。-1)を指定したことになります。)すべてのセルがすでに埋まっている時に新しいコントロールを追加した時の動作は、TableLayoutPanel.GrowStyleプロパティにより異なります。GrowStyleプロパティがAddRowsのとき(デフォルト)は行を拡張し、AddColumnsのときは列を拡張します。FixedSizeのときは、例外ArgumentExceptionがスローされます。次の例では、insertRowとinsertColumnで指定された位置にButtonコントロールを追加しています。挿入位置にコントロールがあるか調べ、無いときのみ挿入しています。insertRow);}サンプル「TableLayoutPanel1.exe」でも、メニューから簡単にButtonコントロールの追加や、TableLayoutPanel.GrowStyleプロパティの変更を行うことができますので、お試しください。†TableLayoutPanelに配置されたコントロールが占有しているセルの位置を取得する方法としてTableLayoutPanelクラスには、GetColumn、GetRow、GetCellPosition、GetPositionFromControlといったメソッドが用意されています。この内、GetColumn、GetRowとGetCellPositionは同じですが、これらとGetPositionFromControlは似ているようで全く異なります。列数が十分にあるTableLayoutPanel「tableLayoutPanel1」に次のように2つのボタンを配置したとします。0);このときは、button1に対してGetCellPositionとGetPositionFromControlが返す値は同じ(0,0)になります。button2に対しても両者とも(1,0)となります。0);button3が(0,0)に入ることにより、button1は(1,0)に、button2は(2,0)に追い出されます。このとき、button1とbutton2に対してGetPositionFromControlが返す値は(1,0)と(2,0)になりますが、GetCellPositionが返す値は(0,0)と(1,0)のままです。button3に対してGetCellPositionとGetPositionFromControlが返す値は(0,0)ですので、GetCellPositionが(0,0)を返すコントロールが2つ存在することになります。GetPositionFromControlは現在実際にコントロールが占有しているセルの位置を返し、GetCellPositionはControls.Add(あるいはTableLayoutPanel.SetCellPositionメソッド)で指定された値を返すということになります。位置を指定しないでControls.Addを呼び出したコントロールに対しては、GetCellPositionは(-1,-1)を返します。VS2005のフォームデザイナのみでコントロールを配置した場合はGetCellPositionとGetPositionFromControlは一致すると考えてよさそうですが、実行時に配置したコントロールがある場合は、そうならない可能性があることを知っておくべきでしょう。実際の現在位置を返します。」とありますが、これはこういう意味だったのです。上で紹介した例に、次のようにしてもう一つbuttonを追加してみましょう。0);ちょっと意外ですが、button4は(2,0)の位置、つまりbutton1とbutton2の間に挿入されます。GetCellPositionが(0,0)であるbutton1が優先されるようなのです。それでは、間違いなく指定した位置のセルにコントロールを配置するにはどうすればいいのかということになると、あまりいい方法が思いつきません。一つの方法として、次のように実際に配置されている位置をGetCellPositionが返す位置に強制的に設定してしまってから、コントロールを追加するやり方が考えられます。†これもまた分かりにくい話ですが、TableLayoutPanelのColumnCountやRowCountプロパティは、実際の列数や行数と一致するとは限りません。実行時にコントロールをTableLayoutPanelに追加して実際の列数や行数が拡張された場合でも、ColumnCountやRowCountの値は変更されませんので、実際の列数、行数と違いが出てしまいます。これらのプロパティはTableLayoutPanelのGrowStyleプロパティがFixedSizeの場合のみ実際の列数や行数と必ず一致し、GrowStyleがAddColumnsまたはAddRowsの場合は、RowCountまたはColumnCountだけが実際の列数や行数と必ず一致するということになります。プロパティそれでは実際の列数と行数を取得するにはどのようにすればよいかというと、...これがよく分かりません。TableLayoutPanelに配置されているすべてのコントロールの実際の位置をGetPositionFromControlで取得して、その最大値とColumnCountまたはRowCountの大きい方が実際の列数または行数であるとする以外の良い方法が今のところ見つかりません。今回、予想外に記事が長くなってしまいましたので、きりが良くないのですが、続きは次回とさせていただきます。