C# SplitContainerの使い方|画面分割・サイズ調整・固定方法をサンプルで解説
はじめに
C#でWindowsフォームアプリを作成していると、「左側にメニュー、右側に詳細画面を表示したい」「上に検索条件、下に一覧を表示したい」といった画面分割レイアウトを作りたくなる場面があります。
そのようなときに便利なのが、Windows FormsのSplitContainerコントロールです。
SplitContainerを使うと、フォーム上の領域を2つのパネルに分割し、ユーザーが境界線をドラッグしてサイズを変更できる画面を簡単に作成できます。また、分割位置を固定したり、片側のパネルだけサイズを固定したり、パネルを折りたたんで非表示にしたりすることも可能です。
この記事では、C# SplitContainerの基本的な使い方から、サイズ調整、分割位置の固定、イベント活用、よくあるエラーの対処法まで、サンプルコード付きで解説します。
1. C#のSplitContainerとは
SplitContainerは、Windows Formsで画面を2つの領域に分割するためのコントロールです。
フォーム上にSplitContainerを配置すると、内部にPanel1とPanel2という2つのパネルが作成されます。この2つのパネルの間には、サイズ変更用の境界線であるSplitterが表示されます。
たとえば、次のような画面を作るときに使用します。
C#左側:メニュー
右側:メイン画面
または、次のような上下分割の画面にも使えます。
C#上側:検索条件
下側:検索結果一覧
C#のWindows Formsアプリで柔軟なレイアウトを作る場合、SplitContainerは非常によく使われるコントロールです。
1-1. SplitContainerでできること
SplitContainerを使うと、主に次のようなことができます。
C#・画面を左右または上下に分割する
・Panel1とPanel2に別々のコントロールを配置する
・ユーザーが境界線をドラッグしてサイズを変更する
・分割位置をコードから指定する
・分割位置を固定する
・片側のパネルを非表示にする
・フォームサイズ変更に合わせてレイアウトを自動調整する
たとえば、業務アプリでよくある「左メニュー+右詳細画面」や「検索条件+一覧表」のようなレイアウトは、SplitContainerを使うと簡単に実装できます。
1-2. Panel1・Panel2・Splitterの役割
SplitContainerは、主に次の3つの要素で構成されています。
C#Panel1 :分割された片側の領域
Panel2 :もう片側の領域
Splitter :Panel1とPanel2の境界線
左右分割の場合、通常は左側がPanel1、右側がPanel2になります。
C#splitContainer1.Panel1.Controls.Add(menuPanel);
splitContainer1.Panel2.Controls.Add(mainPanel);
上下分割の場合、通常は上側がPanel1、下側がPanel2になります。
C#splitContainer1.Orientation = Orientation.Horizontal;
Splitterは、ユーザーがドラッグして分割位置を変更するための境界線です。境界線の位置はSplitterDistanceプロパティで設定できます。
C#splitContainer1.SplitterDistance = 200;
1-3. SplitContainerを使うメリット
SplitContainerを使うメリットは、画面分割レイアウトを簡単に作成できることです。
通常、フォーム上で複数のパネルを手動配置し、サイズ変更時の動きをすべて自分で制御しようとすると、ResizeイベントやAnchor、Dockの調整が複雑になります。
しかし、SplitContainerを使えば、2つの領域のサイズ調整や境界線のドラッグ操作を標準機能として扱えます。
C#splitContainer1.Dock = DockStyle.Fill;
splitContainer1.SplitterDistance = 250;
このように設定するだけで、フォーム全体を2分割し、サイズ変更にも対応しやすいレイアウトを作成できます。
1-4. PanelやTableLayoutPanelとの違い
Panel、TableLayoutPanel、SplitContainerは、どれもレイアウトを作るために使われますが、役割が異なります。
Panelは、複数のコントロールをまとめるための単純なコンテナです。画面分割や境界線のドラッグ操作は標準では持っていません。
TableLayoutPanelは、行と列で画面を区切るレイアウト用のコンテナです。複雑なグリッド配置には向いていますが、ユーザーが境界線をドラッグしてサイズ変更するような操作には向いていません。
一方、SplitContainerは、2つの領域を分割し、境界線によるサイズ変更を実現するためのコントロールです。
C#// Panelは単純な領域
Panel panel = new Panel();
// TableLayoutPanelは表形式のレイアウト
TableLayoutPanel table = new TableLayoutPanel();
// SplitContainerは分割可能な領域
SplitContainer splitContainer = new SplitContainer();
ユーザーが画面上で左右や上下のサイズを調整できるUIを作りたい場合は、SplitContainerを使うのが適しています。
2. SplitContainerの基本的な使い方
SplitContainerは、Visual Studioのデザイナーから簡単に配置できます。また、コードだけで作成することもできます。
まずは、デザイナーを使った基本的な使い方から確認していきます。
2-1. Visual Studioのデザイナーで配置する方法
Visual StudioでSplitContainerを配置する手順は次のとおりです。
C#1. Windows Formsアプリのフォームを開く
2. ツールボックスを表示する
3. 「コンテナー」カテゴリから「SplitContainer」を選択する
4. フォーム上にドラッグ&ドロップする
5. DockプロパティをFillに設定する
フォームに配置すると、splitContainer1という名前でコントロールが作成されます。必要に応じて、名前を分かりやすく変更しておくとよいでしょう。
たとえば、左メニューと右メイン画面に使う場合は、次のような名前にしておくとコードが読みやすくなります。
C#splitMain
デザイナー上では、境界線をドラッグして初期の分割位置を調整することもできます。
2-2. Panel1とPanel2にコントロールを配置する方法
SplitContainerにコントロールを配置する場合は、SplitContainer本体ではなく、Panel1またはPanel2に追加します。
デザイナーでは、左側または上側の領域にコントロールをドラッグするとPanel1に配置されます。右側または下側の領域にドラッグするとPanel2に配置されます。
コードで追加する場合は、次のように書きます。
C#Button button = new Button();
button.Text = "メニュー";
button.Dock = DockStyle.Top;
TextBox textBox = new TextBox();
textBox.Multiline = true;
textBox.Dock = DockStyle.Fill;
splitContainer1.Panel1.Controls.Add(button);
splitContainer1.Panel2.Controls.Add(textBox);
重要なのは、次のようにsplitContainer1.Controls.Add()へ直接追加しないことです。
C#// 推奨しない
splitContainer1.Controls.Add(button);
基本的には、Panel1.ControlsまたはPanel2.Controlsに追加します。
2-3. Dockプロパティで画面全体に表示する方法
SplitContainerをフォーム全体に表示したい場合は、DockプロパティをDockStyle.Fillに設定します。
C#splitContainer1.Dock = DockStyle.Fill;
これにより、フォームのサイズが変更されても、SplitContainerがフォーム全体に広がります。
フォーム全体を左右に分割する場合は、次のような設定がよく使われます。
C#splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.SplitterDistance = 200;
DockStyle.Fillを設定していない場合、フォームサイズを変更してもSplitContainerが追従せず、余白ができたり、画面が崩れたりすることがあります。
2-4. Orientationで縦分割・横分割を切り替える方法
SplitContainerの分割方向は、Orientationプロパティで設定します。
左右に分割する場合は、Orientation.Verticalを指定します。
C#splitContainer1.Orientation = Orientation.Vertical;
上下に分割する場合は、Orientation.Horizontalを指定します。
C#splitContainer1.Orientation = Orientation.Horizontal;
少し分かりにくい点として、Verticalは「境界線が縦方向」という意味です。そのため、画面は左右に分割されます。
一方、Horizontalは「境界線が横方向」という意味です。そのため、画面は上下に分割されます。
C#// 左右分割
splitContainer1.Orientation = Orientation.Vertical;
// 上下分割
splitContainer1.Orientation = Orientation.Horizontal;
3. SplitContainerをコードで作成する方法
SplitContainerは、Visual Studioのデザイナーを使わずに、C#コードだけで作成することもできます。
動的に画面を生成したい場合や、共通部品としてレイアウトを作成したい場合は、コードで作成する方法を知っておくと便利です。
3-1. SplitContainerをフォームに追加する基本サンプル
次のサンプルでは、フォームにSplitContainerを追加し、左右分割の画面を作成します。
C#using System;
using System.Windows.Forms;
namespace SplitContainerSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CreateSplitContainer();
}
private void CreateSplitContainer()
{
SplitContainer splitContainer = new SplitContainer();
splitContainer.Dock = DockStyle.Fill;
splitContainer.Orientation = Orientation.Vertical;
splitContainer.SplitterDistance = 200;
this.Controls.Add(splitContainer);
}
}
}
このコードを実行すると、フォーム全体が左右に分割されます。左側がPanel1、右側がPanel2です。
3-2. Panel1とPanel2にButtonやTextBoxを追加するサンプル
次に、Panel1にボタン、Panel2にテキストボックスを追加するサンプルを見てみましょう。
C#using System;
using System.Windows.Forms;
namespace SplitContainerSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CreateLayout();
}
private void CreateLayout()
{
SplitContainer splitContainer = new SplitContainer();
splitContainer.Dock = DockStyle.Fill;
splitContainer.Orientation = Orientation.Vertical;
splitContainer.SplitterDistance = 180;
Button buttonMenu = new Button();
buttonMenu.Text = "メニュー";
buttonMenu.Dock = DockStyle.Top;
buttonMenu.Height = 40;
TextBox textBoxMain = new TextBox();
textBoxMain.Multiline = true;
textBoxMain.Dock = DockStyle.Fill;
textBoxMain.Text = "メイン画面";
splitContainer.Panel1.Controls.Add(buttonMenu);
splitContainer.Panel2.Controls.Add(textBoxMain);
this.Controls.Add(splitContainer);
}
}
}
このサンプルでは、左側のPanel1にメニュー用のボタン、右側のPanel2にメイン画面用のテキストボックスを配置しています。
Dockを適切に設定することで、フォームサイズを変更しても自然にレイアウトが調整されます。
3-3. 初期表示時の分割位置を設定する方法
初期表示時の分割位置は、SplitterDistanceプロパティで指定します。
C#splitContainer1.SplitterDistance = 250;
左右分割の場合、SplitterDistanceは左端から境界線までの距離を表します。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.SplitterDistance = 250;
上下分割の場合、SplitterDistanceは上端から境界線までの距離を表します。
C#splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.SplitterDistance = 120;
ただし、SplitterDistanceを設定するタイミングには注意が必要です。フォームやSplitContainerのサイズが確定していない段階で不適切な値を設定すると、例外が発生する場合があります。
安全に設定するなら、フォームのLoadイベントで設定する方法があります。
C#private void Form1_Load(object sender, EventArgs e)
{
splitContainer1.SplitterDistance = 250;
}
3-4. デザイナーを使わずに画面分割する場合の注意点
コードだけでSplitContainerを作成する場合は、次の点に注意しましょう。
C#・Dockを設定する
・Panel1とPanel2にコントロールを追加する
・SplitterDistanceはサイズが確定してから設定する
・Panel1MinSizeとPanel2MinSizeを必要に応じて設定する
・コントロールの追加順序に注意する
特に、DockStyle.Fillを使う場合は、追加順序によって表示結果が変わることがあります。
たとえば、フォーム上部にメニューバーを配置し、その下にSplitContainerを表示する場合は、メニューバーを先に追加し、SplitContainerを後で追加するか、Dockの設定を考慮する必要があります。
C#MenuStrip menuStrip = new MenuStrip();
menuStrip.Dock = DockStyle.Top;
SplitContainer splitContainer = new SplitContainer();
splitContainer.Dock = DockStyle.Fill;
this.Controls.Add(splitContainer);
this.Controls.Add(menuStrip);
表示が崩れる場合は、Controls.SetChildIndexで前後関係を調整する方法もあります。
4. SplitContainerのサイズ調整方法
SplitContainerでは、分割位置、境界線の幅、パネルの最小サイズなどを設定できます。
画面サイズの変更やユーザー操作に強いレイアウトを作るには、これらのプロパティを適切に使うことが重要です。
4-1. SplitterDistanceで分割位置を指定する方法
SplitterDistanceは、Panel1のサイズを指定するプロパティです。
左右分割の場合は、Panel1の幅を指定します。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.SplitterDistance = 200;
この場合、左側のPanel1の幅が200ピクセルになります。
上下分割の場合は、Panel1の高さを指定します。
C#splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.SplitterDistance = 100;
この場合、上側のPanel1の高さが100ピクセルになります。
SplitterDistanceを使うときは、Panel1MinSizeやPanel2MinSizeとの関係に注意が必要です。最小サイズを下回る値や、全体サイズに対して大きすぎる値を設定すると、例外が発生することがあります。
4-2. SplitterWidthで境界線の幅を変更する方法
SplitterWidthを使うと、Panel1とPanel2の間にある境界線の幅を変更できます。
C#splitContainer1.SplitterWidth = 8;
境界線を太くすると、ユーザーがドラッグしやすくなります。タッチ操作を考慮する場合や、境界線が見つけにくい場合に便利です。
C#splitContainer1.SplitterWidth = 10;
splitContainer1.Cursor = Cursors.VSplit;
ただし、境界線を太くしすぎると画面の見た目に影響するため、アプリ全体のデザインに合わせて調整しましょう。
4-3. Panel1MinSize・Panel2MinSizeで最小サイズを設定する方法
Panel1MinSizeとPanel2MinSizeを使うと、それぞれのパネルの最小サイズを設定できます。
C#splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 300;
左右分割の場合、これらはパネルの最小幅を表します。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 300;
上下分割の場合は、パネルの最小高さを表します。
C#splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.Panel1MinSize = 80;
splitContainer1.Panel2MinSize = 200;
最小サイズを設定しておくと、ユーザーが境界線をドラッグしたときに、パネル内のボタンやテキストボックスが極端に小さくなることを防げます。
4-4. フォームサイズ変更時にレイアウトを崩さない設定
フォームサイズ変更時にレイアウトを崩さないためには、Dockを適切に設定することが重要です。
基本的には、SplitContainer本体をフォーム全体に広げます。
C#splitContainer1.Dock = DockStyle.Fill;
さらに、Panel1やPanel2に配置するコントロールにもDockを設定します。
C#listBoxMenu.Dock = DockStyle.Fill;
dataGridViewMain.Dock = DockStyle.Fill;
これにより、フォームサイズが変わっても、内部のコントロールがパネルに合わせて自動的に伸縮します。
よく使う設定例は次のとおりです。
C#splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 300;
listBoxMenu.Dock = DockStyle.Fill;
dataGridViewMain.Dock = DockStyle.Fill;
Anchorで細かく制御する方法もありますが、SplitContainer内ではDockStyle.Fillを使ったほうがシンプルにまとまりやすいです。
4-5. 実行時にユーザーがサイズ変更できる仕組み
SplitContainerでは、標準でユーザーが境界線をドラッグしてサイズを変更できます。
特別なコードを書かなくても、IsSplitterFixedがfalseであれば、実行時に分割位置を変更できます。
C#splitContainer1.IsSplitterFixed = false;
ユーザーがドラッグすると、Panel1とPanel2のサイズが自動的に調整されます。
サイズ変更後に何か処理を行いたい場合は、SplitterMovedイベントを使います。
C#private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
{
int distance = splitContainer1.SplitterDistance;
Console.WriteLine($"現在の分割位置: {distance}");
}
このように、分割位置の変更を検知して、設定保存や表示調整を行うこともできます。
5. SplitContainerの分割位置を固定する方法
画面によっては、ユーザーに分割位置を変更させたくない場合があります。
たとえば、左メニューの幅を常に固定したい場合や、検索条件エリアの高さを固定したい場合です。
そのような場合は、IsSplitterFixedやFixedPanelを使います。
5-1. IsSplitterFixedで分割位置を固定する方法
IsSplitterFixedをtrueに設定すると、ユーザーが境界線をドラッグできなくなります。
C#splitContainer1.IsSplitterFixed = true;
これにより、分割位置が固定されます。
たとえば、左メニューを200ピクセルで固定したい場合は、次のように設定します。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.SplitterDistance = 200;
splitContainer1.IsSplitterFixed = true;
この設定により、ユーザーは境界線をドラッグできなくなり、左側のメニュー幅が固定されます。
5-2. ユーザーによるドラッグ操作を禁止する方法
ユーザーによるドラッグ操作を禁止する最も簡単な方法は、IsSplitterFixedをtrueにすることです。
C#splitContainer1.IsSplitterFixed = true;
さらに、見た目としてドラッグできないことを分かりやすくしたい場合は、カーソルを通常の矢印に変更する方法もあります。
C#splitContainer1.Cursor = Cursors.Default;
ただし、Cursorを変更しても、ドラッグ操作そのものを禁止できるわけではありません。操作を禁止するには、必ずIsSplitterFixedを使用します。
C#splitContainer1.IsSplitterFixed = true;
splitContainer1.Cursor = Cursors.Default;
5-3. 片側パネルのサイズを固定する実装例
フォームサイズが変わったときに、片側のパネルだけ固定したい場合は、FixedPanelを使います。
たとえば、左側のPanel1を固定したい場合は、次のように設定します。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.SplitterDistance = 200;
この設定では、フォームの幅が変わってもPanel1の幅はできるだけ維持され、Panel2側が伸縮します。
右側のPanel2を固定したい場合は、次のようにします。
C#splitContainer1.FixedPanel = FixedPanel.Panel2;
上下分割で上側を固定したい場合も、考え方は同じです。
C#splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.SplitterDistance = 120;
この場合、上側の検索条件エリアを固定し、下側の一覧エリアを伸縮させるレイアウトになります。
5-4. 固定レイアウトでよくある失敗と対処法
分割位置を固定するレイアウトでは、次のような失敗がよくあります。
C#・IsSplitterFixedだけ設定してFixedPanelを設定していない
・SplitterDistanceをフォームサイズより大きく設定している
・Panel1MinSizeとPanel2MinSizeの合計が大きすぎる
・フォームサイズ変更時に意図しないパネルが伸縮する
たとえば、左メニューを固定したい場合、IsSplitterFixedだけでは「ユーザーがドラッグできない」状態になるだけです。フォームサイズ変更時にどちらのパネルを優先して固定するかは、FixedPanelで指定します。
C#splitContainer1.IsSplitterFixed = true;
splitContainer1.FixedPanel = FixedPanel.Panel1;
また、最小サイズの合計がフォームサイズより大きいと、分割位置を正常に調整できなくなる場合があります。
C#splitContainer1.Panel1MinSize = 200;
splitContainer1.Panel2MinSize = 500;
フォーム幅が十分にない場合、このような設定はレイアウト崩れの原因になります。最小サイズは、実際に想定する画面サイズに合わせて設定しましょう。
6. SplitContainerの便利なプロパティ
SplitContainerには、サイズ調整以外にも便利なプロパティが用意されています。
ここでは、実務でよく使うプロパティを中心に解説します。
6-1. FixedPanelでサイズ固定するパネルを指定する方法
FixedPanelは、フォームサイズが変更されたときに、どちらのパネルのサイズを固定するかを指定するプロパティです。
C#splitContainer1.FixedPanel = FixedPanel.Panel1;
指定できる値は次のとおりです。
C#FixedPanel.None // 固定しない
FixedPanel.Panel1 // Panel1を固定
FixedPanel.Panel2 // Panel2を固定
左メニューを固定し、右側のメイン画面を伸縮させたい場合は、次のようにします。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.SplitterDistance = 220;
上部の検索条件を固定し、下部の一覧を伸縮させたい場合は、次のようにします。
C#splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.SplitterDistance = 100;
FixedPanelは、固定レイアウトを作るときに非常に重要なプロパティです。
6-2. Panel1Collapsed・Panel2Collapsedでパネルを非表示にする方法
Panel1CollapsedまたはPanel2Collapsedをtrueにすると、指定したパネルを非表示にできます。
C#splitContainer1.Panel1Collapsed = true;
この場合、Panel1が折りたたまれ、Panel2が残りの領域を使用します。
再表示する場合は、falseに戻します。
C#splitContainer1.Panel1Collapsed = false;
左メニューの表示・非表示を切り替えるサンプルは次のとおりです。
C#private void buttonToggleMenu_Click(object sender, EventArgs e)
{
splitContainer1.Panel1Collapsed = !splitContainer1.Panel1Collapsed;
}
右側のパネルを非表示にしたい場合は、Panel2Collapsedを使います。
C#splitContainer1.Panel2Collapsed = true;
ナビゲーションメニューを一時的に隠したい場合や、詳細エリアを必要なときだけ表示したい場合に便利です。
6-3. BorderStyleで見た目を変更する方法
BorderStyleを使うと、SplitContainerの境界や外枠の見た目を変更できます。
C#splitContainer1.BorderStyle = BorderStyle.FixedSingle;
指定できる主な値は次のとおりです。
C#BorderStyle.None // 枠線なし
BorderStyle.FixedSingle // 一重線の枠
BorderStyle.Fixed3D // 立体的な枠
たとえば、分割された領域をはっきり見せたい場合は、FixedSingleを設定すると分かりやすくなります。
C#splitContainer1.BorderStyle = BorderStyle.FixedSingle;
見た目をシンプルにしたい場合は、Noneでも問題ありません。
C#splitContainer1.BorderStyle = BorderStyle.None;
6-4. BackColorやCursorで操作性を改善する方法
BackColorを使うと、SplitContainerやパネルの背景色を変更できます。
C#splitContainer1.Panel1.BackColor = System.Drawing.Color.LightGray;
splitContainer1.Panel2.BackColor = System.Drawing.Color.White;
左側メニューの背景色を変えると、画面構成が分かりやすくなります。
また、Cursorを設定すると、マウスカーソルの表示を変更できます。
C#splitContainer1.Cursor = Cursors.VSplit;
左右分割の場合はCursors.VSplit、上下分割の場合はCursors.HSplitを使うと、サイズ変更できることが分かりやすくなります。
C#// 左右分割
splitContainer1.Cursor = Cursors.VSplit;
// 上下分割
splitContainer1.Cursor = Cursors.HSplit;
ただし、カーソル変更はあくまで見た目の補助です。ドラッグを禁止する場合はIsSplitterFixedを使います。
6-5. TabIndexやフォーカス移動の設定
SplitContainer内に複数の入力コントロールを配置する場合は、TabIndexにも注意しましょう。
TabIndexを設定すると、Tabキーでフォーカス移動する順番を制御できます。
C#textBoxName.TabIndex = 0;
textBoxAddress.TabIndex = 1;
buttonSearch.TabIndex = 2;
Panel1とPanel2をまたいで入力項目がある場合、思わぬ順番でフォーカスが移動することがあります。
たとえば、検索条件を上側、検索結果を下側に配置している場合は、検索条件内の入力項目から検索ボタンへ自然に移動するように設定します。
C#textBoxKeyword.TabIndex = 0;
comboBoxCategory.TabIndex = 1;
buttonSearch.TabIndex = 2;
dataGridViewResult.TabIndex = 3;
業務アプリではキーボード操作のしやすさも重要なので、TabIndexは忘れずに確認しておきましょう。
7. SplitContainerのイベント活用
SplitContainerには、分割位置の変更に関するイベントが用意されています。
代表的なイベントは、SplitterMovedとSplitterMovingです。
これらを使うことで、ユーザーが境界線を動かしたときに処理を実行できます。
7-1. SplitterMovedで分割位置変更後の処理を行う方法
SplitterMovedイベントは、ユーザーが境界線を移動し終わった後に発生します。
C#private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
{
int distance = splitContainer1.SplitterDistance;
labelStatus.Text = $"分割位置: {distance}";
}
このイベントは、分割位置の保存や、画面表示の更新に向いています。
たとえば、ユーザーが変更した分割位置を設定ファイルに保存したい場合、SplitterMovedで保存処理を行うことができます。
C#private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
{
Properties.Settings.Default.SplitterDistance = splitContainer1.SplitterDistance;
Properties.Settings.Default.Save();
}
7-2. SplitterMovingで移動中の処理を行う方法
SplitterMovingイベントは、ユーザーが境界線を移動している途中で発生します。
C#private void splitContainer1_SplitterMoving(object sender, SplitterCancelEventArgs e)
{
labelStatus.Text = $"移動中: {e.SplitX}, {e.SplitY}";
}
移動中にリアルタイムで座標を表示したい場合や、特定の条件で移動をキャンセルしたい場合に使えます。
たとえば、分割位置が一定範囲を超えないようにしたい場合は、次のように制御できます。
C#private void splitContainer1_SplitterMoving(object sender, SplitterCancelEventArgs e)
{
if (e.SplitX < 150)
{
e.Cancel = true;
}
}
ただし、通常はPanel1MinSizeやPanel2MinSizeで制御するほうが簡単です。特別な条件がある場合にSplitterMovingを使うとよいでしょう。
7-3. サイズ変更時にレイアウトを再調整するサンプル
フォームのサイズ変更に合わせて分割位置を再調整したい場合は、フォームのResizeイベントを使います。
たとえば、常に左側をフォーム幅の30%にしたい場合は、次のようにします。
C#private void Form1_Resize(object sender, EventArgs e)
{
if (splitContainer1.Width > 0)
{
splitContainer1.SplitterDistance = splitContainer1.Width * 30 / 100;
}
}
ただし、この方法を使うと、ユーザーが手動で変更した分割位置もフォームサイズ変更時に上書きされます。
ユーザー操作を尊重したい場合は、FixedPanelを使うか、初回表示時だけSplitterDistanceを設定するようにしましょう。
C#private bool initialized = false;
private void Form1_Shown(object sender, EventArgs e)
{
if (!initialized)
{
splitContainer1.SplitterDistance = splitContainer1.Width * 30 / 100;
initialized = true;
}
}
7-4. 分割位置を保存・復元する実装例
ユーザーが調整した分割位置を次回起動時に復元したい場合は、アプリケーション設定を使う方法があります。
まず、SplitterMovedイベントで分割位置を保存します。
C#private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
{
Properties.Settings.Default.SplitterDistance = splitContainer1.SplitterDistance;
Properties.Settings.Default.Save();
}
次に、フォームのLoadイベントで保存された値を復元します。
C#private void Form1_Load(object sender, EventArgs e)
{
int distance = Properties.Settings.Default.SplitterDistance;
if (distance > 0 && distance < splitContainer1.Width)
{
splitContainer1.SplitterDistance = distance;
}
}
より安全にするには、Panel1MinSizeやPanel2MinSizeを考慮して範囲チェックを行います。
C#private void Form1_Load(object sender, EventArgs e)
{
int distance = Properties.Settings.Default.SplitterDistance;
int min = splitContainer1.Panel1MinSize;
int max = splitContainer1.Width - splitContainer1.Panel2MinSize - splitContainer1.SplitterWidth;
if (distance >= min && distance <= max)
{
splitContainer1.SplitterDistance = distance;
}
}
このようにしておくと、フォーム起動時に不正な値を設定して例外が発生するリスクを減らせます。
8. よくあるレイアウトパターン別サンプル
ここでは、C# SplitContainerを使った実用的なレイアウトパターンを紹介します。
業務アプリや管理画面でよく使う構成を中心に見ていきましょう。
8-1. 左メニュー・右メイン画面を作るサンプル
左側にメニュー、右側にメイン画面を配置するレイアウトです。
C#private void CreateMenuLayout()
{
SplitContainer splitContainer = new SplitContainer();
splitContainer.Dock = DockStyle.Fill;
splitContainer.Orientation = Orientation.Vertical;
splitContainer.FixedPanel = FixedPanel.Panel1;
splitContainer.SplitterDistance = 200;
splitContainer.Panel1MinSize = 150;
splitContainer.Panel2MinSize = 400;
ListBox listBoxMenu = new ListBox();
listBoxMenu.Dock = DockStyle.Fill;
listBoxMenu.Items.Add("顧客管理");
listBoxMenu.Items.Add("商品管理");
listBoxMenu.Items.Add("売上管理");
Label labelMain = new Label();
labelMain.Text = "メイン画面";
labelMain.Dock = DockStyle.Fill;
labelMain.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
splitContainer.Panel1.Controls.Add(listBoxMenu);
splitContainer.Panel2.Controls.Add(labelMain);
this.Controls.Add(splitContainer);
}
この構成では、左側のメニュー幅を固定し、右側のメイン画面をフォームサイズに合わせて伸縮させています。
8-2. 上部検索条件・下部一覧画面を作るサンプル
上部に検索条件、下部に一覧を配置するレイアウトです。
C#private void CreateSearchLayout()
{
SplitContainer splitContainer = new SplitContainer();
splitContainer.Dock = DockStyle.Fill;
splitContainer.Orientation = Orientation.Horizontal;
splitContainer.FixedPanel = FixedPanel.Panel1;
splitContainer.SplitterDistance = 100;
splitContainer.Panel1MinSize = 80;
splitContainer.Panel2MinSize = 200;
Panel searchPanel = new Panel();
searchPanel.Dock = DockStyle.Fill;
TextBox textBoxKeyword = new TextBox();
textBoxKeyword.Left = 20;
textBoxKeyword.Top = 20;
textBoxKeyword.Width = 200;
Button buttonSearch = new Button();
buttonSearch.Text = "検索";
buttonSearch.Left = 240;
buttonSearch.Top = 18;
searchPanel.Controls.Add(textBoxKeyword);
searchPanel.Controls.Add(buttonSearch);
DataGridView grid = new DataGridView();
grid.Dock = DockStyle.Fill;
grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
splitContainer.Panel1.Controls.Add(searchPanel);
splitContainer.Panel2.Controls.Add(grid);
this.Controls.Add(splitContainer);
}
検索条件エリアの高さを固定し、一覧画面を広く使えるようにしています。
8-3. TreeViewとDataGridViewを組み合わせるサンプル
左側にTreeView、右側にDataGridViewを配置する構成は、マスタ管理画面などでよく使われます。
C#private void CreateTreeAndGridLayout()
{
SplitContainer splitContainer = new SplitContainer();
splitContainer.Dock = DockStyle.Fill;
splitContainer.Orientation = Orientation.Vertical;
splitContainer.SplitterDistance = 250;
splitContainer.Panel1MinSize = 180;
splitContainer.Panel2MinSize = 400;
TreeView treeView = new TreeView();
treeView.Dock = DockStyle.Fill;
treeView.Nodes.Add("すべて");
treeView.Nodes.Add("カテゴリA");
treeView.Nodes.Add("カテゴリB");
DataGridView dataGridView = new DataGridView();
dataGridView.Dock = DockStyle.Fill;
dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dataGridView.Columns.Add("Code", "コード");
dataGridView.Columns.Add("Name", "名称");
splitContainer.Panel1.Controls.Add(treeView);
splitContainer.Panel2.Controls.Add(dataGridView);
this.Controls.Add(splitContainer);
}
TreeViewでカテゴリを選択し、右側のDataGridViewに一覧を表示するような画面に向いています。
8-4. SplitContainerを入れ子にして3分割画面を作るサンプル
SplitContainerは2分割用のコントロールですが、入れ子にすることで3分割以上の画面も作成できます。
次のサンプルでは、左メニュー、右上詳細、右下一覧の3分割画面を作成します。
C#private void CreateNestedSplitLayout()
{
SplitContainer splitMain = new SplitContainer();
splitMain.Dock = DockStyle.Fill;
splitMain.Orientation = Orientation.Vertical;
splitMain.SplitterDistance = 200;
splitMain.FixedPanel = FixedPanel.Panel1;
SplitContainer splitRight = new SplitContainer();
splitRight.Dock = DockStyle.Fill;
splitRight.Orientation = Orientation.Horizontal;
splitRight.SplitterDistance = 150;
splitRight.FixedPanel = FixedPanel.Panel1;
ListBox menu = new ListBox();
menu.Dock = DockStyle.Fill;
menu.Items.Add("メニュー1");
menu.Items.Add("メニュー2");
menu.Items.Add("メニュー3");
TextBox detail = new TextBox();
detail.Multiline = true;
detail.Dock = DockStyle.Fill;
detail.Text = "詳細エリア";
DataGridView grid = new DataGridView();
grid.Dock = DockStyle.Fill;
splitMain.Panel1.Controls.Add(menu);
splitMain.Panel2.Controls.Add(splitRight);
splitRight.Panel1.Controls.Add(detail);
splitRight.Panel2.Controls.Add(grid);
this.Controls.Add(splitMain);
}
入れ子にする場合は、それぞれのSplitContainerに分かりやすい名前を付けることが重要です。
C#splitMain
splitRight
splitLeft
名前を整理しておくと、後からサイズ調整やイベント処理を追加するときに分かりやすくなります。
9. SplitContainerでよくあるエラー・困りごと
SplitContainerは便利なコントロールですが、設定値やタイミングによってエラーが発生したり、意図しない表示になったりすることがあります。
ここでは、よくある困りごとと対処法を紹介します。
9-1. SplitterDistanceを設定すると例外が出る原因
SplitterDistanceを設定したときに例外が発生する主な原因は、指定した値が有効範囲外になっていることです。
たとえば、フォーム幅がまだ確定していない段階で、大きすぎる値を設定すると問題になることがあります。
C#splitContainer1.SplitterDistance = 1000;
SplitterDistanceは、Panel1MinSizeやPanel2MinSize、SplitterWidthとの関係で有効範囲が決まります。
安全に設定するには、フォーム表示後に範囲チェックを行います。
C#private void Form1_Shown(object sender, EventArgs e)
{
int distance = 250;
int max = splitContainer1.Width - splitContainer1.Panel2MinSize - splitContainer1.SplitterWidth;
if (distance >= splitContainer1.Panel1MinSize && distance <= max)
{
splitContainer1.SplitterDistance = distance;
}
}
上下分割の場合は、WidthではなくHeightを基準にします。
C#int max = splitContainer1.Height - splitContainer1.Panel2MinSize - splitContainer1.SplitterWidth;
9-2. 最小サイズの設定で分割位置が変えられない場合
Panel1MinSizeやPanel2MinSizeを大きく設定しすぎると、分割位置をほとんど動かせなくなることがあります。
C#splitContainer1.Panel1MinSize = 300;
splitContainer1.Panel2MinSize = 500;
フォーム全体の幅が800ピクセル程度しかない場合、境界線の移動可能範囲がほとんどなくなります。
対処法としては、最小サイズを見直します。
C#splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 250;
また、フォーム自体の最小サイズを設定しておくのも有効です。
C#this.MinimumSize = new System.Drawing.Size(800, 500);
パネル内のコントロールが必要とするサイズと、フォームの最小サイズをセットで考えることが大切です。
9-3. DockやAnchorの設定で表示が崩れる場合
SplitContainerで表示が崩れる場合、DockやAnchorの設定が原因になっていることがよくあります。
特に、パネル内に配置したコントロールにDockを設定していない場合、フォームサイズを変更してもコントロールが追従しません。
C#dataGridView1.Dock = DockStyle.Fill;
また、複数のコントロールに同時にDockStyle.Fillを設定すると、重なって表示されることがあります。
C#// 同じパネルにFillを複数配置すると重なる場合がある
panel.Controls.Add(textBox1);
panel.Controls.Add(dataGridView1);
このような場合は、PanelやTableLayoutPanelを組み合わせて、領域を整理するとよいでしょう。
C#TableLayoutPanel layout = new TableLayoutPanel();
layout.Dock = DockStyle.Fill;
layout.RowCount = 2;
layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 40));
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
layout.Controls.Add(textBox1, 0, 0);
layout.Controls.Add(dataGridView1, 0, 1);
splitContainer1.Panel2.Controls.Add(layout);
9-4. パネル内のコントロールが隠れる場合
パネル内のコントロールが隠れる場合は、主に次の原因が考えられます。
C#・Panel1MinSizeまたはPanel2MinSizeが小さすぎる
・コントロールのDock設定が不適切
・コントロールの追加順序が意図と違う
・AutoScrollが無効になっている
入力項目が多い場合は、パネルにスクロールを設定する方法があります。
C#splitContainer1.Panel1.AutoScroll = true;
また、コントロールを固定サイズで配置している場合、パネルサイズが小さくなると見切れることがあります。
その場合は、MinimumSizeを設定したり、TableLayoutPanelでレイアウトを整理したりすると改善できます。
C#buttonSearch.MinimumSize = new System.Drawing.Size(80, 30);
splitContainer1.Panel1MinSize = 200;
9-5. フォーム起動時に意図したサイズにならない場合
フォーム起動時にSplitterDistanceが意図した値にならない場合は、設定するタイミングを確認しましょう。
コンストラクタ内で設定すると、まだフォームやコントロールのサイズが確定していないことがあります。
C#public Form1()
{
InitializeComponent();
// サイズ確定前のため、期待通りにならない場合がある
splitContainer1.SplitterDistance = 300;
}
このような場合は、LoadイベントやShownイベントで設定します。
C#private void Form1_Shown(object sender, EventArgs e)
{
splitContainer1.SplitterDistance = 300;
}
特に、フォーム最大化やDPI設定の影響を受ける場合は、Shownイベントで設定したほうが安定することがあります。
C#private void Form1_Shown(object sender, EventArgs e)
{
int distance = Math.Min(300, splitContainer1.Width - splitContainer1.Panel2MinSize - splitContainer1.SplitterWidth);
if (distance >= splitContainer1.Panel1MinSize)
{
splitContainer1.SplitterDistance = distance;
}
}
10. SplitContainerを使うときの実装ポイント
SplitContainerを使うときは、単に画面を分割するだけでなく、サイズ変更やユーザー操作を考慮して設計することが重要です。
ここでは、実装時に意識したいポイントを整理します。
10-1. 画面サイズ変更を考慮して設計する
Windows Formsアプリでは、ユーザーがフォームサイズを変更することがあります。そのため、固定サイズ前提で設計すると、表示崩れが起きやすくなります。
基本的には、次のような設定を意識しましょう。
C#splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 300;
パネル内の主要なコントロールにもDockStyle.Fillを設定します。
C#treeView1.Dock = DockStyle.Fill;
dataGridView1.Dock = DockStyle.Fill;
さらに、フォーム自体にも最小サイズを設定しておくと、極端に小さくされたときのレイアウト崩れを防げます。
C#this.MinimumSize = new System.Drawing.Size(800, 500);
10-2. 固定したい領域と可変にしたい領域を明確にする
SplitContainerを使うときは、どちらの領域を固定し、どちらの領域を伸縮させるのかを最初に決めておくことが大切です。
たとえば、左メニューは固定、右側の作業領域は可変にする場合は、次のように設定します。
C#splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.SplitterDistance = 220;
上部の検索条件は固定、下部の一覧は可変にする場合は、次のようにします。
C#splitContainer1.Orientation = Orientation.Horizontal;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.SplitterDistance = 100;
固定したい領域が明確になると、FixedPanelやSplitterDistanceの設定方針も決めやすくなります。
10-3. MinSizeを設定して操作しやすいUIにする
ユーザーが境界線を自由に動かせるようにする場合でも、パネルが小さくなりすぎると操作しにくくなります。
そのため、Panel1MinSizeとPanel2MinSizeを設定しておきましょう。
C#splitContainer1.Panel1MinSize = 180;
splitContainer1.Panel2MinSize = 300;
たとえば、左側にメニューがある場合、メニュー項目が読める幅を最小サイズにします。
C#splitContainer1.Panel1MinSize = 160;
右側に一覧表がある場合、主要な列が表示できる幅を確保します。
C#splitContainer1.Panel2MinSize = 400;
最小サイズを適切に設定することで、ユーザーが操作しやすいUIになります。
10-4. デザイナー設定とコード設定を混在させるときの注意点
Visual Studioのデザイナーで設定した内容と、コードで設定した内容が混在すると、意図しない動きになることがあります。
たとえば、デザイナーでSplitterDistanceを設定しているのに、フォームのLoadイベントで別の値を設定している場合、実行時にはコード側の値が優先されます。
C#private void Form1_Load(object sender, EventArgs e)
{
splitContainer1.SplitterDistance = 250;
}
設定箇所が複数あると、後から修正するときに原因を追いにくくなります。
対策として、レイアウトに関する設定はなるべく一箇所にまとめるのがおすすめです。
C#private void InitializeSplitContainerLayout()
{
splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.FixedPanel = FixedPanel.Panel1;
splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 300;
splitContainer1.SplitterDistance = 220;
}
このようにメソッド化しておくと、設定内容を確認しやすくなります。
まとめ
C#のSplitContainerは、Windows Formsで画面を左右または上下に分割するための便利なコントロールです。
Panel1とPanel2にコントロールを配置し、Splitterによって分割位置を調整できます。DockStyle.Fillを設定すればフォーム全体に表示でき、Orientationを変更すれば左右分割と上下分割を切り替えられます。
基本的な使い方は次のとおりです。
C#splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Orientation = Orientation.Vertical;
splitContainer1.SplitterDistance = 200;
サイズ調整では、SplitterDistance、SplitterWidth、Panel1MinSize、Panel2MinSizeをよく使います。
C#splitContainer1.SplitterDistance = 200;
splitContainer1.SplitterWidth = 6;
splitContainer1.Panel1MinSize = 150;
splitContainer1.Panel2MinSize = 300;
分割位置を固定したい場合は、IsSplitterFixedやFixedPanelを使います。
C#splitContainer1.IsSplitterFixed = true;
splitContainer1.FixedPanel = FixedPanel.Panel1;
また、Panel1CollapsedやPanel2Collapsedを使えば、片側のパネルを非表示にすることもできます。
C#splitContainer1.Panel1Collapsed = true;
SplitContainerを使うときは、固定したい領域と可変にしたい領域を明確にし、フォームサイズ変更時の動きも考慮して設計することが大切です。
左メニュー・右メイン画面、上部検索条件・下部一覧画面、TreeViewとDataGridViewの組み合わせ、入れ子による3分割画面など、さまざまなレイアウトに応用できます。
C#のWindows Formsで画面分割レイアウトを作る場合は、SplitContainerの基本プロパティとイベントを理解しておくことで、保守しやすく使いやすい画面を実装できます。

