Formが主に所属するモニターを判断する方法を考える (解決)

Windows Formsアプリケーションを作っていると、Formsがどのモニターにいるか知りたいときがあります。
単純に左上隅の座標で判断する方法もありますが、感覚的に違う場合があるので他の判断方法を考えてみました。

もしかしたら一発で取得する方法もあるかもですが、とりあえず地道にやる方法で。

追記

一発でやる方法が分かりました!
こちらの記事を参照ください

最初に

この先「モニター」と「Screen」という言葉が似た感じで出てきます。
「モニター」は液晶モニターや液晶テレビなど、画面を映し出す機器そのものを指します。
「Screen」はモニターによって表示される領域を処理する.NET Frameworkのクラスです。
物理的なものと論理的なものですが、ざっくり説明なのであまり気にせず同じようなもんだと思っておいてください。

なぜ判断が必要なのか

1つのモニターの時は悩む必要ありません。
Formをどこに動かしても対象のScreenは1つです。

20150924_1

モニターが1つってのは Screen.AllScreens.Length が 1 の状態。分かりやすい。
唯一の Screen.PrimaryScreen だけ相手していればOK。

問題はマルチモニター環境。
例えば私のデスクトップPCはWUXGAの液晶モニター2台とFHDの液晶テレビが繋がっています。
ノートPCは本体のWSXGA+液晶モニターとFHDの液晶テレビが繋がっています。
こんな感じで環境によってサイズや数はバラバラ。
このモニター上をFormが自由に動けるわけで、プログラムからはどこにいるか判断するのが難しいという悩み。

座標で判断してみたらどうか

Formの原点(左上隅)がScreenに入っているかで判定する方法が考えられます。

for (int i = 0; i < Screen.AllScreens.Length; i++)
{
    if(Screen.AllScreens[i].Bounds.Contains(this.Location))
    {
        //入ってる
    }
}

これでも何となくうまくいきそうですが、こういう時に問題が。

20150924_2

Formの原点は左側のScreenにあるものの、感覚的には右側のScreenにいる感じですよね。
この状態で左側Screenと判断されても何かが違う。

面積で判断してみたらどうか

各ScreenとFormが重なり合ってる領域を比較するとなんとなくうまくいきそう。

20150924_3

左側Screenの領域と右側Screenの領域の面積を比較すると右側が大きい。この方法なら行けそう。

領域の重なり合いは Rectangle.Intersect で取れるので、ScreenとFormのBoundsを取れば行ける。
そんなわけで全Screenぶんまわして比較する処理はこんな感じ。
処理完了時に OrenoScreen に面積の大きいScreenの参照が入るって寸法。

Screen OrenoScreen = null;
long Area = 0;
foreach(Screen s in Screen.AllScreens)
{
    Rectangle IntersectRectangle = Rectangle.Intersect(s.Bounds, this.Bounds);
    long NewArea = (long)IntersectRectangle.Width * (long)IntersectRectangle.Height;
    if (Area < NewArea)
    {
        Area = NewArea;
        OrenoScreen = s;
    }
}
if (OrenoScreen == null)
{
    OrenoScreen = Screen.PrimaryScreen;
}

うまくいった!

まとめ

面積で取ると良い感じなのが分かった。

ただ、ループで回して比較してってのがちょっといまいち。
ありがちな処理なので、スマートに一発で取れるユーティリティ的な何かがありそうな気もするんだよね。
もっと良い方法あったら教えてください。

追記

一発でやる方法が分かりました!
こちらの記事を参照ください


コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です