Может ли TEdit показать цвет эмодзи? - PullRequest
6 голосов
/ 01 апреля 2019

Я бы хотел видеть смайлики в цвете в элементах управления TEdit или TMemo с использованием VCL и Delphi 10 +.

Можно ли это сделать?

Введенный текст:

??‍???‍??‍??‍??

Что я вижу:

enter image description here

Что я хотел бы увидеть:

enter image description here

1 Ответ

9 голосов
/ 01 апреля 2019

Ваш вопрос вызвал у меня любопытство, поэтому я попробовал, и вот результат:

Рисование цветных шрифтов в целом

Очевидно, FMX поддерживает это из коробки позже.версии, но не в Сиэтле, который у меня случается.Я не знаю, если VCL также поддерживает его из коробки в вашей версии, но если нет, вы можете добиться с помощью Direct2D.Хитрость заключается в рисовании текста с использованием опции D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT.

В Сиэтле (10) эта константа не определена и, к сожалению, не используется в функциях, совместимых с TCanvas по умолчанию.Но вы можете вызвать DrawText или одну из других функций самостоятельно и указать опцию.

Общая структура основана на этой документации Embarcadero .Остальное взято из TDirect2DCanvas в сочетании с DrawText документацией .

uses Vcl.Direct2D, Winapi.D2D1;

{$R *.dfm}

procedure TForm1.FormPaint(Sender: TObject);
const
  str: string = 'xyz??‍???‍??‍??‍??';
  D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT = 4;
var
  c: TDirect2DCanvas;
  r: D2D_RECT_F;
begin
  c := TDirect2DCanvas.Create(Canvas.Handle, Rect(0, 0, 100, 100));
  c.BeginDraw;
  try

    r.left := 0;
    r.top := 0;
    r.right := 100;
    r.bottom := 50;

    // Brush determines the font color.
    c.Brush.Color := clBlack;

    c.RenderTarget.DrawText(
      PWideChar(str), Length(Str), c.Font.Handle, r, c.Brush.Handle,
      D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
  finally
    c.EndDraw;
    c.Free;
  end;
end;

Этот маленький кусочек кода работает довольно уродливо (с точки зрения позиционирования текста), но выМожно также заглянуть в TDirect2DCanvas и скопировать реализацию одного из его текстовых методов, чтобы создать функцию для вывода текста определенным способом, который вы хотите.И после этого должно быть довольно легко применить это к вашему собственному потомку TGraphicControl или TCustomControl для создания ярлыка, поддерживающего эмодзи.

Выполнение этого в TEdit

Для управленияэто в TEdit сложнее, так как рисование текста (и смайликов) обрабатывается самим элементом управления.Должна быть возможность создать потомка TEdit и / или подключить его к сообщению WM_PAINT и закрасить текст, используя тот же трюк, но я не уверен, насколько хорошо это будет работать.

Я сделал быстрый снимок, но он не очень хорошо работает, особенно при редактировании.Итак, я сделал этого потомка TEdit.Когда он сфокусирован, он рисует текст обычным способом, и цветные эмодзи будут черно-белыми и разделятся на два символа (эмодзи и символ сочетания цветов).Когда редактирование теряет фокус, пользовательский код рисования вступает во владение, что хорошо работает в этом сценарии.Может быть, вы можете попытаться отшлифовать его, чтобы он работал и во время редактирования, но тогда вам нужно принять во внимание прокрутку, расположение каретки и другие вещи.Для потомка TMemo это будет еще сложнее.Я надеюсь, что вы довольны только цветным дисплеем.: -)

type
  TMyEdit = class(Vcl.StdCtrls.TEdit)
  protected
    procedure PaintWindow(DC: HDC); override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

uses Vcl.Direct2D, Winapi.D2D1;

{$R *.dfm}

const
  D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT = 4;

constructor TMyEdit.Create(AOwner: TComponent);
begin
  inherited;
  DoubleBuffered := True;
end;

procedure TMyEdit.PaintWindow(DC: HDC);
var
  c: TDirect2DCanvas;
  r: D2D_RECT_F;
begin
  // Default drawing when focused. Otherwise do the custom draw.
  if Focused then
  begin
    Inherited;
    Exit;
  end;

  c := TDirect2DCanvas.Create(dc, ClientRect);
  c.BeginDraw;
  try

    r.left := ClientRect.Left;
    r.top := ClientRect.Top;
    r.right := ClientRect.Right;
    r.bottom := ClientRect.Bottom;

    // Basic font properties
    c.Font.Assign(Font);
    // Brush determines the font color.
    c.Brush.Color := Font.Color;

    c.RenderTarget.DrawText(
      PWideChar(Text), Length(Text), c.Font.Handle, r, c.Brush.Handle,
      D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
  finally
    c.EndDraw;
    c.Free;
  end;
end;
...