Recent

Author Topic: Painting text  (Read 3479 times)

SaraT

  • Full Member
  • ***
  • Posts: 131
  • A little student
Painting text
« on: April 11, 2024, 06:14:03 pm »
Hello coders
I would like to paint text with word wrap like the attached image,
rounded rect, background and border color.

How can I do this on a PaintBox control? Or please give a better idea.
Thanks a lot.
« Last Edit: May 17, 2024, 02:54:51 pm by SaraT »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Painting text
« Reply #1 on: April 11, 2024, 06:46:08 pm »
I would create a TBitmap on the fly,
WordWrap I would realize by calculating via "theBitmap.Canvas.TextWidth(AText)"
and to know where the new line starts use "theBitmap.Canvas.TextHeight(AText)"
do not forget to add some space between words, borders, new line etc...
Rounded corners are more challenging due the fact that an image is a 2D rectangle,
anyway you could start experimenting with "theBitmap.Canvas.LineTo()" to draw "from x to y" a line for all borders with a hole/space between.
One thing you should have in mind about the round corners, they are visible as a rectangle (eg background color from bitmap is visible)
When the bitmap is prepared, assign it to the control you need it.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

SaraT

  • Full Member
  • ***
  • Posts: 131
  • A little student
Re: Painting text
« Reply #2 on: April 11, 2024, 07:31:51 pm »
I would create a TBitmap on the fly...

Thanks for the information, but I posted in the forum because I have no idea of how
to paint anything on PaintBox control / canvas. So please, if anybody has a working code
and share with us, I would be so thankful.

Regards!

paweld

  • Hero Member
  • *****
  • Posts: 1278
Re: Painting text
« Reply #3 on: April 11, 2024, 07:52:30 pm »
Best regards / Pozdrawiam
paweld

TRon

  • Hero Member
  • *****
  • Posts: 3778
Re: Painting text
« Reply #4 on: April 11, 2024, 07:54:48 pm »
TextRect can be used to wrap text automatically.

See also developing with graphics for information on graphics and besides that there are plenty enough examples distributed with Lazarus.
I do not have to remember anything anymore thanks to total-recall.

Handoko

  • Hero Member
  • *****
  • Posts: 5382
  • My goal: build my own game engine using Lazarus
Re: Painting text
« Reply #5 on: April 11, 2024, 08:49:27 pm »
Draw the rounded corners
That's easy. I done it, OpenGL version. KodeZwerg already explained the basic. But forget to mention, you need have good understanding in trigonometry, to calculate the X-Y positions. The easier solution is, use TCanvas.Arc command:
https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tcanvas.arc.html

Word-wrapping the text
Just as TRon said, TextRect has word wrap feature:
https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tcanvas.textrect.html
Alternatively, we can use TextWidth and TextHeight and do the calculation manually, just as KodeZwerg said.

Draw the dash lines
You just need to set the Canvas.Pen.Style:
https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tpen.style.html


The problem is when all them need to be done together, that will be not so easy.
« Last Edit: April 11, 2024, 08:57:36 pm by Handoko »

TRon

  • Hero Member
  • *****
  • Posts: 3778
Re: Painting text
« Reply #6 on: April 11, 2024, 09:05:22 pm »
Draw the rounded corners
That's easy. I done it, OpenGL version. KodeZwerg already explained the basic. But forget to mention, you need have good understanding in trigonometry, to calculate the X-Y positions. The easier solution is, use TCanvas.Arc command:
https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tcanvas.arc.html
Alternatively you could use RoundRect

Quote
The problem is when all them need to be done together, that will be not so easy.
Not too difficult either  :)

3 canvas calls in onpaint event should be able to do it (I could be a couple of calls off because of setting the correct penstyle/brush/font).
I do not have to remember anything anymore thanks to total-recall.

Handoko

  • Hero Member
  • *****
  • Posts: 5382
  • My goal: build my own game engine using Lazarus
Re: Painting text
« Reply #7 on: April 11, 2024, 09:20:12 pm »
You're right. It is easier than I thought.  :D

