delphi - Firemonkey 旋转文本

标签 delphi firemonkey delphi-xe4 firemonkey-fm3

我想在 Canvas 上绘制文本。为了进行旋转,我使用了 https://forums.embarcadero.com/thread.jspa?messageID=440010 中的以下代码

//bm is a TImage    
a := 45;
c:= bm.Canvas;
CurrentM := c.Matrix;
a:=-radian(a);
m.m11:= cos(a); m.m12:=sin(a); m.m13:=0;
m.m21:=-sin(a); m.m22:=cos(a); m.m23:=0;
m.m31:=0;       m.m32:=0;      m.m33:=1;
c.setmatrix(M);

c.BeginScene;
    c.filltext(rectf(100,100,5000,5000), 'test rotated string', false,1,[],ttextalign.taLeading,ttextalign.taLeading);
c.EndScene;

这很好用。我已将矩形的右侧和底部设置为 5000,这样我就不必担心矩形太小。

问题是我现在想要更改我的 TextAlignment 属性。因此,要从右向左绘制文本,我必须调整矩形,然后按以下方式绘制它:

c.BeginScene;
    c.filltext(rectf((100 - 5000),100,100,5000), 'test rotated string', false,1,[],ttextalign.taTrailing,ttextalign.taLeading);
c.EndScene;

所以基本上我移动了矩形左上角的 x 值并将其移回 5000(我再次使用 5000 来确保我的文本适合)。然后,我将矩形右下角的 x 值设置为上一个示例矩形左上角的 x 值。 这对于 0 度旋转来说效果很好,但是一旦我改变了度数,我就不会在正确的位置绘制文本。我认为这是因为文本将围绕矩形的左上角位置旋转(该位置被更改以使文本从右向左书写)。

最佳答案

I assume this is because the text will rotate around the rectangle's TopLeft position

不,旋转以 Canvas 的当前原点为中心。默认情况下,该坐标为 0, 0,但可以通过当前设置的变形矩阵进行更改。典型的方法是:选择一个旋转中心,将原点移动到该中心,旋转,移回更改后的原点,然后绘制。请参阅TControl.MatrixChanged以供引用。但还有很多其他方法。

这里是如何在表单中从左下角到右上角绘制文本的示例:

enter image description here

procedure TForm1.FormPaint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
var
  Angle: Single;
  R: TRectF;
  S: String;
  H: Single;
  Matrix: TMatrix;
begin
  Canvas.Fill.Color := TAlphaColors.Black;
  Angle := -ArcTan2(ClientHeight, ClientWidth);
  R := ClientRect;
  S := 'Text from bottom-left...';
  H := Canvas.TextHeight(S);
  Matrix := CreateRotationMatrix(Angle);
  Matrix.m31 := Sin(Angle) * (ClientHeight - H);
  Matrix.m32 := ClientHeight  * (1 - Cos(Angle));
  Canvas.SetMatrix(Matrix);
  Canvas.FillText(R, S, False, 1, [], TTextAlign.taLeading,
    TTextAlign.taTrailing);
  S := '...to top-right';
  Matrix.m31 := ClientWidth * (1 - Cos(Angle)) + Sin(Angle) * H;
  Matrix.m32 := -Sin(Angle) * ClientWidth;
  Canvas.SetMatrix(Matrix);
  Canvas.FillText(R, S, False, 1, [], TTextAlign.taTrailing,
    TTextAlign.taLeading);
end;

更新:

此代码尚未考虑已转移的原点。

为了回应您的评论,以下代码使用上面解释的方法,在任意位于表格。

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
const
  S = 'Hello World';
var
  R: TRectF;
  OriginalMatrix: TMatrix;
  ShiftMatrix: TMatrix;
  RotationMatrix: TMatrix;
  ShiftBackMatrix: TMatrix;
  Matrix: TMatrix;
