質問者
TextBox系コントロールでの文字幅の異常

質問
-
OS : win7
VisualStudio:VS2010MS ゴシック,12ptに設定したTextBoxおよびRichTextBoxに文字列を表示させたのですが
一部の文字(全角スペース、~、など)の幅が以下のMeasureTextWidthで計測した値より僅かに小さく表示されてしまいます
WinFormではTextRenderer.MeasureTextで得られた文字幅通りにTextBoxに表示され、その文字幅もMeasureTextWidthのものと一致するので
計測した文字幅が間違っているのではなくTextBoxでの表示に問題があるのだと推測できましたが、どうすれば正常に表示できるのか分かりません
なにか問題点がありましたら、教えていただけないでしょうか
<TextBox Grid.Row="1" Name="textBox"Padding="0" FontFamily="MS PGothic" FontStretch="Normal" FontSize="16/> private int MeasureTextWidth(string st) { FormattedText formattedText = new FormattedText(st, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("MS PGothic"), 16, Brushes.Black, numberSub, TextFormattingMode.Display); double width = formattedText.WidthIncludingTrailingWhitespace ; return (int)width; }
すべての返信
-
空白やチルダの幅というと、A幅やC幅の扱いの差異かな?と思えますが、WPF の描画は全面的に自前でやっていそうなので、計測結果と描画が異なることはないと思いたいですね。
ですので、描画先と計測方法に不一致が発生している可能性を疑ってみてはいかがでしょうか?
具体的にどのような方法で計測値と描画を比較されているかわかりませんが、たとえば、使用している TypeFace が完全に一致していないとか、TextBox の配置されている場所に変換がかかっていて、画面上の描画が変形しているとか、計測に使用しているパラメータと描画に使用しているパラメータが違うとかですね。あとは、具体的な比較方法を提示すると、より具体的な話が出てくるかもしれませんね。
-
空白やチルダの幅というと、A幅やC幅の扱いの差異かな?と思えますが、WPF の描画は全面的に自前でやっていそうなので、計測結果と描画が異なることはないと思いたいですね。
ですので、描画先と計測方法に不一致が発生している可能性を疑ってみてはいかがでしょうか?
具体的にどのような方法で計測値と描画を比較されているかわかりませんが、たとえば、使用している TypeFace が完全に一致していないとか、TextBox の配置されている場所に変換がかかっていて、画面上の描画が変形しているとか、計測に使用しているパラメータと描画に使用しているパラメータが違うとかですね。あとは、具体的な比較方法を提示すると、より具体的な話が出てくるかもしれませんね。
以下の表でシンプルにズレがあるかないかで比較しました
WinFormでは階段状に表示されるのですが、WPFではズレてしまいます
16ドット | | 半角で「&emsp;」、全角スペース+半角スペース
15ドット | _ | 半角スペース2個+_
14ドット | .| 全角スペース+ドット
13ドット | . | 半角スペース2個+ドット
12ドット | ~| 半角スペース+~
11ドット | | 全角スペース
10ドット | _| 半角スペース+_
9ドット | ゙| 半角スペース+゙
8ドット | .| 半角スペース+ドット
7ドット |~|
6ドット |..|
5ドット | | 半角スペース
4ドット |゙|
3ドット |.|
2ドット | | (「&thinsp;」) -
WPF で確認できる環境がないのですが、
- 文章中では 12pt と書かれているが、XAML 上や実装では 16pt になっている
- XAML 上では、文字列の拡大縮小率が FontStreachs.Normal だが、TypeFaces はデフォルトの FontStreach.Medium で作成されている(たぶん問題ない)
- FormattedText.Width の単位は 1/96point で小数値で返されると思いますが、それを int に変換してから、さらにドット数に変換しているのでしょうか?
- 結局、何と何を比較しているのですか? (私には、書かれている文章では、まったくわかりません)
何が階段状で、何がずれるんでしょう?
-
WPF で確認できる環境がないのですが、
- 文章中では 12pt と書かれているが、XAML 上や実装では 16pt になっている
- XAML 上では、文字列の拡大縮小率が FontStreachs.Normal だが、TypeFaces はデフォルトの FontStreach.Medium で作成されている(たぶん問題ない)
- FormattedText.Width の単位は 1/96point で小数値で返されると思いますが、それを int に変換してから、さらにドット数に変換しているのでしょうか?
- 結局、何と何を比較しているのですか? (私には、書かれている文章では、まったくわかりません)
何が階段状で、何がずれるんでしょう?
- WPFではフォントの単位もpixelなので12ptに相当する16pixelを使っています
- 変えて試してみましたが改善されませんでした
- この条件ではぴったり整数値が返されます
- 「WinFormのMS Pゴシック 12ptでのTextBox」と、「WPFのMS PGothic 16pixelでのTextBox」との目視による比較です
この表はMS Pゴシック 12ptの環境下で範囲で一行につき1ドットずつ幅が狭くなっていくもので、WinFormのTextBoxでは一行ずつ階段状に表示されるのですがWPFのTextBoxではズレてしまいます
| | 半角で「&emsp;」、全角スペース+半角スペース | _ | 半角スペース2個+_ | .| 全角スペース+ドット | . | 半角スペース2個+ドット | ~| 半角スペース+~ | | 全角スペース | _| 半角スペース+_ | ゙| 半角スペース+゙ | .| 半角スペース+ドット |~| |..| | | 半角スペース |゙| |.| | | (「&thinsp;」)
-
ヘルプ上は、FontSize は「テキストの Em 単位のフォント サイズ (デバイスに依存しない単位 (1 単位は 1/96 インチ) で指定)。」と書いてあるのでポイント単位で指定だと思っていました。簡単に試してみましたが、
- そもそも、FontSizeが12でも16でも整数値なんて返りませんでした。
- WinForms と WPF でどちらも見た目は階段状になります。アンチエイリアス等の都合で WinForms と WPF の間で(画像として)比較すると、一致はしません。
-
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Console.WriteLine((MeasureTextWidth(" ")).ToString()); Console.WriteLine((MeasureTextWidth(" ")).ToString()); Console.WriteLine((MeasureTextWidth("~")).ToString()); } private double MeasureTextWidth(string st) { FormattedText formattedText = new FormattedText(st, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("MS PGothic"), 16, Brushes.Black,new NumberSubstitution() , TextFormattingMode.Display); return formattedText.WidthIncludingTrailingWhitespace; } }
回答ありがとうございます、当環境では上記のコードで整数値が出力されました
「WinFormのMS Pゴシック 12ptでのTextBox」と、
「WPFのTextBox」 <TextBox Name="textBox1" FontSize="16" AcceptsReturn="True" FontStretch="Normal" FontFamily="MS PGothic" />
の比較の画像をはっておきます
左がWinFormの望ましい表示で、右がWPFの文字幅がズレた表示です
http://www1.axfc.net/uploader/Img/so/108711.bmp
WPFで左の様に表示するにはどうしたら良いでしょうか