适合特定宽度的字符串长度

时间:2010-12-27 23:50:43

标签: wpf wpf-controls

我确定我错过了一些明显的东西,我有一个区域,我打算在其中绘制文字。我知道它(区域)的高度和宽度。我想知道宽度中有多少个字符/单词,最好是字符。第二个问题,如果线太长我想画第二行,所以我想我也需要得到文本的高度,包括它认为正确的垂直填充?

我也想知道反转,即我可以在特定宽度中容纳多少个字符。

我认为WPF不受像素约束的事实会对答案有所影响吗?

最终,我计划在文本中嵌入不规则形状图像周围的文字。

任何正确方向的指针都会很棒。

由于

3 个答案:

答案 0 :(得分:16)

对于WPF,您可以使用FormattedText类来计算给定文本字符串将使用的宽度 - 它将取决于实际文本。

示例:

FormattedText formattedText = new FormattedText("Hello Stackoverflow", 
                                                System.Globalization.CultureInfo.GetCultureInfo("en-us"), 
                                                FlowDirection.LeftToRight, 
                                                new Typeface("Arial"), FontSize =14, Brushes.Black);
double textWidth = formattedText.Width;

获取给定宽度的子字符串(简化):

string text  = GetSubStringForWidth("Hello Stackoverflow", 55);
...
public string GetSubStringForWidth(string text, double width)
{
    if (width <= 0)
        return "";

    int length = text.Length;
    string testString;

    while(true)//0 length string will always fit
    {
        testString = text.Substring(0, length);
        FormattedText formattedText = new FormattedText(testString, 
                                                        CultureInfo.GetCultureInfo("en-us"), 
                                                        FlowDirection.LeftToRight, 
                                                        new Typeface("Arial"), 
                                                        FontSize = 14, 
                                                        Brushes.Black);
        if(formattedText.Width <= width)
            break;
        else
            length--;
    }
    return testString;
}

答案 1 :(得分:3)

@ BrokenGlass的答案很棒,但根据应用程序的特性,您可能会发现使用二进制搜索可以获得更好的性能。如果大多数字符串符合可用宽度,或者通常只需要修剪一两个字符,那么线性搜索最好。但是,如果你有很多长字符串会被严重截断,那么下面的二进制搜索就可以正常工作。

请注意,availableWidth和fontSize都是在与设备无关的单位(1/96英寸)中指定的。另外,使用与您绘制文本的方式相匹配的TextFormattingMode。

public static string TruncateTextToFitAvailableWidth(
    string text, 
    double availableWidth, 
    string fontName, 
    double fontSize)
{
    if(availableWidth <= 0)
        return string.Empty;

    Typeface typeface = new Typeface(fontName);

    int foundCharIndex = BinarySearch(
        text.Length,
        availableWidth,
        predicate: (idxValue1, value2) =>
        {
            FormattedText ft = new FormattedText(
                text.Substring(0, idxValue1 + 1), 
                CultureInfo.CurrentCulture, 
                FlowDirection.LeftToRight, 
                typeface, 
                fontSize, 
                Brushes.Black,
                numberSubstitution: null,
                textFormattingMode: TextFormattingMode.Ideal);

            return ft.WidthIncludingTrailingWhitespace.CompareTo(value2);
        });

    int numChars = (foundCharIndex < 0) ? ~foundCharIndex : foundCharIndex + 1;

    return text.Substring(0, numChars);
}

/**
<summary>
See <see cref="T:System.Array.BinarySearch"/>. This implementation is exactly the same,
except that it is not bound to any specific type of collection. The behavior of the
supplied predicate should match that of the T.Compare method (for example, 
<see cref="T:System.String.Compare"/>).
</summary>
*/      
public static int BinarySearch<T>(
    int               length,
    T                 value,
    Func<int, T, int> predicate) // idxValue1, value2, compareResult
{
    return BinarySearch(0, length, value, predicate);
}

public static int BinarySearch<T>(
    int               index,
    int               length,
    T                 value,
    Func<int, T, int> predicate)
{
    int lo = index;
    int hi = (index + length) - 1;

    while(lo <= hi)
    {
        int mid = lo + ((hi - lo) / 2);

        int compareResult = predicate(mid, value);

        if(compareResult == 0)
            return mid;
        else if(compareResult < 0)
            lo = mid + 1;
        else
            hi = mid - 1;
    }

    return ~lo;
}

答案 2 :(得分:-1)

这是不可能的,因为字符的长度不同,例如W比i宽得多(除非你使用像Courier New这样的字体)。