begin
  PaintBox1.Canvas.Fill.Color := TAlphaColors.Black;
  R.Right := 50;
  R.Bottom := 100;
  R.Left := R.Right - 5000;
  R.Top := R.Bottom - 5000;
  OriginalMatrix := PaintBox1.Canvas.Matrix;
  ShiftMatrix := IdentityMatrix;
  ShiftMatrix.m31 := -R.Right;
  ShiftMatrix.m32 := -R.Bottom;
  RotationMatrix := CreateRotationMatrix(DegToRad(-90));
  ShiftBackMatrix := IdentityMatrix;
  ShiftBackMatrix.m31 := R.Right;
  ShiftBackMatrix.m32 := R.Bottom;
  Matrix := MatrixMultiply(RotationMatrix, ShiftBackMatrix);
  Matrix := MatrixMultiply(ShiftMatrix, Matrix);
  Matrix := MatrixMultiply(Matrix, OriginalMatrix);
  PaintBox1.Canvas.SetMatrix(Matrix);
  PaintBox1.Canvas.FillText(R, S, False, 1, [], TTextAlign.taTrailing,
    TTextAlign.taTrailing);
  PaintBox1.Canvas.SetMatrix(OriginalMatrix);
end;

可以简化为:

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
const
  S = 'Hello World';
var
  R: TRectF;
  SaveMatrix: TMatrix;
  Matrix: TMatrix;
begin
  PaintBox1.Canvas.Fill.Color := TAlphaColors.Black;
  R := RectF(-Canvas.TextWidth(S), -Canvas.TextHeight(S), 0, 0);
  SaveMatrix := PaintBox1.Canvas.Matrix;
  Matrix := CreateRotationMatrix(DegToRad(-90));
  Matrix.m31 := 50;
  Matrix.m32 := 100;
  PaintBox1.Canvas.MultyMatrix(Matrix);
  PaintBox1.Canvas.FillText(R, S, False, 1, [], TTextAlign.taTrailing,
    TTextAlign.taTrailing);
  PaintBox1.Canvas.SetMatrix(SaveMatrix);
end;

这又演变成这个一般例程:

procedure DrawRotatedText(Canvas: TCanvas; const P: TPointF; RadAngle: Single;
  const S: String; HTextAlign, VTextAlign: TTextAlign);
var
  W: Single;
  H: Single;
  R: TRectF;
  SaveMatrix: TMatrix;
  Matrix: TMatrix;
begin
  W := Canvas.TextWidth(S);
  H := Canvas.TextHeight(S);
  case HTextAlign of
    TTextAlign.taCenter:   R.Left := -W / 2;
    TTextAlign.taLeading:  R.Left := 0;
    TTextAlign.taTrailing: R.Left := -W;
  end;
  R.Width := W;
  case VTextAlign of
    TTextAlign.taCenter:   R.Top := -H / 2;
    TTextAlign.taLeading:  R.Top := 0;
    TTextAlign.taTrailing: R.Top := -H;
  end;
  R.Height := H;
  SaveMatrix := Canvas.Matrix;
  Matrix := CreateRotationMatrix(RadAngle);
  Matrix.m31 := P.X;
  Matrix.m32 := P.Y;
  Canvas.MultyMatrix(Matrix);
  Canvas.FillText(R, S, False, 1, [], HTextAlign, VTextAlign);
  Canvas.SetMatrix(SaveMatrix);
end;

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  PaintBox1.Canvas.Fill.Color := TAlphaColors.Black;
  DrawRotatedText(PaintBox1.Canvas, PointF(50, 100), DegToRad(-90),
    'Hello world', TTextAlign.taTrailing, TTextAlign.taTrailing);
end;

关于delphi - Firemonkey 旋转文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18229549/

相关文章:

Delphi 按钮 - 设计时和运行时的不同外观

android - 在 Delphi 中与 Mifare DESFire 通信

ios - 我们如何在 Delphi iOS 中使用 Open SSL?

ios - 如何在 Delphi 中使用 Indy HTTP Server 来接收 iOS 应用程序中的连接?

delphi - Delphi 中的 Indy HTTPS POST 请求使用 TLS 1.0 而不是 TLS 1.2

delphi - 将长按事件添加到按钮类的最佳方法是什么?

delphi - Delphi命令行编译器

android - FireMonkey 绘制模糊线条

Delphi - 定位编译器无法在其默认路径中搜索的单元的路径

ios - Delphi xe4-如何通过HTTP访问Foursquare API