如何垂直或水平对齐定向文本?
How to align oriented text vertically or horizontally?
我正在编写一个在 canvas 上绘制文本的函数。该功能支持垂直和水平对齐,以及文本方向。我的问题是在文本定向时无法计算正确的对齐方式。这是 header:
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;
并且垂直规则的结果更好,而水平规则的结果最差:
我认为你的垂直规则应该是
drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y ), inttostr( y ), 'arial', 8, clBlack, 900, haCenter, vaCenter);
因为您正试图对齐复选标记,它们需要居中。更改您的算法会按预期移动垂直位置,因此看起来您的原始算法是正确的 - 只是您对它的应用是错误的。
问题是旋转文本时宽度和高度没有改变。
当使用 90° 旋转时,returns textHeight 函数是实际(可见)宽度。表示可见高度的 textWidth 也是如此。
在这种情况下,无法使用与水平文本相同的公式将垂直和水平旋转 90° 的文本居中(即:将宽度的一半减去 x 位置会导致位移过大).
由于我只管理垂直和水平文本,我将通过测试方向来使用解决方法 属性。当 900 然后我切换 textHeight 和 textwidth 结果来计算文本的对齐位置。
好的 - 简单的没用。然后,您需要做的是找到文本的中心位置,并在旋转后从那里计算 'Top left'。问题是我不知道字体围绕哪个点定位——我猜是左上角。假设如此,那么您的函数变为:
// 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 中使用的浮点版本。
我没有测试过这段代码 - 我只是想展示数学。你需要对自己进行微调。
我正在编写一个在 canvas 上绘制文本的函数。该功能支持垂直和水平对齐,以及文本方向。我的问题是在文本定向时无法计算正确的对齐方式。这是 header:
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;
并且垂直规则的结果更好,而水平规则的结果最差:
我认为你的垂直规则应该是
drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y ), inttostr( y ), 'arial', 8, clBlack, 900, haCenter, vaCenter);
因为您正试图对齐复选标记,它们需要居中。更改您的算法会按预期移动垂直位置,因此看起来您的原始算法是正确的 - 只是您对它的应用是错误的。
问题是旋转文本时宽度和高度没有改变。
当使用 90° 旋转时,returns textHeight 函数是实际(可见)宽度。表示可见高度的 textWidth 也是如此。
在这种情况下,无法使用与水平文本相同的公式将垂直和水平旋转 90° 的文本居中(即:将宽度的一半减去 x 位置会导致位移过大).
由于我只管理垂直和水平文本,我将通过测试方向来使用解决方法 属性。当 900 然后我切换 textHeight 和 textwidth 结果来计算文本的对齐位置。
好的 - 简单的没用。然后,您需要做的是找到文本的中心位置,并在旋转后从那里计算 'Top left'。问题是我不知道字体围绕哪个点定位——我猜是左上角。假设如此,那么您的函数变为:
// 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 中使用的浮点版本。
我没有测试过这段代码 - 我只是想展示数学。你需要对自己进行微调。