在面板中查找文本的高度

时间:2010-06-11 17:41:58

标签: c# visual-studio-2008 compact-framework

我有自定义的面板。我用它来显示文字。但有时文本太长并且包含在下一行。有什么方法可以自动调整面板大小以显示所有文本吗?

我正在使用C#和Visual Studio 2008以及紧凑的框架。


以下是我想要调整大小的代码:
(注意:HintBox是我自己的继承自面板的类。所以我可以根据需要修改它。

public void DataItemClicked(ShipmentData shipmentData)
{
    // Setup the HintBox
    if (_dataItemHintBox == null)
        _dataItemHintBox = HintBox.GetHintBox(ShipmentForm.AsAnObjectThatCanOwn(),
                                             _dataShipSelectedPoint,
                                             new Size(135, 50), shipmentData.LongDesc,
                                             Color.LightSteelBlue);


    _dataItemHintBox.Location = new Point(_dataShipSelectedPoint.X - 100,
                                          _dataShipSelectedPoint.Y - 50);
    _dataItemHintBox.MessageText = shipmentData.LongDesc;
    // It would be nice to set the size right here
    _dataItemHintBox.Size = _dataItemHintBox.MethodToResizeTheHeightToShowTheWholeString()
    _dataItemHintBox.Show();

}

我将给出Will Marcouiller的答案,因为他的代码示例最接近我的需要(看起来它会起作用)。但是,这是我认为我将使用的:

public static class CFMeasureString
{
    private struct Rect
    {
        public readonly int Left, Top, Right, Bottom;
        public Rect(Rectangle r)
        {
            this.Left = r.Left;
            this.Top = r.Top;
            this.Bottom = r.Bottom;
            this.Right = r.Right;
        }
    }

    [DllImport("coredll.dll")]
    static extern int DrawText(IntPtr hdc, string lpStr, int nCount, 
                               ref Rect lpRect, int wFormat);
    private const int DT_CALCRECT = 0x00000400;
    private const int DT_WORDBREAK = 0x00000010;
    private const int DT_EDITCONTROL = 0x00002000;

    static public Size MeasureString(this Graphics gr, string text, Rectangle rect, 
                                     bool textboxControl)
    {
        Rect bounds = new Rect(rect);
        IntPtr hdc = gr.GetHdc();
        int flags = DT_CALCRECT | DT_WORDBREAK;
        if (textboxControl) flags |= DT_EDITCONTROL;
        DrawText(hdc, text, text.Length, ref bounds, flags);
        gr.ReleaseHdc(hdc);
        return new Size(bounds.Right - bounds.Left, bounds.Bottom - bounds.Top + 
                        (textboxControl ? 6 : 0));
    }
}

这使用os级别调用来绘制文本。通过P-Invoking它我可以得到我需要的功能(多线包装)。请注意,此方法不包含任何边距。只是文本占用的实际空间。

我没有写这段代码。我是从http://www.mobilepractices.com/2007/12/multi-line-graphicsmeasurestring.html得到的。那个博文有我的确切问题和这个修复。 (虽然我做了一个小调整,使其成为一种扩展方法。)

2 个答案:

答案 0 :(得分:4)

您可以使用Graphics.MeasureString()方法。

如果您的文本分配的代码示例在您的面板上,我可以使用MeasureString()方法提供代码示例,如果您需要它。

我无法知道Graphics.MeasureString()方法是否是Compact Framework的一部分,因为在我链接的页面上没有说明。

编辑#1

Here's a link我在那里回答了另一个与文字大小相关的问题,而我正在为你写一个样本。 =)

编辑#2

Here's another link related你的问题。 (下一个编辑是示例代码。= P)

编辑#3

public void DataItemClicked(ShipmentData shipmentData) { 
    // Setup the HintBox 
    if (_dataItemHintBox == null) 
        _dataItemHintBox = HintBox.GetHintBox(ShipmentForm.AsAnObjectThatCanOwn(), 
                                             _dataShipSelectedPoint, 
                                             new Size(135, 50), shipmentData.LongDesc, 
                                             Color.LightSteelBlue); 

    // Beginning to measure the size of the string shipmentData.LongDesc here.

    // Assuming that the initial font size should be 30pt.
    Single fontSize = 30.0F;
    Font f = new Font("fontFamily", fontSize, FontStyle.Regular);

    // The Panel.CreateGraphics method provides the instance of Graphics object 
    // that shall be used to compare the string size against.
    using (Graphics g = _dataItemHintBox.CreateGraphics()) {
        while (g.MeasureString(shipmentData.LongDesc, f).Width > _dataItemHintBox.Size.Width - 5) {
            --fontSize;
            f = new Font("fontFamily", fontSize, FontStyle.Regular);
        }
    }

    // Font property inherited from Panel control.
    _dataItemHintBox.Font = f;

    // End of font resizing to fit the HintBox panel.

    _dataItemHintBox.Location = new Point(_dataShipSelectedPoint.X - 100, 
                                          _dataShipSelectedPoint.Y - 50); 
    _dataItemHintBox.MessageText = shipmentData.LongDesc; 
    // It would be nice to set the size right here 
    _dataItemHintBox.Size = _dataItemHintBox.MethodToResizeTheHeightToShowTheWholeString() 
    _dataItemHintBox.Show(); 
} 

免责声明: 此代码尚未经过测试,并且不在我的掌控之列。为了测试它,可能必须进行一些更改。这为实现您似乎想要实现的目标提供了指导。可能有更好的方法来做到这一点,但我知道这个有效。嗯,算法可以正常工作,你可以在我的其他答案中看到。

而不是行:

SizeF fontSize = 30.0F;

您还可以执行以下操作:

var fontSize = _dataItemHintBox.Font.Size;
  

为什么会这样?

因为Font.Size属性只读。因此,每次Font.Size发生变化时,您都需要创建System.Drawing.Font类的新实例。

在你的比较中,而不是有一行:

while (g.MeasureString(shipmentData.LongDesc, f)...)

你也可以:

while (g.MeasureString(shipmentData.LongDesc, _dataItemHintBox.Font)...)

这将无需第二个Font类实例,即 f

请随时发布反馈,因为我可以根据收到的反馈更改我的样本以适应您的实际情况,以便更好地帮助您。 =)

我希望这有帮助! =)

答案 1 :(得分:2)

您可以使用适合您的TextRenderer.MeasureText重载中的任何一个。使用此功能,您可以确定字符串的实际渲染大小,并相应地调整面板的大小。

如果您尝试在Paint事件中进行衡量,那么您可以使用MeasureString对象上的e.Graphics函数,但在Paint内调整大小是不明智的。使用TextRenderer可以避免您必须使用Graphics创建CreateGraphics()对象,并在完成后将其丢弃。

修改

由于紧凑框架不支持TextRenderer(我第一次看到问题时错过了标记),您必须在Graphics对象上使用MeasureString()函数。像这样:

public Size GetStringSize(string text)
{
    using(Graphics g = yourPanel.CreateGraphics())
    {
        return g.MeasureString(text, yourPanel.Font);
    }
}