如何垂直或水平对齐定向文本?

Posted

技术标签:

【中文标题】如何垂直或水平对齐定向文本?【英文标题】:How to align oriented text vertically or horizontally? 【发布时间】:2016-06-22 18:05:43 【问题描述】:

我正在编写一个在画布上绘制文本的函数。该功能支持垂直和水平对齐,以及文本方向。我的问题是当文本定向时无法计算正确的对齐方式。这是标题:

procedure drawText(canvas: TCanvas; pos: TPoint; Text: string;
  FontName: TFontName; FontSize: integer; FontColor: TColor; Angle: integer;
  Halign: THorizontalAlignement; Valign: TVerticalAlignement);

Halign 可以是左、右或居中,Valign 可以是上、下或居中。

一切都适用于简单的无方向文本:

h := TextWidth(Text);
case Halign of
    haLeft: // do nothing;
    ;
    haRight: x := x - h;
    haCenter: x := x - ( h div 2 );
  end;

  v := TextHeight(Text);
  case Valign of
    vaTop:  // do nothing;
      ;
    vaBottom: y := y - v;
    vaCenter: y := y - ( v div 2 );
  end;
  Font.Orientation := Angle;
  textOut(x, y, Text );

我已经做了很多尝试来确定什么去哪里,并且我已经设法根据其对齐参数定位垂直文本,但是水平文本放错了位置。

我知道它与方向和宽度和高度有关,但我不知道如何正确处理它。

水平规则调用过程示例:

    drawText( bmp.canvas, point( x, viewOption.padding - DocumentRuleTextMargin), 
inttoStr( x ), 'arial', 8, clBLack, 0, haCenter, vaBottom ); 

调用垂直规则的程序(烦人的那个): drawText(bmp.canvas, Point(x - CDocumentRuleTextMargin, y), inttostr(y), 'arial', 8, clBlack, 900, haCenter, vaBottom);

结果如下:

我试图通过修改计算过程中 y 位置的符号来摆脱这种情况,如下所示:

 v := TextHeight(Text);
  case Valign of
    vaTop:  // do nothing;
      ;
    vaBottom: y := y + v;
    vaCenter: y := y + ( v div 2 );
  end;  

垂直规则的结果更好,而水平规则的结果最差:

【问题讨论】:

我希望您先设置角度,然后再询问尺寸。 TextExtent 为您提供这些。 使用TextRect,首先使用tfCalcRect。让 GDI 计算所需的定向宽度和高度。 是的。在查询文本大小之前或之后,我做了很多尝试关注方向,但它根本没有改变。 实际上,textRect 旨在将文本剪辑在矩形右侧,我正在寻找一种解决方案来将文本放置在我想要的位置,而不是剪辑它。我很确定 TextExtent、TextWidth 和 TextHeight 函数工作得很好,我唯一的问题是它们的行为会因方向而异,我无法猜测如何。 【参考方案1】:

好的 - 简单没用。那么,您需要做的是找到文本的中心位置,并在旋转后从那里计算“左上角”。问题是我不知道字体指向哪一点——我猜是左上角。假设是这样,那么您的功能变为:

// get centre
case Halign of
    haLeft: x1 := x + (h div 2);
    haRight: x1 := x - (h div 2);
    haCenter: x1 := x; // do nothing
  end;

  v := TextHeight(Text);
  case Valign of
    vaTop:  y1 := y + (v div 2);
    vaBottom: y1 := y - (v div 2);
    vaCenter: y1 := y; // do nothing
  end;
  Font.Orientation := Angle;
  // calculate new top left - depending on whether you are using firemonkey
  // or VCL you may need to convert to floats and/or use Cosint
  // x := x1 - (w/2)*CosD(Angle) - (h/2)*SinD(Angle);
  x := x1 - ((w * CosInt(Angle * 10)) - (h*SinInt(Angle*10)) div 2000);
  //y := y1 - (w/2)*SinD(Angle) + (h/2)*CosD(Angle);
  y := y1 - ((w * SinInt(Angle * 10)) - (h*CosInt(Angle*10)) div 2000);
  textOut(x, y, Text );

由于您在代码中使用 Div,我猜您正在使用 VCL。

我建议您查找 SinInt 以了解其中的乘法和除法。 cmets 显示了您将在 Firemonkey 中使用的浮点版本。

我没有测试过这段代码——我只是想展示一下数学。你需要自己微调。

【讨论】:

【参考方案2】:

我认为你的情况的垂直规则应该是

drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y ), inttostr( y ), 'arial', 8, clBlack, 900, haCenter, vaCenter);

因为您正在尝试与复选标记对齐,并且它们需要居中。更改您的算法按预期移动了垂直位置,因此看起来您的原始算法是正确的 - 只是您的应用程序是错误的。

【讨论】:

其实alignements参数的计算没有很好的计算,所以改成vaCenter并不能解决我的问题。这就是重点:当文本是垂直或水平时,我正在寻找正确的计算方法【参考方案3】:

问题是旋转文本时宽度和高度不会改变。

当使用 90° 旋转时,返回 textHeight 函数的是实际(可见)宽度。表示可见高度的 textWidth 也是如此。

在这种情况下,不可能使用与水平文本相同的公式将旋转 90° 的文本垂直居中和水平居中(即:将宽度的一半减去 x 位置会导致位移过大)。

由于我只管理垂直和水平文本,我将通过测试方向属性来使用解决方法。当 900 时,我切换 textHeight 和 textwidth 结果来计算文本的对齐位置。

【讨论】:

以上是关于如何垂直或水平对齐定向文本?的主要内容,如果未能解决你的问题,请参考以下文章

将多个 div 对齐一行并将文本垂直和水平居中

如何在love2D中垂直和水平居中对齐文本?

如何左对齐和垂直对齐标题中的图像并将文本水平保持在div的中心[重复]

pyqt5 tabwidget 垂直制表符 水平文本左对齐

RichEdit 垂直文本对齐

css基础文本对齐,水平对齐,垂直对齐