画面のサイズを取得するには?[ユニバーサルWindowsアプリ開発]WinRT/Metro TIPS

ユニバーサルプロジェクトの共有プロジェクトを用いて、画面サイズに関係する各種の情報を取得する方法を解説する。

» 2014年08月07日 16時18分 公開
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次

 画面のサイズを取得したいことはないだろうか? 特にユニバーサルプロジェクトの共有プロジェクトでUI(ユーザーインターフェース)を記述していると、対応すべき画面サイズが多いので、より切実だろう。本稿では、ウィンドウの論理的なサイズを取得する方法と、実際のピクセル数を求める方法の、両方について説明する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #86」からダウンロードできる。

事前準備

 ユニバーサルプロジェクトを使ってユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Express 2013 for Windowsを使っている。

  • SLAT対応のPC*1
  • 2014年4月のアップデート*2適用済みの64bit版Windows 8.1 Pro版以上*3
  • Visual Studio 2013 Update 2(またはそれ以降)*4を適用済みのVisual Studio 2013(以降、VS 2013)*5

*1 SLAT対応ハードウェアは、Windows Phone 8.1エミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能だ。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウェアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。

*2 事前には「Windows 8.1 Update 1」と呼ばれていたアップデート。スタート画面の右上に検索ボタンが(環境によっては電源ボタンも)表示されるようになるので、適用済みかどうかは簡単に見分けられる。ちなみに公式呼称は「the Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 update that is dated April, 2014」というようである。

*3 Windows Phone 8.1エミュレーターを使用しないのであれば、32bit版のWindows 8.1でもよい。

*4 マイクロソフトのダウンロードページから誰でも入手できる。

*5 本稿に掲載したコードを試すだけなら、無償のExpressエディションで構わない。Visual Studio Express 2013 Update 3 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsストアアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。


用語

 本稿では、紛らわしくない限り次の略称を用いる。

  • Windows:Windows 8.1とWindows RT 8.1(2014年4月のアップデートを適用済みのもの)
  • Phone:Windows Phone 8.1

サンプルコードについて

 Visual Studio 2013 Update 2(およびUpdate 3)では、残念なことにVB用のユニバーサルプロジェクトのテンプレートは含まれていない*6。そのため、本稿で紹介するコードはC#のユニバーサルプロジェクトだけとさせていただく*7

*6 VB用のユニバーサルプロジェクトは、来年にリリースされるといわれているVisual Studio「14」からの提供となるようだ。「Visual Studio UserVoice」(英語)のリクエストに対する、6月18日付けの「Visual Studio team (Product Team, Microsoft)」からの回答による。

*7 Visual Studio 2013 Update 2(またはそれ以降)のVBでユニバーサルWindowsアプリを作る場合のお勧めは、「The Visual Basic Team」のブログ記事(英語)によれば、PCLを使う方法のようである。しかし、本稿で説明するような「#if」ディレクティブを使う方法は、PCLでは利用できない。


論理サイズを取得するには?

 論理サイズ、すなわちDIP単位でウィンドウのサイズを取得するには、Windowクラス(Windows.UI.Xaml名前空間)のBoundsプロパティを使えばよい。

 DIP(=Device Independent Pixel、デバイス非依存ピクセル)とは、XAMLコードでコントロールのサイズなどを指定するときの単位である。1DIPは1論理インチの96分の1であり、1論理インチは72ポイントのフォントの高さと定義されている。

 ウィンドウの論理サイズを取得するコードは、次のようになる。

Windows.Foundation.Rect logicalSize = Windows.UI.Xaml.Window.Current.Bounds;
double logicalWidth = logicalSize.Width;   // 幅(DIP単位)
double logicalHeight = logicalSize.Height; // 高さ(DIP単位)

