C#GDI+;换行文本(不带文本渲染器)

C#GDI+;换行文本(不带文本渲染器),c#,gdi,word-wrap,C#,Gdi,Word Wrap,假设我有“Lorem ipsum Door sit amet,Concertetur adipiscing Elite.Phasellus arcu massa,tempus non tincidunt ut,tempus sit amet odio.Mauris在酒后驾车”这一串字 我希望字符串以特定长度(以像素为单位)进行包装,并且不打断单词。例如80像素 我有用于绘制字符串的字体变量和图形变量(通常称为“g”),以便在需要时测量字符串的长度 我找到的所有示例仅按字符长度包装文本,但我需要它

假设我有“Lorem ipsum Door sit amet,Concertetur adipiscing Elite.Phasellus arcu massa,tempus non tincidunt ut,tempus sit amet odio.Mauris在酒后驾车”这一串字

我希望字符串以特定长度(以像素为单位)进行包装,并且不打断单词。例如80像素

我有用于绘制字符串的字体变量和图形变量(通常称为“g”),以便在需要时测量字符串的长度

我找到的所有示例仅按字符长度包装文本,但我需要它以像素为单位用于GDI+绘图。 我不想使用TextRenderer控件,因为它似乎有bug。有时,它测量自己的文本高度是错误的。这种情况很少见,但经常发生

到目前为止,我得到了以下信息:

public static string WrapTextByPixels(string text, ref Graphics g, Font font, float maxWidth)
        {
            string[] originalLines = text.Split(new[] { " " }, StringSplitOptions.None);

            var wrapBuilder = new StringBuilder();

            float currentLineWidth = 0;

            foreach (var item in originalLines)
            {
                float itemWidth = g.MeasureString(item, font).Width;

                currentLineWidth += itemWidth;
                if (currentLineWidth > maxWidth ||
                    itemWidth > maxWidth) // When a single word is longer than the maxWidth then just add it
                {
                    wrapBuilder.Append(Environment.NewLine);
                    currentLineWidth = 0;
                }
                wrapBuilder.Append(item + " ");
            }

            return wrapBuilder.ToString();
        }

但是上面的代码不起作用。有些行仍然太长。

这是我曾经发现的一种扩展方法,它不是我自己的扩展方法,我想给予表扬,但我不记得是从哪里得到的:

public static string WrapText(this string text, double pixels, string fontFamily, float emSize)
    {
        string[] originalLines = text.Split(new[] { " " }, StringSplitOptions.None);

        var wrapBuilder = new StringBuilder();

        double actualWidth = 0;

        foreach (var item in originalLines)
        {
            var formatted = new FormattedText(
                item,
                CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                new Typeface(fontFamily),
                emSize,
                Brushes.Black);

            actualWidth += formatted.Width;
            if (actualWidth > pixels)
            {
                wrapBuilder.Append(Environment.NewLine);
                actualWidth = 0;
            }
            wrapBuilder.Append(item + " ");
        }

        return wrapBuilder.ToString();
    }

这应该会对您有所帮助。

这是我曾经发现的一种扩展方法,它不是我自己的,我想给予表扬,但我不记得是从哪里得到的:

public static string WrapText(this string text, double pixels, string fontFamily, float emSize)
    {
        string[] originalLines = text.Split(new[] { " " }, StringSplitOptions.None);

        var wrapBuilder = new StringBuilder();

        double actualWidth = 0;

        foreach (var item in originalLines)
        {
            var formatted = new FormattedText(
                item,
                CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                new Typeface(fontFamily),
                emSize,
                Brushes.Black);

            actualWidth += formatted.Width;
            if (actualWidth > pixels)
            {
                wrapBuilder.Append(Environment.NewLine);
                actualWidth = 0;
            }
            wrapBuilder.Append(item + " ");
        }

        return wrapBuilder.ToString();
    }

这应该会对您有所帮助。

我并不完全相信GDI+文本格式化程序已经损坏,但在某些情况下,它无法满足您的需要,您需要自行进行文字包装

“简单”的方法是扫描你的字符串,寻找你喜欢插入断线的位置(比如在空格处),但是你也可以考虑标点符号,比如逗号和破折号作为位置。 在逐字构建新字符串时,请使用

Graphics.MeasureString
确定新的行宽。当宽度超过所需宽度时,需要在当前单词前插入换行符

请注意,您将遇到无法在可用宽度内断开的文本问题(一个很长的单词,没有空格,或者格式宽度很窄),因此在这种情况下,您可能需要一种在单词内断开的回退机制(或者在适合的最后一个字符处停止,或者疯狂地添加连字号系统)

还请注意,在处理这样的文本片段时,使用的
StringFormat
可能会导致问题,因为它可以设置为在正在测量的文本的开始/结束处包含/排除空白,因此,这可能会导致宽度计算出错,从而导致在最后一个字符“擦”格式化区域的边缘时,换行有点太早或太晚。以类似的方式,您必须小心行尾的空格和多个空格字符序列


对于调试,一个好的方法是根据窗口的宽度设置格式宽度,然后为每次重新绘制重新设置文本格式。然后,您可以逐渐将widow拖出并拖回,以检查格式化程序是否以理想宽度进行换行,并处理狭窄的格式化区域等。

我不完全相信GDI+文本格式化程序已损坏,但在某些情况下,它无法满足您的需要,您需要自己进行换行

“简单”的方法是扫描你的字符串,寻找你喜欢插入断线的位置(比如在空格处),但是你也可以考虑标点符号,比如逗号和破折号作为位置。 在逐字构建新字符串时,请使用

Graphics.MeasureString
确定新的行宽。当宽度超过所需宽度时,需要在当前单词前插入换行符

请注意,您将遇到无法在可用宽度内断开的文本问题(一个很长的单词,没有空格,或者格式宽度很窄),因此在这种情况下,您可能需要一种在单词内断开的回退机制(或者在适合的最后一个字符处停止,或者疯狂地添加连字号系统)

还请注意,在处理这样的文本片段时,使用的
StringFormat
可能会导致问题,因为它可以设置为在正在测量的文本的开始/结束处包含/排除空白,因此,这可能会导致宽度计算出错,从而导致在最后一个字符“擦”格式化区域的边缘时,换行有点太早或太晚。以类似的方式,您必须小心行尾的空格和多个空格字符序列


对于调试,一个好的方法是根据窗口的宽度设置格式宽度,然后为每次重新绘制重新设置文本格式。然后,您可以逐渐将窗口拖出并拖回,以检查格式化程序是否以理想宽度换行,并处理狭窄的格式化区域等。

您不能在此处绕过TextRenderer,您必须使用其MeasureText()方法,以便计算出的布局与稍后在DrawText()时渲染的内容相匹配方法渲染文本。计算字符串长度的其他方法,如Graphics.MeasureString()只会产生更多错误,Graphics类的文本布局非常不同。这是在.NET2.0中添加TextRenderer的原因


如果结果不好,那几乎总是因为没有正确指定TextFormatFlags。它必须与DrawText()方法调用中使用的标志完全匹配。这并不总是容易找到的,尤其是当文本是通过在框架内绘制代码绘制的时候。使用查找。

此处不能绕过TextRenderer,您必须使用其MeasureText()方法,以便计算的布局与稍后DrawText()方法渲染文本时渲染的内容相匹配。计算字符串长度的其他方法,如Graphics.MeasureString()只会产生更多错误,Graphics类的文本布局非常复杂