There are two ways to draw text with Lazarus:
- Canvas.Textout /Canvas.TextRect: Debugging into the LCL you can see that it finally calls Windows.ExtTextOutW.
- DrawText(handle, ...): This finally calls Windows.DrawTextW
As the attached demo shows, the underscore issue occurs only with DrawText, not with Canvas.TextOut.
TLabel.Paint finally calls the DrawText method. I am aware that it has advantages in calculating the size of the bounding rectangle when wordwrapping is allowed. Maybe this was the reason why the creators of the LCL chose this method.
This leads to the idea that the reason for the issue is in Windows, and this is confirmed when I do the same test in Delphi XE10.3.3 which shows exactly the same behaviour.
I could imagine that the vertices of the font glyphs are defined either by floating point numbers or by large integers later scaled to the destination font size. Depending on how this is done exactly there may be round-off errors by one pixel which eventually may show or hide the underscore line.
Sounds bad...
On the other hand, as a remedy, we could increment the bottom of the rectangle returned by the DrawText method when DT_CALCRECT is included in the flags.
Since this is needed for Windows only, I'd recommend that you try the following steps:
- Load the file lcl/interfaces/win32/win32winapi.inc (You should make a backup copy of the changed file so that you can restore the original behaviour).
- Find the procedure TWin32WidgetSet.DrawText.
- Towards its end there is block "if lf.lfItalic > 0". Put the following code before this "if". It is supposed to move the bottom of the calculated bounding rectangle of the text by one pixel to avoid clipping of the underscore line.
if lf.lfUnderline<>0 then
inc(Rect.Bottom);
- Rebuild the IDE and run your tests again
- Report back whether it fixes the issue and whether you see any side effects (it seems to work for me).