尝试在C#中获取字符串宽度以模拟wordwrap和文本位置(现在用richTextBox编写)。
richTextBox的大小为555x454像素,我使用等宽字体Courier New 12pt。
我尝试了TextRenderer.MeasureText()
和Graphics.MeasureString()
方法。
TextRenderer
返回的值大于Graphics
,因此文本通常适合一行,我的代码确定应该换行到其他行。
但另一方面,使用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;
}
答案 0 :(得分:0)
我相信通过在屏幕上的给定位置下获取角色来完成任务要容易得多。例如,如果您使用的是RichTextBox控件,请参阅RichTextBox.GetCharIndexFromPosition方法以获取最接近指定位置的字符的索引。以下是一些演示该想法的示例代码:
private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
var textIndex = richTextBox1.GetCharIndexFromPosition(e.Location);
if (richTextBox1.Text.Length > 0)
label1.Text = richTextBox1.Text[textIndex].ToString();
}
答案 1 :(得分:0)
所以我最后在我的代码中添加了一些东西。我会缩短它。
public static List<string> WordWrap(this string sourceCode, Font font, int width, Graphics g)
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
var format = StringFormat.GenericTypographic;
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
var width = g.MeasureString(word, font, 0, format).Width;
}
通过这些修正,我得到了正确字符的正确宽度(使用等宽字体我得到相等的宽度)。
但是当使用Courier New,12pt字体测量宽度时,\t
和\n
等其他空格仍然存在问题,我得到0.0078125
和9.6015625
。第二个值是用这个字体键入的任何字符的宽度,所以它不是一个大问题,但最好是0或我错了?如果有人有解决这个问题的建议,请发表评论。