(XAML#24)「画面上のサイズとフォントのサイズ」
まず、WPF(その元になる Windows)における“長さ”について説明しておきます。Windows は、画面の解像度(ピクセル数ではなく DPI=Dot Per Inch)を96と想定しています。といっても、グラフィックの解像度(1920×1080など)と、実際のスクリーンサイズはバラバラですから、物理的な画面上の1インチを測ったところで、必ず96ドット(ピクセル)になるとは限りません。そこで、最近の Windows では、96DPIのような具体的な数字を表記する代わりに、「既定(100%)」「125%」「150%」と表記したり、「小さくする」「大きくする」と表記しています。しかし、内部的には100%=96DPIという計算になっており、125%のときは120DPI、150%なら144DPIという計算になることを覚えておいてください。
なお、コントロールパネルでこの設定を変えるときは「ログオフ(サインオフ)」するようにしてください。Windows 8ではサインオフしなくてもDPIが変更されたように見えますが、これはDPIではなくフォントサイズを変更して、疑似的に変更したように見せているだけです。
さて、WPFは、この設定を踏襲します。たとえば、WPFで「1インチの長さ」を表現したいのであれば「96」という固定の長さを指定することになります。これは、既定(100%=96DPI)の環境では物理画面の“96ドット”に相当します。つまり、1単位=1ドットが成立します。Windowsの設定(すべての項目のサイズを変更する)で、より大きな解像度が設定されている場合はどうでしょう。WPFで96という長さを指定したら、同じように「画面の1インチ」を確保しなければなりません。つまり物理画面上の120ドットの長さに相当します。つまり、同じ長さを指定していても、DPIの数値が大きい方が大きく表示されることになります。
※注意 なお、Silverlightは、環境の設定にかかわらず常に96DPIを想定して描画します。
たとえば、Windows の Loaded イベントを次のように記述できます。解像度は水平方向(X)と垂直方向(Y)の両方が存在します。
[コード]
public double DPIX { get; private set; }
public double DPIY { get; private set; }
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var source = PresentationSource.FromVisual(this);
if (source != null && source.CompositionTarget != null)
{
DPIX = 96.0 / source.CompositionTarget.TransformFromDevice.M11;
DPIY = 96.0 / source.CompositionTarget.TransformFromDevice.M22;
}
}
通常は、DPI を意識してサイズ計算に組み入れる必要はありません。一般にアプリケーションを利用者が DPI の設定を大きくしているのは、アプリケーションの表示を大きくしたいためですから、物理的なスクリーンのサイズに制限されるということでもなければ、そのまま描画するのが好ましいでしょう。フォントも DPI の設定によって拡大されています。
しかし、ビットマップイメージをドット単位で表示したり、ドット数を考慮して画面キャプチャ刺せるような場合には、これを計算しなければなりません。たとえば、Imageコントロールなどを使ってイメージを表示する場合は、前述の計算式で使われている「source.CompositionTarget.TransformFromDevice.M11」(水平方向の場合)を、表示したいドット数に乗じるだけです。
画面の大きさに合わせてフォントの大きさを変更したいという場合も、同様の計算が必要です。ただし、フォントサイズの基準となる「ポイント」は1/72インチを単位とします。物理画面上のドット数にかかわらず、WPFでは96が1インチをあらわす基準となっていることに注意してください。つまり、“1ポイント”は(WindowsのDPIの設定にかかわらず)WPFの96÷72=1.333…(4/3)に相当します。つまり、WPF 上のある領域に収まるフォントサイズを計算したい場合は、そのサイズを4/3で割れば(3/4を掛ければ)求められます。
たとえば、通常の画面設定(96DPI)であれば、100ドットのサイズに収まるフォントは100÷96×72=75ポイントのフォントということになります。なお、フォントサイズは、描画範囲の大枠を示しているだけで、ベースラインを持つ場合はディセント(ベースラインの下側)に余白ができたり、水平方向ではカーニングといって字間を詰めて描画されることがあるので、ギリギリのサイズを指定しても常に「いっぱいいっぱい」に表示されるわけではありません。
次のコードは、画面の Grid パネル上に10行描画できるようなフォントサイズを計算してウィンドウに設定しています。
[XAML]
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="Window_Loaded">
<Grid>
...
[コード]
private void Window_Loaded(object sender, RoutedEventArgs e)
{
FontSize =(((Grid)this.Content).RenderSize.Height / 96.0 * 72.0) / 10.0;
}