【问题标题】:Unexpected offset when using WinApi.Windows.TextOut with escapement使用带擒纵机构的 WinApi.Windows.TextOut 时出现意外偏移
【发布时间】:2019-04-27 21:50:20
【问题描述】:

我正在尝试使用 winapi TextOut 方法将文本绘制到画布上。这在擒纵机构为 0、900、1800 或 2700 时工作得相当好,但对于所有其他值,我得到一个偏移错误(“跳跃”)。

请运行附加的代码来查看问题。如您所见,水平和垂直文本按预期绘制,但第三行绘制在错误位置。

一些问题:

  1. 显而易见:为什么会发生这种情况,我应该怎么做才能解决它
  2. 为什么方向没有效果?我在示例中输入了 1234,但无论我使用什么值,结果都是相同的

(我们使用的代码是一个旧的“类似cad”库的一部分。这个库的作者已经离开了这个星球,所以我们不能请他帮助我们,这将是一个很大的麻烦用一个新的更现代的库替换这个库。我试图隔离相关代码)

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TFaceName = string[LF_FACESIZE];
  TExtendedFont = class(TObject)
  private
    LogFont: TLOGFONTA;
    FHandle: HFONT;
  public
    constructor Create;
    destructor Destroy; override;
    procedure UpdateHandle;

    property Handle: HFONT read FHandle;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    procedure DrawText(X,Y,Escapement : integer; T : string);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TExtendedFont.UpdateHandle;
var
  TmpHandle: HFONT;
begin
  TmpHandle := CreateFontIndirectA(LogFont);
  DeleteObject(FHandle);
  FHandle := TmpHandle;
end;

constructor TExtendedFont.Create;
begin
  inherited Create;
  GetObject(GetStockObject(DEFAULT_GUI_FONT), SizeOf(LogFont), @LogFont);
  LogFont.lfFaceName := 'Courier New';
  FHandle := CreateFontIndirectA(LogFont);
end;

destructor TExtendedFont.Destroy;
begin
  DeleteObject(FHandle);
  inherited Destroy;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Canvas.FillRect(ClientRect);
  DrawText(150,150,0,'No escapement (0°)');
  DrawText(150,150,1800,'180°');
  DrawText(150,150,2700,'270°');
  DrawText(150,150,StrToIntDef(Edit1.Text,0),'With escapement');
end;

procedure TForm1.DrawText(X,Y,Escapement : integer; T : string);
var
  C : TCanvas;
  FLogFont : TExtendedFont;
begin
  C := Canvas;

  FLogFont := TExtendedFont.Create;
  try
    FLogFont.LogFont.lfHeight := 21; //With a value of 20 or less, the problem disappears
    FLogFont.LogFont.lfEscapement := Escapement;
    FLogFont.LogFont.lfOrientation := 1234; //It doesn't seem to matter what value I use here
    FLogFont.UpdateHandle;

    SetTextAlign(C.Handle,TA_BOTTOM+TA_LEFT+TA_NOUPDATECP);

    C.Font.Handle := FLogFont.Handle;
    SetBkMode(C.Handle, TRANSPARENT);

    C.Pixels[X,Y] := clRed; //This SHOULD be the lower left corner of the text
    WinApi.Windows.TextOut(C.Handle,X,Y,PChar(T), Length(T));
  finally
    C.Font.Handle := 0;
    FLogFont.Free;
  end;  // try/finally
end;

end.

-

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 336
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 63
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Draw text'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Edit1: TEdit
    Left = 8
    Top = 8
    Width = 49
    Height = 21
    TabOrder = 1
    Text = '1'
  end
end

-

program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form2};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

【问题讨论】:

    标签: delphi canvas textout


    【解决方案1】:
    1. 似乎取决于使用的字体。前任使用 Tahoma 而不是 Courier New 字体大小为 21 或 27 时问题不可见。我没有关于如何纠正 Courier New 的建议。

    2. 取决于Graphics Mode

    图形模式默认为 GM_COMPATIBLE(值 1),logfont 的文档说(强调我的):

    lfEscapement - 指定角度,以十分之一度为单位,在 擒纵矢量和设备的 x 轴。擒纵机构矢量 平行于一行文本的基线。 当图形模式设置为 GM_COMPATIBLE 时,lfEscapement 指定擒纵和方向。你应该设置 lfEscapement 和 lfOrientation 为相同的值。

    在我看来这是一种误导,因为lfOrientation 的设置无效。

    进一步:

    lfOrientation - 指定角度,以十分之一度为单位 每个字符的基线和设备的 x 轴。

    在我的测试中,对于GM_COMPATIBLE,我发现lfOrientation 是否设置没有区别(正如您所说)。

    但是,在GM_ADVANCED 模式下,设置lfOrientation 肯定会影响字符方向。

    使用SetGraphicsMode(C.Handle, GraphicsMode); 更改图形模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-08
      • 2020-10-17
      • 1970-01-01
      • 1970-01-01
      • 2017-11-15
      • 2021-09-28
      • 1970-01-01
      • 2018-12-29
      相关资源
      最近更新 更多