首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >计算字符串宽度时的奇怪行为(以像素为单位)

计算字符串宽度时的奇怪行为(以像素为单位)
EN

Stack Overflow用户
提问于 2017-02-21 09:09:54
回答 2查看 363关注 0票数 1

尝试在C#中获取字符串宽度以模拟文字包装和文本位置(现在用richTextBox编写)。

richTextBox的大小是555x454px,我使用单间距字体CourierNew12pt。

我尝试了TextRenderer.MeasureText()Graphics.MeasureString()方法。

TextRenderer返回的值比Graphics大,所以文本通常适合一行,所以我确定的代码应该包装到另一行。

但是,另一方面,通过使用Graphics,我的代码确定特定的字符串比在原始richTextBox中打印的字符串短,因此它被包装到下一行的错误位置。

在调试过程中,我发现计算的宽度不同,这很奇怪,因为我使用单间距字体,所以所有字符的宽度都应该是相同的。但是我从Graphics.MeasureString()得到类似的东西(例如:‘’- 5.33333254,'S‘- 15.2239571,'\r’- 5.328125)。

如何使用C#精确地计算字符串宽度,从而模拟文字包装并以像素确定特定的文本位置?

为什么在使用单间距字体时,不同字符的宽度不同?

注:我正在从事个人眼睛跟踪项目,我想确定,在实验期间,特定的文本放在哪里,这样我就可以知道哪些单词是用户查看的。为了前夫。当时,t用户正在查看点256,350 on,我知道在这里有WriteLine方法调用。我的目标视觉刺激是源代码,带有缩进、制表符、行尾,放在一些可编辑的文本区域(将来可能是一些简单的在线源代码编辑器)。

这是我的代码:

代码语言:javascript
运行
复制
    //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;
        }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-21 17:00:11

最后,我在代码中添加了一些内容。我会把它缩短。

代码语言:javascript
运行
复制
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;
    }

通过这些修正,我得到了正确的普通字符宽度(使用单间距字体,我得到了相同的宽度)。

但是其他的白空间(如\t\n )仍然存在问题,当我用Courier,12pt字体测量宽度时,会得到0.00781259.6015625。第二个值是用这种字体输入的任何字符的宽度,所以这不是一个大问题,但最好是0,还是我错了?如果有人有解决这个问题的建议,请留言。

票数 0
EN

Stack Overflow用户

发布于 2017-02-21 11:19:35

我相信,通过在屏幕上给定的位置下获得一个字符来完成任务要容易得多。例如,如果您使用的是RichTextBox控件,请参考RichTextBox.GetCharIndexFromPosition方法获取与指定位置最近的字符的索引。下面是一些示例代码,它演示了这个想法:

代码语言:javascript
运行
复制
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();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42362999

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档