我想在 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
以供引用。但还有很多其他方法。
这里是如何在表单中从左下角到右上角绘制文本的示例:
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/