Changing Text Line Spacing using Windows API

Hi everyone,

I am currently programming in delphi and drawing text on a Canvas using the DrawText windows API.
The method can draw text and wrap it inside a specified Rectangle. The problem is that I can't modify the
vertical spacing between lines once the text wraps. anyone knows how? Thanks in advance!
:)

Here's my code:
const
   TEXT = 'The quick brown fox jumped over the sly lazy dog.';
var
   Flags : integer;
   MyRect : TRect;
begin
   Flags := DT_WORDBREAK;
   MyRect := Rect(0,0,20,20);
   DrawText(Image1.Canvas.Handle, PChar(TEXT), Length(TEXT), MyRect, Flags);
end;
dabestprogrammerindauniverseAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

aikimarkCommented:
include the DT_CALCRECT flag value to have the DrawText function return the height of the text.
http://www.undu.com/Articles/010129a.html
http://www.undu.com/Articles/981008d.html

You can also get the height (in pixels) of the current font settings with:
Th:=Image1.Canvas.TextHeight('Xg');        {Height of current font in pixels}
0
dabestprogrammerindauniverseAuthor Commented:
thanks aikimark,
but my question is how to change the width between the lines of the spacing between the lines. :)
0
aikimarkCommented:
you might have to roll-your-own line wrapping:
Loop through the words in the string, appending each word (to be written to your canvas) until the temporary string is larger than the rectangle you wish to draw.  

Remove the last word added (or hyphenate it, which is a more advanced technique and more difficult).

Write the string to the canvas

Reset the string variable

Move the CurrentY position of the canvas down by some multiplier of the height of the fontsize.

Start appending new words with the next iteration of the loop until you have written all the words.
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

dabestprogrammerindauniverseAuthor Commented:
Yup, I figured that out. Also, in case a line consists of only one word whose width is wider than the specified rect, then the clipping should be on a per character basis. So there isn't any other way is there?
thanks! :)
0
aikimarkCommented:
I do not know of any property, method, or API that would allow you do this easily.

Here's an interesting idea for you to explore:
1. Use DrawText to automatically wrap your text
2. save the characters or character images from each line into a data structure
3. Clear the drawing area rectangle
4. increase the height of the drawing area by the
number_of_lines * (inter_line_space_increase - 1)
5. loop through your saved lines and print/draw them at the appropriate location.

============
I've never written a hyphenation routine, so can't give you much help on that topic.
0
aikimarkCommented:
Another thought would be to use a Rich Text Format object to do the wrapping and inter-line spacing for you and do either of the following:
1. replace the DrawText area with the visible RTF control
2. copy the RTF object's canvas to your Image1.Canvas
0
Slick812Commented:
hello  dabestprogrammerindauniverse , , I have used the  GetTextExtentExPoint( ) function to get a Line break distance, like this -



procedure TForm1.but_CustomTextClick(Sender: TObject);
var
TextStr: String;
Bmp1: TBitmap;
numChar, lines: Integer;
aSize: tagSize;
begin
// button click event
TextStr := 'This is a text string long enough to wrap a couple of times. And '+
           'More text here, followed by even more text  followed by eveen more text'+
           ' followed by even more text  followed by even moore text';
Bmp1 := TBitmap.Create;
try
  Bmp1.Width := 188;// try to have a 3 pixel border, use 182 below
  Bmp1.Height := 210;
  Bmp1.Canvas.Font.Name := 'Arial';
  Bmp1.Canvas.Font.Size := 12;

  if Length(TextStr) < 1 then Exit;
  lines := 0;
  repeat
  GetTextExtentExPoint(Bmp1.Canvas.Handle, PChar(TextStr),Length(TextStr),182,
                     @numChar, nil, aSize);
  TextOut(Bmp1.canvas.handle,3,(lines*(aSize.cy+8))+3,PChar(TextStr), numChar);
                                              // use the y postion above to adjust the custom spacing per line
  Delete(TextStr,1,numChar);
  Inc(Lines);
  until Length(TextStr) < 1;

  Canvas.Draw(530,290, Bmp1);
  finally
  FreeAndNil(Bmp1);
  end;
end;


 = = = = = = = = = = = = = =  = = = = = = =  =
this seems to work for me, however this does NOT find spaces and punctuation to divide the words, it will chop a word anywhere
  ask questions if you need more
0
Slick812Commented:
very sorry, I posted before looking some, I found better do what, you may try this one, I tink it will devide on spaces an punctuaton



procedure TForm1.but_CustomTextClick(Sender: TObject);
var
TextStr: String;
Bmp1: TBitmap;
numChar, oNum, lines: Integer;
aSize: tagSize;
begin
TextStr := 'Thisisatextstringlongenoughtowrap a couple of times. And'+
           'Moretextherefollowedbevenmore text  followed by eveen more text'+
           ' followed-by-even-more-text  followed by even moore text';
Bmp1 := TBitmap.Create;
try
  Bmp1.Width := 188;// try to have a 3 pixel border, use 182 below
  Bmp1.Height := 230;
  Bmp1.Canvas.Font.Name := 'Arial';
  Bmp1.Canvas.Font.Size := 11;

  if Length(TextStr) < 1 then Exit;
  lines := 0;
  repeat
  GetTextExtentExPoint(Bmp1.Canvas.Handle, PChar(TextStr),Length(TextStr),182,
                     @numChar, nil, aSize);
  oNum := numChar;
  while (numChar > 1) and not
      (TextStr[numChar] in [' ','.',',','-','_','?','!','$','(',')']) do
       Dec(numChar);
  if numChar = 1 then
    numChar := oNum;
  TextOut(Bmp1.canvas.handle,3,(lines*(aSize.cy+8))+3,PChar(TextStr), numChar);
  Delete(TextStr,1,numChar);
  Inc(Lines);
  until Length(TextStr) < 1;

  Canvas.Draw(530,290, Bmp1);
  finally
  FreeAndNil(Bmp1);
  end;
end;
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.