Как лучше всего программно сказать, обрезается ли заголовок TLabel (т.е. нарисован с использованием многоточия)? - PullRequest
3 голосов
/ 30 ноября 2010

У меня TLabel с EllipsisPosition, установленным на epEndEllipsis, и я должен быть в состоянии определить, обрезан ли текст в настоящее время или нет.Помимо расчета площади, необходимой для отображения текста самостоятельно, и сравнения ее с фактическими размерами надписи, кто-нибудь придумал более простой / более элегантный способ сделать это?

На самом деле, вычисление необходимой области вОтказоустойчивый способ также не выглядит таким простым, как кажется ... Например, TCanvas.GetTextHeight не учитывает разрывы строк.

TCustomLabel.DoDrawText внутренне использует либо DrawTextWили DrawThemeTextEx с флагом DT_CALCRECT, чтобы определить, следует ли использовать многоточие или нет.Там задействовано довольно много кода, весь из которых объявлен private.Простое дублирование всего этого кода не будет квалифицироваться как «элегантный» в моей книге ...

Есть идеи?

(я использую Delphi 2010 на случай, если кто-нибудь придумаетрешение для Delphi-версии)

Обновление 1: Теперь я понял, что могу просто позвонить TCustomLabel.DoDrawText(lRect, DT_CALCRECT) напрямую (который просто объявлен protected), чтобыметка выполняет вычисление требуемого размера без дублирования своего кода.Я просто должен убедиться, что временно установил EllipsisPosition на epNone или вообще использовал временный экземпляр метки.Это на самом деле не так уж плохо, и я мог бы просто пойти с ним, если никто не может придумать еще более простое решение.

Обновление 2: Я добавил свое решение как отдельноеответ.Оказалось, что все оказалось гораздо проще, чем я ожидал, поэтому, вероятно, нет более простого / лучшего способа сделать это, но я все равно оставлю этот вопрос открытым на некоторое время на всякий случай.

Ответы [ 2 ]

3 голосов
/ 30 ноября 2010

FWIW, вот что я придумал (это метод пользовательского TLabel -десцендента):

function TMyLabel.IsTextClipped: Boolean;
const
  EllipsisStr = '...';
var
  lEllipBup: TEllipsisPosition;
  lRect: TRect;
begin
  lRect := ClientRect;
  Dec(lRect.Right, Canvas.TextWidth(EllipsisStr));

  lEllipBup := EllipsisPosition;
  EllipsisPosition := epNone;
  try
    DoDrawText(lRect, DT_CALCRECT or IfThen(WordWrap, DT_WORDBREAK));
  finally
    EllipsisPosition := lEllipBup;
  end;
  Result := ((lRect.Right - lRect.Left) > ClientWidth)
         or ((lRect.Bottom - lRect.Top) > ClientHeight);
end;

Поскольку теперь он использует ту же логику, что и TCustomLabel.DoDrawText (особенноискусственное заполнение и правильная настройка WordWrap), он также корректно работает с многострочными и переносимыми словами текстами.Обратите внимание, что «правильно» в данном случае означает «оно всегда возвращает True, когда TLabel рисуется с подрезанной надписью, а False в противном случае».

Хотя приведенный выше код выполняет то, что я изначально запрашивалЯ, вероятно, не буду использовать его таким образом - но это больше из-за недостатков самого TLabel: особенно с многострочным текстом, он часто ведет себя не так, как я бы этого хотел, например, когда недостаточно места дляВ нескольких строках последнее слово первой строки всегда будет обрезано, даже если бы поместилась вся эта строка плюс многоточие.

2 голосов
/ 30 ноября 2010

В качестве отправной точки вы можете использовать

function DrawStringEllipsis(const DC: HDC; const ARect: TRect; const AStr: string): boolean;
var
  r: TRect;
  s: PChar;
begin
  r := ARect;
  GetMem(s, length(AStr)*sizeof(char) + 8);
  StrCopy(s, PChar(AStr));
  DrawText(DC, PChar(s), length(AStr), r, DT_LEFT or DT_END_ELLIPSIS or DT_MODIFYSTRING);
  result := not SameStr(AStr, s);
  FreeMem(s);
end;

Пример использования:

procedure TForm1.FormClick(Sender: TObject);
begin
  Caption := 'Clipped ' + BoolToStr(DrawStringEllipsis(Canvas.Handle, Rect(10, 100, 50, 50), 'This is a text.'), true);
end;

Нетрудно написать компонент TExtLabel, который имеет WasClipped свойство с использованием этой техники.Действительно, компонент TLabel является одним из самых простых компонентов в VCL - он просто рисует строку.

...