Done:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Canvas.Pen.Style   := psDash;
  4.   Canvas.Pen.Width   := 3;
  5.   Canvas.Pen.Color   := clGreen;
  6.   Canvas.Brush.Color := clYellow;
  7.   Canvas.RoundRect(50, 50 , 250, 150, 50, 50);
  8. end;

For the word wrapping part, I will let others to do it. It is midnight here, I am going to sleep now.

Good night and have fun!

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Painting text
« Reply #8 on: April 11, 2024, 09:42:59 pm »
Thanks for the information, but I posted in the forum because I have no idea of how
to paint anything on PaintBox control / canvas.
You are welcomed, it sounded a bit bit different in your first post.
I am no magician that knows your skills.
Or please give a better idea.
I was replying to that statement.

Since others showed how to do the roundings ....
here is my way about how to wordwrap and put text on a paintbox control, with easy adjustments you can use it wherever.
Code: Pascal  [Select][+][-]
  1. procedure WordWrappedImage(var APaintBox: TPaintBox; const AFont: TFont; const AText: AnsiString; const ABackground: TColor);
  2. var
  3.   bmp: TBitmap;
  4.   sa: TStringArray;
  5.   s: string;
  6.   i: Integer;
  7.   PosY, Padding: Integer;
  8. begin
  9.   // create a bitmap on the fly
  10.   bmp := TBitmap.Create;
  11.   try
  12.     // set size to paintbox
  13.     bmp.SetSize(APaintBox.Width, APaintBox.Height);
  14.     // set background color
  15.     bmp.Canvas.Brush.Color := ABackground;
  16.     // fill image with color
  17.     bmp.Canvas.FillRect(bmp.Canvas.ClipRect);
  18.     // set font, including color and any set style(s)
  19.     bmp.Canvas.Font := AFont;
  20.  
  21.     // space that stay free around text
  22.     Padding := 5;
  23.     // vertical counter
  24.     PosY := Padding;
  25.     // temporal string
  26.     s := '';
  27.     // convert the text to an array of words by splitting them at spaces or lineendings
  28.     sa := AText.Split([' ', #10, #13]);
  29.     // draw text wordwrapped on image
  30.     // this method fails if a word is bigger than the image got space
  31.     for i := Low(sa) to High(sa) do
  32.       begin
  33.         // assign some word to draw for a new line
  34.         if s = '' then
  35.           s := sa[i]
  36.         else
  37.           // or begin testing if the collection of words are fitting into the image
  38.           begin
  39.             // add more words to current line
  40.             if (bmp.Canvas.TextWidth(s + ' ' + sa[i]) < (bmp.Width - Padding)) then
  41.               s := s + ' ' + sa[i]
  42.             else
  43.               begin
  44.                 // draw current line
  45.                 bmp.Canvas.TextOut(Padding, PosY, s);
  46.                 Inc(PosY, bmp.Canvas.TextHeight(s));
  47.                 // check if we are in bounds of image
  48.                 if ((PosY + bmp.Canvas.TextHeight(s)) > (bmp.Height - Padding)) then
  49.                   begin
  50.                     s := '';
  51.                     break;
  52.                   end;
  53.                 // assign a new word for the next line
  54.                 s := sa[i];
  55.               end;
  56.           end;
  57.         // if it is just one line, draw it
  58.         if (s <> '') then
  59.           bmp.Canvas.TextOut(Padding, PosY, s);
  60.       end;
  61.     // give the prepared image to the paintbox
  62.     APaintBox.Canvas.Draw(0, 0, bmp);
  63.   finally
  64.     bmp.Free;
  65.   end;
  66. end;
In attachment you see my test setup.
Here is the code for the button:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   WordWrappedImage(PaintBox1, Memo1.Font, Memo1.Text, clSkyBlue);
  4. end;
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Painting text
« Reply #9 on: April 12, 2024, 02:16:24 pm »
Updated my way of doing, included Handokos suggestion and added a X-center option.
Code: Pascal  [Select][+][-]
  1. procedure WordWrappedImage(var APaintBox: TPaintBox; const AFont: TFont; const AText: AnsiString; const ABackground, ABorder, ATransparent: TColor; const ACentered: Boolean = False);
  2. var
  3.   bmp: TBitmap;
  4.   sa: TStringArray;
  5.   s: string;
  6.   i: Integer;
  7.   PosY, Padding: Integer;
  8. begin
  9.   // create a bitmap on the fly
  10.   bmp := TBitmap.Create;
  11.   try
  12.     // set size to paintbox
  13.     bmp.SetSize(APaintBox.Width, APaintBox.Height);
  14.     // set fake transparent color
  15.     bmp.Canvas.Brush.Color := ATransparent;
  16.     // fill image with above fake color so we dont have "black" corners
  17.     bmp.Canvas.FillRect(bmp.Canvas.ClipRect);
  18.  
  19.     // set real background color and draw rounded corner style like Handoko showed, just adjusted for this example
  20.     bmp.Canvas.Brush.Color := ABackground;
  21.     bmp.Canvas.Pen.Style   := psDash;
  22.     bmp.Canvas.Pen.Width   := 1; // i prefer a small line around, adjust to your needs
  23.     bmp.Canvas.Pen.Color   := ABorder;
  24.     bmp.Canvas.RoundRect(bmp.Canvas.ClipRect, 15, 15); // adjust the numbers, higher values = bigger corner angle, you can also play with two different values like 15 and 30 to get a different shaped corner
  25.  
  26.     // set font, including color and any set style(s)
  27.     bmp.Canvas.Font := AFont;
  28.  
  29.     // space that stay free around text
  30.     Padding := 5;
  31.     // vertical counter
  32.     PosY := Padding;
  33.     // temporal string
  34.     s := '';
  35.     // convert the text to an array of words by splitting them at spaces or lineendings
  36.     sa := AText.Split([' ', #10, #13]);
  37.     // draw text wordwrapped on image
  38.     // this method fails if a word is bigger than the image got space
  39.     for i := Low(sa) to High(sa) do
  40.       begin
  41.         // assign some word to draw for a new line
  42.         if s = '' then
  43.           s := sa[i]
  44.         else
  45.           // or begin testing if the collection of words are fitting into the image
  46.           begin
  47.             // add more words to current line
  48.             if (bmp.Canvas.TextWidth(s + ' ' + sa[i]) < (bmp.Width - Padding)) then
  49.               s := s + ' ' + sa[i]
  50.             else
  51.               begin
  52.                 // draw current line
  53.                 if ACentered then
  54.                   bmp.Canvas.TextOut((bmp.Width - bmp.Canvas.TextWidth(s)) div 2, PosY, s)
  55.                 else
  56.                   bmp.Canvas.TextOut(Padding, PosY, s);
  57.                 Inc(PosY, bmp.Canvas.TextHeight(s));
  58.                 // check if we are in bounds of image
  59.                 // everything that not fit anymore will be skipped
  60.                 if ((PosY + bmp.Canvas.TextHeight(s)) > (bmp.Height - Padding)) then
  61.                   break;
  62.                 // assign the last word that not fitted for the next line
  63.                 s := sa[i];
  64.               end;
  65.           end;
  66.         // if it is just one line, draw it
  67.         if (s <> '') then
  68.           if ACentered then
  69.             bmp.Canvas.TextOut((bmp.Width - bmp.Canvas.TextWidth(s)) div 2, PosY, s)
  70.           else
  71.             bmp.Canvas.TextOut(Padding, PosY, s);
  72.       end;
  73.  
  74.     // give the prepared image to the paintbox
  75.     APaintBox.Canvas.Draw(0, 0, bmp);
  76.   finally
  77.     bmp.Free;
  78.   end;
  79. end;
Example call:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   WordWrappedImage(PaintBox1, Memo1.Font, Memo1.Text, clSkyBlue, clBlue, clBtnFace, True);
  4. end;
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

SaraT

  • Full Member
  • ***
  • Posts: 131
  • A little student
Re: Painting text
« Reply #10 on: May 18, 2024, 08:13:01 am »
Hi guys!!

I would like to paint and bold a word only with the above code.
How can I do this?

Lets say to bold the first word "Lorem ipsum..." in your example.

Please and thanks a lot!

 

TinyPortal © 2005-2018