在系统标签上精确放置文本的图形DrawString

5

我在VS2008中重写了Label控件的OnPaint方法:

void Label_OnPaint(object sender, PaintEventArgs e) {
  base.OnPaint(e);
  dim lbl = sender as Label;
  if (lbl != null) {
    string Text = lbl.Text;
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    if (myShowShadow) { // draw the shadow first!
      e.Graphics.DrawString(Text, lbl.Font, new SolidBrush(myShadowColor), myShadowOffset, StringFormat.GenericDefault);
    }
    e.Graphics.DrawString(Text, lbl.Font, new SolidBrush(lbl.ForeColor), 0, 0, StringFormat.GenericDefault);
  }
}

这个方法可以实现,但我真的想知道如何在垂直和水平方向上都居中文本。我听说过 MeasureString() 方法,但我的“Text”会包含分页符,这使问题更加复杂。
有人能指导我如何做到这一点吗?
4个回答

9

或者您可以创建自己的StringFormat对象,并使用支持RectangleFDrawString重载将其传递:

StringFormat formatter = new StringFormat();
formatter.LineAlignment = StringAlignment.Center;
formatter.Alignment = StringAlignment.Center;

RectangleF rectangle = new RectangleF(0, 0, lbl.Width, lbl.Height);

e.Graphics.DrawString(Text, lbl.Font, new SolidBrush(lbl.ForeColor), rectangle, formatter);

两个都是答案,但我只能标记一个。这一个有代码可以供其他人跟进。 - user153923

3

您可以使用 TextRenderer.DrawText 方法,并添加 HorizontalCenterVerticalCenter 标志来进行调用。


1
你还需要使用接受 Rectangle 参数的重载函数。 - Aaronaught
TrueType字形微调可能会破坏阴影效果。 - Hans Passant
@SLaks:我该如何获取 System.Label 对象的 DeviceContext(第一个参数)? - user153923
2
e.GraphicsPaint 事件处理程序传递。(Graphics 实现了 IDeviceContext - SLaks

2

这是我目前正在使用的代码:

SizeF size;
string text = "Text goes here";
size = e.Graphics.MeasureString(text, font);
x = (lineWidth / 2) - (size.Width / 2);
y = top;
e.Graphics.DrawString(text, font, Brushes.Black, x, y);

1
我只是想在一年后添加一个我创建的工具,因为StringAlignment被证明不是非常可靠。它与Neo的版本非常相似。
下面的代码非常出色地实现了文本的垂直和水平居中。此外,我编写了各种重载,以便可以提供不同的选项,使此控件的行为完全符合我的要求。
以下是我的重载:
private static void DrawCenter(Label label, Graphics graphics) {
  DrawCenter(label.Text, label, label.Location, label.ForeColor, graphics);
}

private void DrawCenter(string text, Label label, Graphics graphics) {
  DrawCenter(text, label, label.Location, label.ForeColor, graphics);
}

private static void DrawCenter(string text, Label label, Point location, Graphics graphics) {
  DrawCenter(text, label, location, label.ForeColor, graphics);
}

private static void DrawCenter(string text, Label label, Point location, Color fontColor, Graphics graphics) {
  Rectangle rect = new Rectangle(location, label.Size);
  SizeF lSize = graphics.MeasureString(text, label.Font, rect.Width);
  PointF lPoint = new PointF(rect.X + (rect.Width - lSize.Width) / 2, rect.Y + (rect.Height - lSize.Height) / 2);
  graphics.DrawString(text, label.Font, new SolidBrush(fontColor), lPoint);
}

要在标签的OnPaint事件中使用这些,请简单修改我在问题中提供的原始代码如下:

private void Label_OnPaint(object sender, PaintEventArgs e) {
  base.OnPaint(e);
  Label lbl = sender as Label;
  if (lbl != null) {
    string txt = lbl.Text;
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    if (myShowShadow) { // draw the shadow first!
      Point offset = new Point(lbl.Location.X - 1, lbl.Location.Y - 1)
      DrawCenter(txt, lbl, offset, myShadowColor, e.Graphics);
    }
    DrawCenter(lbl, e.Graphics);
  }
}

对于一个Print_Document事件,我有一个版本,如果在设计师中已经有一个框围绕标签,则还会打印一个框围绕它:

private static void DrawCenter(string text, Label label, Point location, Color fontColor, Graphics graphics) {
  Rectangle rect = new Rectangle(location, label.Size);
  SizeF lSize = graphics.MeasureString(text, label.Font, rect.Width);
  PointF lPoint = new PointF((rect.Width - lSize.Width) / 2, (rect.Height - lSize.Height) / 2);
  graphics.DrawString(text, label.Font, new SolidBrush(fontColor), lPoint);
  if (label.BorderStyle != BorderStyle.None) {
    using (Pen p = new Pen(Color.Black)) {
      graphics.DrawRectangle(p, rect);
    }
  }
}

如果您觉得这个有用,请点个赞。
~乔

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接