ウィンドウの論理サイズを取得する(C#)
このコードで取得した幅と高さは、DIP(デバイス非依存ピクセル)単位である。
なお、画面のサイズではなくウィンドウのサイズであることに注意。Windowsで複数アプリを並べて表示しているときには、画面の幅ではなく、分割されたウィンドウの幅になる。

 通常はXAMLコードで指定する寸法(すなわち、DIP単位)で考えているはずなので、この論理サイズが分かれば十分だろう。しかし、物理的なサイズ(実際のピクセル数)を知りたいこともある。そのときは、以降で説明するようにして、論理サイズにスケールファクターを掛け合わせる。

スケールファクターを取得するには?

 スケールファクター(「スケールプラトー」とも言う)を取得するには、WindowsではDisplayInformationクラス(Windows.Graphics.Display名前空間)のResolutionScaleプロパティを、PhoneではDisplayInformationクラスのRawPixelsPerViewPixelプロパティを使えばよい。

 前述の論理サイズを物理的なピクセル数に換算するための係数が、スケールファクターだ。高解像度のモニターでは大きなスケールファクターが適用されており、以前のTIPSで述べたように*8、スケールファクターに応じた画像が自動的に使用される。スケールファクターが取得できれば、物理的なピクセル数に換算することもできるし、解像度に応じた適切な画像をコードで選ぶことも可能になる。

 スケールファクターを取得するコードは、次のようになる。共有プロジェクトで記述する場合は、このように「#if」ディレクティブで切り分ける。

#if WINDOWS_APP
  // Windows用のコード
  Windows.Graphics.Display.ResolutionScale resolutionScale 
    = Windows.Graphics.Display.DisplayInformation.GetForCurrentView()
      .ResolutionScale;
  double scaleFactor = (double)resolutionScale / 100.0;
#endif
#if WINDOWS_PHONE_APP
  // Phone用のコード
  double scaleFactor = Windows.Graphics.Display.DisplayInformation.GetForCurrentView()
                       .RawPixelsPerViewPixel;
#endif

スケールファクターを取得する(C#)
Windows用のコードに出てくる「ResolutionScale」は列挙型であるが、それぞれの値としてスケールファクターのパーセント(=スケールファクターを100倍した値)が割り当てられている。従って、double型にキャストして100で割ることでスケールファクターになる。将来において異なる値が割り当てられる可能性を心配するならば、switch文を記述すること。
なお、Phoneでも、Windows Phone 8.1のWindows Runtimeアプリに限ってはResolutionScaleプロパティが存在しているのだが、MSDNには「ResolutionScale may be altered or unavailable for releases after Windows Phone 8.1」と記載があり、将来なくなることが予告されている。
また、UIが構築される以前にDisplayInformationクラスを使おうとすると例外になってしまうので、注意してほしい。このコードは、フレームのSizeChangedイベントなどで実行するとよい。

実際のピクセル数を求めるには?

 前述した論理サイズにスケールファクターを掛ければよい。

 ウィンドウの実際のピクセル数を求めるコードは、前述したコードの変数を使って、次のように書ける。

double physicalWidth = logicalWidth * scaleFactor;   // 幅(ピクセル単位)
double physicalHeight = logicalHeight * scaleFactor; // 高さ(ピクセル単位)

ウィンドウの実際のピクセル数を求める(C#)

(別解)論理DPIを求めるには?

 DisplayInformationクラスのLogicalDpiプロパティを使えばよい。

 1DIPは1論理インチの96分の1であることは前に述べた。これは、スケールファクターが100%のときには、1論理インチに実際のピクセルが96個あるということだ。1論理インチに実際のピクセルがいくつあるかを、論理DPI(=Dot Per Inch、1論理インチあたりのドット数)という。スケールファクターが100%のとき論理DPIは96であり、スケールファクターが200%なら論理DPIは192になる。

 逆に言えば論理DPIを96で割ればスケールファクターになるから、論理DPIを使っても実際のピクセル数を求められるのだ。

 論理DPIを取得するコードは、次のようになる。

float logicalDpi = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi;

論理DPIを取得する(C#)
このlogicalDpiを96で割ることでも、スケールファクターを求められる。

実行結果

 以上で説明した論理DPI/論理サイズ/スケールファクター/実際のピクセル数(以降、物理サイズという)を、ウィンドウのサイズが変更されるたびに表示するアプリを作った(別途公開のサンプルコードを参照)。実行結果は、以下のようになる。

 まず、Windowsで画面の向きの違いと複数アプリを表示したときを見てみよう。画面はシミュレーターの10.6インチ、物理サイズは1366×768ピクセル、スケールファクター100%のものだ。表示内容は上から順に、論理DPI/論理サイズ(幅×高さ)/スケールファクター/物理サイズ(幅×高さ)である。スケールファクターが100%なので、論理サイズと物理サイズは一致している。

10.6インチ(Windowsシミュレーター)
1366×768ピクセル(Windowsシミュレーター)
スケールファクター100%(Windowsシミュレーター) 10.6インチ、1366×768ピクセル、スケールファクター100%(Windowsシミュレーター)
スケールファクター100%のときは、論理サイズと物理サイズが一致する。
画面の向きを変えると、幅と高さは入れ替わって取得される。また、複数アプリを表示しているとき、取得される幅は画面幅ではなくアプリのウィンドウの幅になっていることが分かる(複数アプリ表示時に画面幅を取得したいときはDirectXを使わねばならない)。

 次は、Windowsでスケールファクターが異なる場合である。画面はいずれもシミュレーターの10.6インチのものだが、スケールファクターは100%(物理サイズ1366×768)/140%(1920×1080)/180%(2560×1440)の3通りだ。後ろ2つの画像のサイズは、論理サイズに合わせて縮小してある。

10.6インチ、スケールファクター100%(Windowsシミュレーター)
10.6インチ、スケールファクター140%(Windowsシミュレーター)
10.6インチ、スケールファクター180%(Windowsシミュレーター) 10.6インチ、スケールファクター100%/140%/180%(Windowsシミュレーター)
画像は論理サイズに合わせて縮小してある。解像度が異なっていても、ほぼ同じ見掛けになっていることが分かるだろう。また、論理DPIと論理サイズには小数点以下の端数が付くこともあるが、物理サイズはきれいな整数になっている(実際のピクセル数なのだから、整数になって当然ではある)。

 最後は、Phoneでスケールファクターが異なる場合である。画面はいずれもエミュレーターのもので、「Emulator 8.1 WVGA 4 inch」(=物理サイズ480×800ピクセル、スケールファクター120%)、「Emulator 8.1 720P 4.7 inch」(=720×1280ピクセル、180%)、「Emulator 8.1 WXGA 4.5 inch」(=768×1280ピクセル、200%)の3通りだ。画像のサイズは、3つとも論理サイズに合わせて縮小してある。

WVGA 4インチ(Phoneエミュレーター)
720P 4.7インチ(Phoneエミュレーター)
WXGA 4.5インチ(Phoneエミュレーター) WVGA 4インチ/720P 4.7インチ/WXGA 4.5インチ(Phoneエミュレーター)
3画像とも論理サイズに合わせて縮小してある。解像度が異なっていても、ほぼ同じ見掛けになっている。またWXGA(一番下)の論理サイズを見ると幅が384ピクセルとなっていることから、Phoneでの画面デザインは(DIPで)380ピクセル程度の幅を想定すべきだと分かる(XAMLエディターのデフォルトは、幅がDIPで400ピクセルあるWVGAになっている)。
なお、画像は掲載しないが、画面の向きを変えるとWindowsと同様に幅と高さが入れ替わって取得される。

まとめ

 画面(正確にはウィンドウ)の論理サイズは簡単に取得できる。別途取得したスケールファクターを使って、論理サイズを物理サイズ(実際のピクセル数)に変換できる。

 画面のピクセル密度(=解像度)の扱いについては、次のドキュメントも参照してほしい。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。