C#GDI +换行文本(没有TextRenderer)

问题描述 投票:0回答:3

说1有字符串“Lorem存有胡萝卜,生态番茄汤。南弧质量,时间对于开发商来说,很多时间的硬件。Vulputate最大的在巴基斯坦,但它是。”

我希望该字符串包裹特定长度(以像素为单位)并且不会破坏单词。例如80像素。

我有Font变量用于绘制字符串和Graphics变量(通常称为“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();
        }

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

c# gdi textwrapping
3个回答
2
投票

你不能在这里绕过TextRenderer,你必须使用它的MeasureText()方法,以便计算的布局匹配渲染的内容,稍后,当DrawText()方法呈现文本时。计算字符串长度的其他方法,如Graphics.MeasureString()只会产生更多错误,Graphics类的文本布局非常不同。而且非常糟糕,TextRenderer是在.NET 2.0中添加的原因

如果你得到不好的结果,那几乎总是因为你没有正确指定TextFormatFlags。它必须与将在DrawText()方法调用中使用的标志完全匹配。这并不总是很容易找到,特别是当文本是通过在框架内绘制代码绘制的。使用Reference Source找出答案。


1
投票

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

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();
    }

这应该可以帮助你。


1
投票

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

“简单”的方法是扫描你的字符串,寻找你喜欢插入换行符的位置(例如在空格处 - 但你也可以考虑使用逗号和短划线作为主要位置的标点符号)。

在逐字构建新字符串时,使用Graphics.MeasureString确定该行的新宽度。当它超出所需宽度时,您需要在当前单词之前插入换行符。

请注意,您将遇到无法在可用宽度中打破的文本(一个非常长的单词,其中没有空格或非常窄的格式化宽度)的问题,因此您可能需要一个在这些情况下在单词内打破的回退机制(要么停在适合的最后一个字符,要么发疯并添加一个连字系统)。

还要注意你使用的StringFormat在处理这样的文本片段时可能会出现问题,因为它可以设置为在你测量的文本的开头/结尾包含/排除空格,所以这会搞砸宽度计算,这样就可以了当最后一个字符“擦过”格式化区域的边缘时,会导致您过早或稍晚进行自动换行。以类似的方式,您必须注意行末尾的空格和多个空白字符序列。

对于调试,一种好的方法是将格式宽度基于窗口的宽度,然后为每次重绘重新格式化文本。然后你可以逐渐拖出寡妇来检查格式化程序是否有理想宽度的自动换行,并应对狭窄的格式化区域等。

© www.soinside.com 2019 - 2024. All rights reserved.