DrawTextEx не работает со шрифтом DT_RIGHT и Arial

У меня проблема с DrawTextEx. При использовании Align = DT_RIGHT и шрифта «Arial» текст выходит за пределы прямоугольника.

Это код, который я использовал для воспроизведения проблемы:

procedure TForm2.FormShow(Sender: TObject);
var
  LRect: TRect;
  LString : string;
  LMetaCanvas: TMetafileCanvas;
  LAlign: integer;
  LParams: TDrawTextParams;
begin
  LMetaCanvas := TMetafileCanvas.Create(Image1.Picture.Metafile, 0);

  LRect := Rect(10, 10, 200, 200);

  LMetaCanvas.Brush.Color := clWhite;
  LMetaCanvas.Brush.style := bsSolid;

  LMetaCanvas.Rectangle(LRect.Left, LRect.Top, LRect.Right, LRect.Bottom);

  LMetaCanvas.Font.Name := 'Arial';
  LMetaCanvas.Font.Size := 10;
  LMetaCanvas.Brush.Color := clBlack;
  LMetaCanvas.Brush.Style := bsClear;
  LString := '111111111111111112';

  LParams.cbSize := SizeOf(LParams);
  LParams.iTabLength := 0;
  LParams.iLeftMargin := 0;
  LParams.iRightMargin := 0;
  LParams.uiLengthDrawn := Length(LString);

  LAlign := DT_RIGHT or DT_NOPREFIX or DT_EDITCONTROL or DT_EXPANDTABS or DT_NOCLIP;

  DrawTextEx(
    LMetaCanvas.Handle,
    PChar(LString),
    Length(LString),
    LRect,
    LAlign,
    @LParams);

  LMetaCanvas.Free;
end;

Без DT_NOCLIP символы, находящиеся за пределами прямоугольника, даже не отображаются.

Я использую Delphi 10.2 в Windows 10 Pro, но сталкивался с этой проблемой также в Delphi XE3 и Delphi 2007.

Редактировать: я пытался использовать DT_CALCRECT, но я не уверен, что это правильный способ… Вот код, который я использовал:

  LAlign := DT_RIGHT or DT_NOPREFIX or DT_EDITCONTROL or DT_EXPANDTABS or DT_NOCLIP or DT_CALCRECT;

  DrawTextEx(
    LMetaCanvas.Handle,
    PChar(LString),
    Length(LString),
    LRect,
    LAlign,
    @LParams);

  LAlign := DT_RIGHT or DT_NOPREFIX or DT_EDITCONTROL or DT_EXPANDTABS or DT_NOCLIP;

  DrawTextEx(
    LMetaCanvas.Handle,
    PChar(LString),
    Length(LString),
    LRect,
    LAlign,
    @LParams);

  LMetaCanvas.Free;
end;

После первого вызова DrawTextEx LRect стал (10, 10, 120, 26), что делает его меньше, чем я настроил его вначале (10, 10, 200, 200). Текст выровнен по левому краю (я думаю, это потому, что LRect был изменен, чтобы соответствовать тексту), и все равно без DT_NOCLIP я не вижу последние цифры.

Редактировать: проект, в котором возникла эта проблема, требует TMetaFileCanvas (для других целей) и использует DrawTextEx для отображения сумм (которые должны быть выровнены по правому краю), поэтому, к сожалению, я не могу изменить тип холста, выравнивание или текст. Использование другого шрифта, такого как Arial Unicode MS (который, похоже, не имеет проблем), означало бы изменение огромного количества существующих отчетов, поэтому я бы предпочел избегать этого решения.


person Marina Finetti    schedule 03.08.2019    source источник
comment
Похоже, совсем угловой случай. 1 в качестве символа, Arial в качестве шрифта и метафайл в качестве контекста устройства... Измените любой из трех, и я не могу найти ни одной комбинации, которая смещается. Хотя можно было бы предположить, что они есть. Мне кажется, это проблема MS.   -  person Sertac Akyuz    schedule 20.08.2019
comment
@SertacAkyuz Я согласен, это выглядит как крайний случай, но этот фрагмент кода представляет собой реальную проблему, которая возникает довольно часто и представляет собой большую проблему, когда пользователи видят усеченную сумму денег. Иногда они даже не понимают, что сумма неверна, потому что усечение обрезает целую цифру, а не ее часть. Я думал, что это тоже может быть проблема MS, но я надеялся решить ее с помощью обходного пути в Delphi… А вы? есть предложение?   -  person Marina Finetti    schedule 23.08.2019
comment
Изменение шрифта было бы логичным действием. Однако это может не иметь никакого значения, если пользователи могут выбирать свой шрифт. Приклеивание невидимого символа к проблемным символам может быть обходным путем. Я попробовал и обнаружил, что пространство нулевой ширины работает нормально f.i. Например: LString := StringReplace(LString, '1', '1'#$200B, [rfReplaceAll]); (не знаю, будут ли проблемы с D2007). Также может помочь воспроизведение проблемы только с вызовами API и пометка вопроса с помощью winapi.   -  person Sertac Akyuz    schedule 23.08.2019
comment
.. AAMOF достаточно одного пробела нулевой ширины, даже не важно где он находится. Например: LString := LString + #$200B; Возможно, это заставляет обойти какую-то оптимизацию. Или кто знает что...   -  person Sertac Akyuz    schedule 24.08.2019
comment
@SertacAkyuz добавление пробела нулевой ширины в конце LString сработало, спасибо!   -  person Marina Finetti    schedule 26.08.2019


Ответы (1)


Как предложил @SertacAkyuz, добавление пробела нулевой ширины в конце LString решило проблему.

LString := LString + #$200B;
person Marina Finetti    schedule 27.08.2019