ちょうどまとまっている資料が見つからなかったので、まとめてみました。
環境
C# - Winodws Form Application (Visual Studio 2017 , .NET Framework 4.5)
マルチモニタ環境での座標の扱い
表示領域と移動について
自作のフォームアプリをマルチモニタ対応するために色々弄ってみました。
こういうマルチモニタ環境があるとします。
小さいディスプレイをサブモニタとして使用している私の環境です。
この状態では、表示領域はこうなってます。
プライマリディスプレイの左上が(0,0)であり、セカンダリディスプレイはその左側にあるのでX座標はマイナスになります。
つまり、フォームのLeft
,Top
プロパティに雑に座標を指定すれば自動的にその位置に応じたディスプレイ上に表示させることができます。
結論として、フォームの移動や配置についてのケアは殆ど要らないと言えるでしょう。
逆に言うと、「座標がマイナスならディスプレイからはみ出ている」というロジックの方を改めなければなりません。
ディスプレイ領域の取得
Formはどこのディスプレイ上にあるの?
System.Windows.Forms.Screen.FromControl
メソッドにフォームを引数で渡せばScreen
オブジェクトを取ることができます。
あとはBounds
でディスプレイ領域の矩形が、WorkingArea
でタスクバーを除いた領域が取れます。
System.Drawing.Rectangle rect = System.Windows.Forms.Screen.FromControl(this).Bounds;
結果(矩形)だけが欲しいのなら、Screen.GetBounds
でも良いようです。
System.Drawing.Rectangle rect = System.Windows.Forms.Screen.GetBounds(this);
2つのモニタを跨った場合は、最大部分を保持するディスプレイの方が返されます。中央の座標を含む方ですね。
マウスがあるディスプレイは?
今の“アクティブ”なディスプレイは、マウスのある位置ではないかと思います。マウスのあるディスプレイにフォームを移動させたいこともあるでしょう。
Screen
にFromPoint
があります。
System.Drawing.Rectangle rect = System.Windows.Forms.Screen.FromPoint(Cursor.Position).Bounds;
また、GetBounds
の引数にpoint
型も渡せます。
System.Drawing.Rectangle rect = System.Windows.Forms.Screen.GetBounds(Cursor.Position);
ディスプレイの中に表示されているかどうかのチェック
基本的にはScreen.FromControl
で行けると思いますが、ディスプレイの方から探す方法も抑えておくと良いかも。
public static bool IsOnScreen(System.Windows.Forms.Form frm)
{
foreach (System.Windows.Forms.Screen s in System.Windows.Forms.Screen.AllScreens)
{
if (s.WorkingArea.Contains(new System.Drawing.Rectangle(frm.Location, frm.Size)))
{
return true;
}
}
return false;
}
これははみ出てない事に対するチェック。ちなみにこれ、モニタ2つを跨っている場合ははみ出てる判定になります。
ディスプレイの中にフォームを収めるには
あとはまぁ、適当にやればよろしいかと。
if (this.WindowState == System.Windows.Forms.FormWindowState.Normal)
{
var rect = System.Windows.Forms.Screen.GetBounds(this);
this.Left = (rect.Left + rect.Width > this.Left + this.Width) ? this.Left : rect.Left + rect.Width - this.Width;
this.Left = (rect.Left < this.Left) ? this.Left : rect.Left;
this.Top = (rect.Top + rect.Height > this.Top + this.Height) ? this.Top : rect.Top + rect.Height - this.Height;
this.Top = (rect.Top < this.Top) ? this.Top : rect.Top;
}
これを入れておけば、「モニタ外してからアプリを起動したら行方不明に!」という事態は避けられると思います。
独学のため正確でない可能性があります。
(っ・x・)っ きゅ