Recent

Author Topic: [SOLVED] Problem with the handle when using function lclintf.DrawText  (Read 651 times)

Hartmut

  • Hero Member
  • *****
  • Posts: 749
I want to use function lclintf.DrawText() and have a problem with it's 1st parameter, which is a handle to a "device context". When I write:

Code: Pascal  [Select][+][-]
  1. var h: HDC; {=THandle}
  2. ...
  3. h:=Form1.Canvas.Handle;
  4.  
then it works. But I want to use DrawText() in a common unit, independently from a Form (only to compute the neccessary size of a text). Is this possible?

What I tried:

Code: Pascal  [Select][+][-]
  1. var CV: TCanvas;
  2.     h: HDC; {=THandle}
  3. ...
  4. CV:=TCanvas.Create;
  5. CV.Font.Name:='Courier New';
  6. CV.Font.Height:=15;
  7. h:=CV.Handle; {=> Exception "Canvas does not allow drawing"}
  8. ...
but this raises an Exception (see above). I tried also:

Code: Pascal  [Select][+][-]
  1. var LB: TLabel;
  2.     h: HDC; {=THandle}
  3. ...
  4. LB:=TLabel.Create(nil);
  5. LB.Canvas.Font.Name:='Courier New';
  6. LB.Canvas.Font.Height:=15;
  7. h:=LB.Canvas.Handle; {=> Access Violation}
  8. ...

which raises an Access Violation (see above).

What am I doing wrong?
I "want" the handle only to pass a specific font and font-size, nothing more needed.
I use Lazarus 2.0.10 with FPC 3.2.0 on Windows 7 and Linux Ubuntu 18.04. Thanks in advance.
« Last Edit: November 19, 2022, 05:17:54 pm by Hartmut »

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Problem with the handle when using function lclintf.DrawText
« Reply #1 on: November 18, 2022, 10:42:36 pm »
TLabel is not a windows type control, its a graphic control

You would use GetDC(0) maybe but the issue here is it uses the font size selected in the context. So using GetDC(0) is going to use the system's wide font.

 Or I suppose you could use a TPanel which has a handle.
 BUt you still need to set Font size etc.

The only true wisdom is knowing you know nothing

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2064
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Problem with the handle when using function lclintf.DrawText
« Reply #2 on: November 18, 2022, 11:39:33 pm »
For Windows I would do it like this:
Code: Pascal  [Select][+][-]
  1. uses
  2.   Windows...
  3.  
  4. function GetTextDimension(const AForm: TForm; const AString: string): TRect;
  5. var
  6.   r: TRect;
  7. begin
  8.   r := Rect(5, 5, 5, 5);
  9.   DrawText(AForm.Canvas.Handle, PChar(AString), Length(AString), r, DT_LEFT or DT_CALCRECT);
  10.   Result := r;
  11. end;
  12.  
and call like that
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   r: TRect;
  4. begin
  5.   r := GetTextDimension(Self, s);
  6.   Memo1.Lines.Add(Format('%d x %d', [r.Height, r.Width]));
  7. end;

I hope it helps.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Problem with the handle when using function lclintf.DrawText
« Reply #3 on: November 19, 2022, 12:14:55 am »
The problem with that is it still requires a distant handle outside the unit.

 I suppose a function could be written up so that it requires you to pass a handle to it of a known canvas when making the call. Remember, the poster stated that it lives in a unit away from all others so there is no form in there.

 After thinking about this, it may actually be better if a function did require a handle from some remote point within the calling parameters.
 
 At least it is still isolated in a unit that way.

The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Problem with the handle when using function lclintf.DrawText
« Reply #4 on: November 19, 2022, 12:46:30 am »
But I want to use DrawText() in a common unit, independently from a Form (only to compute the neccessary size of a text). Is this possible?
I would create a temporary bitmap and use its canvas:
Code: Pascal  [Select][+][-]
  1. function MeasureText(AText: String; AFont: TFont; MaxWidth: Integer): TSize;
  2. var
  3.   bmp: TBitmap;
  4.   R: TRect;
  5. begin
  6.   bmp := TBitmap.Create;
  7.   try
  8.     bmp.SetSize(1, 1);
  9.     bmp.Canvas.Font.Assign(AFont);
  10.     R := Rect(0, 0, MaxWidth, 0);
  11.     DrawText(bmp.Canvas.Handle, PChar(AText), Length(AText), R, DT_CALCRECT or DT_WORDBREAK);
  12.     Result := TSize(R.BottomRight);
  13.   finally
  14.     bmp.Free;
  15.   end;
  16. end;  
   

Hartmut

  • Hero Member
  • *****
  • Posts: 749
Re: Problem with the handle when using function lclintf.DrawText
« Reply #5 on: November 19, 2022, 05:17:28 pm »
Thanks a lot to all for your answers, especially to wp for your demo. It works perfectly with a Bitmap as handle source, so I implemented this.

Maybe it should be mentioned, that function DrawText makes one more difference in the LCL between Windows and Linux: if 'MaxWidth' is smaller than the longest word, then on Windows the result-width is increased to the neccessary width for this word (so it is not truncated), while on Linux this is not done (this word is truncated "in the middle" of the word).

 

TinyPortal © 2005-2018