如何实现AutoSize

时间:2010-05-20 15:25:45

标签: c# .net algorithm

我正在试图找出一种自动调整其中包含文字的Rectangle的好方法。我基本上希望大小具有宽度/高度的比率,然后根据该比率“增长”以适合文本。我看过Graphics.MeasureString,但我认为它没有做我正在寻找的东西(也许它确实如此,我只是错误地使用它。)

我不想指定要绘制的矩形的特定宽度。相反,我想说在给定最小宽度的情况下找到适合此文本的最小宽度/高度,但找到的矩形必须具有一定的宽度和高度比。

这不一定是C#特有的,解决这个问题的任何想法我都确定可以映射到C#。

谢谢!

4 个答案:

答案 0 :(得分:1)

我相信你可以使用Graphics.MeasureString。这是我在GUI代码中用来在文本周围绘制矩形的内容。您将文本和要使用的字体交给它,它会返回一个矩形(技术上是一个SizeF对象 - 宽度和高度)。然后你可以按你想要的比例调整这个矩形:

Graphics g = CreateGraphics();
String s = "Hello, World!";
SizeF sizeF = g.MeasureString(s, new Font("Arial", 8));

// Now I have a rectangle to adjust.
float myRatio = 2F;
SizeF adjustedSizeF = new SizeF(sizeF.Width * myRatio, sizeF.Height * myRatio);
RectangleF rectangle = new RectangleF(new PointF(0, 0), adjustedSizeF);

我能正确理解你的问题吗?

答案 1 :(得分:1)

您应该使用TextRenderer.MeasureText,所有控件都使用TextRenderer在.NET 2.0及更高版本中绘制文本。

您的问题没有明确的解决方案,有很多种方法可以在Rectangle中插入文本。一个只显示一行的宽行与一个显示多行的窄行一样有效。你必须约束其中一个维度。这是一个现实的要求,这个矩形显示在一些其他控件内,并且该控件具有某个ClientSize。你需要决定如何安排它。

答案 2 :(得分:0)

关于System.Windows.Forms.Label的评论背面,也许你可以看一下驱动Label绘画的代码?如果你使用Reflector,这应该让你成为一部分。

似乎有一些方法就像GetPreferredSizeCore()那样可能有你想要的东西,我肯定可以通过一点点的工作使其足够通用。

答案 3 :(得分:0)

我找到了自己的解决方案。以下代码确定最适合文本的矩形(匹配比率)。它使用分而治之来找到最接近的矩形(通过将某个“步长”减去宽度)。此算法使用始终满足的最小宽度,我确信可以将其修改为包含最大宽度。想法?

private Size GetPreferredSize(String text, Font font, StringFormat format)
{

    Graphics graphics = this.CreateGraphics();

    if (format == null)
    {
        format = new StringFormat();
    }

    SizeF textSize = SizeF.Empty;

    // The minimum width allowed for the rectangle.
    double minWidth = 100;

    // The ratio for the height compared to the width.
    double heightRatio = 0.61803399; // Gloden ratio to make it look pretty :)

    // The amount to in/decrement for width.
    double step = 100;

    // The new width to be set.
    double newWidth = minWidth;

    // Find the largest width that the text fits into.
    while (true)
    {
        textSize = graphics.MeasureString(text, font, (int)Math.Round(newWidth), format);

        if (textSize.Height <= newWidth * heightRatio)
        {
            break;
        }

        newWidth += step;
    }

    step /= 2;

    // Continuously divide the step to adjust the rectangle.
    while (true)
    {

        // Ensure step.
        if (step < 1)
        {
            break;
        }

        // Ensure minimum width.
        if (newWidth - step < minWidth)
        {
            break;
        }

        // Try to subract the step from the width.
        while (true)
        {

            // Measure the text.
            textSize = graphics.MeasureString(text, font, (int)Math.Round(newWidth - step), format);

            // If the text height is going to be less than the new height, decrease the new width.
            // Otherwise, break to the next lowest step.
            if (textSize.Height < (newWidth - step) * heightRatio)
            {
                newWidth -= step;
            }
            else
            {
                break;
            }

        }

        step /= 2;
    }

    double width = newWidth;
    double height = width * heightRatio;

    return new Size((int)Math.Ceiling(width), (int)Math.Ceiling(height));
}