Това не работи на CentOS4, която е в края на живота си и има стара RPM версия. За съжаление това е, с което OP и вашият наистина се опитват да работят. Макар и далеч, това е най-близкото до решение.

person Christo    schedule 14.08.2013    source източник
comment
Има ли някаква добра причина да не използвате TLabel върху TImage? Можете да завъртите TLabel и да подравните текста, както желаете. Това решение беше добро във VCL, но във FMX всеки компонент може да бъде контейнер на друг компонент.   -  person AvgustinTomsic    schedule 14.08.2013
comment
Трябва да рисувам директно върху платното. Разработвам CAD програма, която използва векторна графика, така че понякога има голямо количество текст, който трябва да бъде начертан, следователно етикетът няма да отговаря на целта ми.   -  person Christo    schedule 15.08.2013


Отговори (3)


Предполагам, че това е така, защото текстът ще се върти около горната лява позиция на правоъгълника

Не, ротацията е центрирана около текущия произход на платното. По подразбиране това е координата 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;

Актуализация:

Този код все още не отчита вече изместен произход.

В отговор на вашия коментар, следният код изчертава текст от координата 50, 100 надолу, завъртян на 90° около тази точка, използвайки метода, обяснен по-горе, върху PaintBox, който е произволно позициониран във формуляра.

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;
person NGLN    schedule 06.10.2013
comment
Първо, каква е разликата между координатите 0,0 на текущото платно и TopLeft на правоъгълника? Тогава какво трябва да направя, ако не знам дължината на текста? - person Christo; 07.10.2013
comment
Горният ляв ъгъл на правоъгълник може да бъде всичко, нали? Е, в горния пример ширината на текста не е важна, но можете да я получите с Canvas.TextWidth. Какво искаш да правиш? - person NGLN; 07.10.2013
comment
Искам да мога да въртя всеки даден текст във всяка точка около горната дясна точка на платното. Пример: Имам текст „здравей свят“, който започва от точка 50;100. И искате да завъртите текста на 90 градуса в долния десен ъгъл на текста (това е 90 градуса около „d“). - person Christo; 07.10.2013

 procedure TmsLineWithArrow.DoDrawTo(const aCanvas: TCanvas;
  const aOrigin: TPointF);
var
 l_Proxy : TmsShape;
 l_OriginalMatrix: TMatrix;
 l_Matrix: TMatrix;
 l_Angle : Single;
 l_CenterPoint : TPointF;

 l_TextRect : TRectF;
begin
 inherited;

 aCanvas.BeginScene;  

 if (StartPoint <> FinishPoint) then
 begin
  l_OriginalMatrix := aCanvas.Matrix;
  try
   l_Proxy := TmsSmallTriangle.Create(FinishPoint);
   try
    // in Radian
    l_Angle := GetArrowAngleRotation;

    // create a point around which will rotate
    l_CenterPoint := TPointF.Create(FinishPoint.X, FinishPoint.Y);

    l_Matrix := l_OriginalMatrix;
    l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y);
    l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle);
    l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y);

    aCanvas.SetMatrix(l_Matrix);

    l_Proxy.DrawTo(aCanvas, aOrigin);
   finally
    FreeAndNil(l_Proxy);
   end;//try..finally
  finally
    aCanvas.SetMatrix(l_OriginalMatrix);
    aCanvas.EndScene;
  end;
 end;//(StartPoint <> FinishPoint)
end;

Този код работи в приложението XE5 Firemonkey. всички източници тук https://bitbucket.org/ingword/mindstream

person Ingword    schedule 30.07.2014
comment
И все пак, как мога да уточня, че искам да завъртя долу вляво, горе вляво, централно, долу вдясно или горе вдясно на текста. В източника, който предоставихте, не виждам никакъв текст? - person Christo; 31.07.2014

За хората, които се интересуват, тук ще намерите версията на C++Builder, която използвам за FMX (тествана на 10.2 / Токио):

функция:

// Начертайте завъртян текст върху pMainBitmap ; Rot = трябва да е кратно на 90°!

void DrawRotatedText(TBitmap * pMainBitmap, TRectF TextDestRect, String StrTxt, int Rot)

(разбира се, добавете "{" и "}" между следния код... винаги грешка с редактора, за да публикувате този отговор...)

int SizeTextW = pMainBitmap->Canvas->TextWidth( StrTxt );
int SizeTextH = pMainBitmap->Canvas->TextHeight( StrTxt );
int SizeTextMax = (SizeTextW>SizeTextH)?SizeTextW:SizeTextH;
TRectF TheTextRect;
TheTextRect.init( 0, 0, SizeTextMax, SizeTextMax );

TBitmap * pBitmapText = new TBitmap( SizeTextMax, SizeTextMax );
if ( pBitmapText )
{
    /* background color used */
    pBitmapText->Clear( claBlack );

    pBitmapText->Canvas->BeginScene();
    // use same color than main bitmap for text
    pBitmapText->Canvas->Fill->Color = pMainBitmap->Canvas->Fill->Color;
    pBitmapText->Canvas->FillText(TheTextRect, StrTxt, false, 100,
        TFillTextFlags()/* << TFillTextFlag::RightToLeft*/, TTextAlign::Center,
        TTextAlign::Center);
    pBitmapText->Canvas->EndScene();
    // Canvas->EndScene must be done before doing bitmap rotate/flip...!
    if( Rot==180 )
        pBitmapText->FlipVertical( );
    else if ( Rot!=0 )
        pBitmapText->Rotate( Rot );

    int PosSrcX = 0;
    int PosSrcY = 0;
    if ( SizeTextW>SizeTextH )
        PosSrcX = (SizeTextMax-SizeTextH)/2;
    else
        PosSrcY = (SizeTextMax-SizeTextW)/2;
    TheTextRect.init( PosSrcX, PosSrcY, PosSrcX+SizeTextH, PosSrcY+SizeTextW );
    int iPosDestX = TextDestRect.left;
    int iPosDestY = TextDestRect.top;
    if ( (TextDestRect.right-TextDestRect.left)>SizeTextH )
        iPosDestX = iPosDestX+(TextDestRect.right-TextDestRect.left-SizeTextH)/2;
    if ( (TextDestRect.bottom-TextDestRect.top)>SizeTextW )
        iPosDestY = iPosDestY + (TextDestRect.bottom-TextDestRect.top-SizeTextW)/2;
    TextDestRect.left = iPosDestX;
    TextDestRect.top = iPosDestY;
    TextDestRect.right = TextDestRect.left+SizeTextH;
    TextDestRect.bottom = TextDestRect.top+SizeTextW;
    pMainBitmap->Canvas->DrawBitmap( pBitmapText, TheTextRect, TextDestRect, 100, true );

    delete( pBitmapText );
}
person Mavati    schedule 07.03.2018