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

时间:2016-03-08 16:59:15

标签: delphi gdi textout

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

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 ); 

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

结果如下:

Example 1

我试图通过修改程序的y位置计算中的符号来解决这个问题:

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

并且结果对于垂直规则更好,而对于水平规则则更差:

example 2

3 个答案:

答案 0 :(得分: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来解释这里的乘法和除法。注释显示您将在Firemonkey中使用的浮点版本。

我没有测试过这段代码 - 我只是想展示数学。你需要自我调整。

答案 1 :(得分:0)

我认为您案例中的纵向规则应该是

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

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

答案 2 :(得分:0)

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

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

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

由于我只管理纵向和横向文本,因此我将通过测试orientation属性来使用解决方法。当900然后我切换textHeight和textwidth结果来计算文本的对齐位置。