ワードラップとテキストの位置をシミュレートするために C# で文字列幅を取得しようとしています (現在は richTextBox に記述されています)。
richTextBox のサイズは 555x454 px で、等幅フォント Courier New 12pt を使用しています。
TextRenderer.MeasureText()
私もGraphics.MeasureString()
方法を試しました。
TextRenderer
Graphics
通常は1行に収まるテキストよりも大きな値を返していたため、コードを別の行に折り返す必要があると判断しました。
しかし、Graphics
一方で、私のコードは、特定の文字列が元の richTextBox に出力されるよりも短いと判断したため、間違った場所で次の行に折り返されました。
デバッグ中に、計算された幅が異なることがわかりました。これは、等幅フォントを使用しているため、すべての文字の幅が同じである必要があるため、奇妙です。しかし、私はこのようなものを取得しますGraphics.MeasureString()
(例: ' ' - 5.33333254、'S' - 15.2239571、'\r' - 5.328125)。
C# で文字列の幅を正確に計算し、ワードラップをシミュレートして、特定のテキスト位置をピクセル単位で決定するにはどうすればよいですか?
等幅フォントを使用すると、文字によって幅が異なるのはなぜですか?
注: 私は個人的なアイ トラッキング プロジェクトに取り組んでおり、実験中に特定のテキストが配置された場所を特定して、ユーザーがどの単語を見ていたかを判断したいと考えています。たとえば。t
ユーザーがポイント [256,350]px を見ていましたが、この場所でメソッドの呼び出しがあることがわかりましたWriteLine
。私のターゲットの視覚的刺激は、インデント、タブ、行末が編集可能なテキスト領域に配置されたソース コードです (将来的には、単純なオンライン ソース コード エディターになる可能性があります)。
これが私のコードです:
//before method call
var font = new Font("Courier New", 12, GraphicsUnit.Point);
var graphics = this.CreateGraphics();
var wrapped = sourceCode.WordWrap(font, 555, graphics);
public static List<string> WordWrap(this string sourceCode, Font font, int width, Graphics g)
{
var wrappedText = new List<string>(); // output
var actualLine = new StringBuilder();
var actualWidth = 0.0f; // temp var for computing actual string length
var lines = Regex.Split(sourceCode, @"(?<=\r\n)"); // split input to lines and maintain line ending \r\n where they are
string[] wordsOfLine;
foreach (var line in lines)
{
wordsOfLine = Regex.Split(line, @"( |\t)").Where(s => !s.Equals("")).ToArray(); // split line by tabs and spaces and maintain delimiters separately
foreach (string word in wordsOfLine)
{
var wordWidth = g.MeasureString(word, font).Width; // compute width of word
if (actualWidth + wordWidth > width) // if actual line width is grather than width of text area
{
wrappedText.Add(actualLine.ToString()); // add line to list
actualLine.Clear(); // clear StringBuilder
actualWidth = 0; // zero actual line width
}
actualLine.Append(word); // add word to actual line
actualWidth += wordWidth; // add word width to actual line width
}
if (actualLine.Length > 0) // if there is something in actual line add it to list
{
wrappedText.Add(actualLine.ToString());
}
actualLine.Clear(); // clear vars
actualWidth = 0;
}
return wrappedText;
}