Могу ли я сам сделать размер TMemo для текста, который он содержит?

Когда вы редактируете заголовок TLabel в дизайнере форм, он изменяет размер TLabel для вас. Есть ли способ заставить TMemo сделать это во время выполнения?

Я хотел бы иметь возможность взять TMemo, присвоить что-то его свойству .lines.text, а затем сказать ему изменить размер и не превышать определенную ширину, хотя он может стать настолько высоким, насколько захочет. Кто-нибудь знает, как это сделать?


person Mason Wheeler    schedule 01.06.2009    source источник


Ответы (4)


Установите для свойства WordWrap элемента TMemo значение true, выгрузите в него свой текст, подсчитайте строки и установите высоту как произведение количества строк и высоты строки, но вам нужно знать высоту строки.

TMemo не предоставляет свойство высоты строки, но если вы не меняете шрифт или размер шрифта во время выполнения, вы можете экспериментально определить высоту строки во время разработки.

Вот код, который я использовал для установки высоты TMemo с высотой строки 13 пикселей. Я также обнаружил, что мне нужна небольшая константа для учета верхней и нижней границ TMemo. Я ограничил высоту до 30 строк (396 пикселей), чтобы сохранить форму.

// Memo.WordWrap = True (at design time)
Memo.Text := <ANY AMOUNT OF TEXT>;
Memo.Height := Min(19 + Memo.Lines.Count * 13, 396); 

Если вам абсолютно необходимо извлечь высоту строки из объекта во время выполнения, вы можете использовать чей-то ответ. Или вы можете использовать TRichEdit, у которого есть свойство SelAttributes, содержащее свойство Height, задающее высоту строки.

-Al.

person A. I. Breveleri    schedule 01.06.2009
comment
Я должен был подумать об этом. Я слишком привык работать с TStringLists, которые делают разрывы строк в CRLF, поэтому мне никогда не приходило в голову, что свойство WordWrap фактически поместит завернутые строки в разные строки .Lines. Спасибо! - person Mason Wheeler; 02.06.2009
comment
Font.Height содержит отрицательное число, подсчитывающее количество пикселей в текстовой строке. Также вы можете вызвать Canvas.TextExtent для расчета высоты текста. - person Stijn Sanders; 02.06.2009

Это прекрасно работает для меня. Добавленная константа (8) может варьироваться в зависимости от того, используете ли вы границу и/или скос, поэкспериментируйте с ней.

procedure TForm1.Memo1Change(Sender: TObject);
var
  LineHeight: Integer;
  DC: HDC;
  SaveFont : HFont;
  Metrics : TTextMetric;
  Increase: Integer;
  LC: Integer;
begin
  DC := GetDC(Memo1.Handle);
  SaveFont := SelectObject(DC, Memo1.Font.Handle);
  GetTextMetrics(DC, Metrics);
  SelectObject(DC, SaveFont);
  ReleaseDC(Memo1.Handle, DC);
  LineHeight := Metrics.tmHeight;
  Increase := Memo1.Height;
  LC := Memo1.Lines.Count;
  if LC < 1 then
    LC := 1;
  Memo1.Height := LC * LineHeight + 8;
  Increase := Memo1.Height - Increase;
  Memo1.Parent.Height := Memo1.Parent.Height + Increase;
end;
person Community    schedule 01.06.2009
comment
Хороший ответ. Я выбрал другой, потому что он был проще, но он работает очень хорошо. Кстати, вам не нужно беспокоиться о +8; вы можете просто назначить ClientHeight и позволить системе позаботиться о границе. - person Mason Wheeler; 02.06.2009
comment
Я знаю, что это старо, но я попробовал предложение @MasonWheeler, и оно никогда не работало правильно. Я считаю, потому что ClientHeight включает внутреннее дополнение, которое есть в заметке. Таким образом, даже установив ClientHeight, вам нужно сделать вызов EM_GETRECT, чтобы действительно рассчитать корректировку размера. - person Tony; 20.12.2017

Я реализовал саморастущий TMemo как хороший пример LiveBindings (один из немногих полезных примеров, которые я мог придумать для LiveBindings в VCL).

Цитата из моего руководства по курсу Delphi XE2 Development Essentials:

«Чтобы построить этот пример, поместите компонент TMemo в форму VCL, откройте свойство LiveBindings и выберите параметр «Новый LiveBinding». Выберите вариант TBindExpression. Откройте BindExpressionMemo11 в инспекторе объектов и установите для SourceComponent значение Memo1, а для SourceExpression — Lines. Count * 22. Чтобы получить лучший результат во время выполнения, установите для SourceExpression более точное выражение.

Font.Size - 4 + (Lines.Count + 1) * -1 * (Font.Height - 3)

Наконец, в обработчике события OnChange TMemo напишите одну строку кода:

BindingsList1.Notify(Отправитель, '');

Вот и все. Скомпилируйте и запустите, чтобы увидеть растущую памятку в действии.

[снимок экрана]

Первоначально элемент управления TMemo будет иметь высоту в две строки (строка с содержимым и следующая строка), и всякий раз, когда мы нажимаем клавишу ввода или перенос слов переводит нас на следующую строку, элемент управления TMemo будет увеличиваться в высоту (фактически, уменьшаясь, поэтому не забудьте оставить достаточно места в форме для расширения TMemo)».

Гротьес, Боб Сварт

person Bob Swart    schedule 04.11.2011
comment
Я был очень взволнован этим ответом, но, похоже, он больше не подходит для XE10 Berlin. - person Tony; 20.12.2017

А почему бы просто не:

Memo1.Height := Memo1.ContentBounds.Height + 5;
person user3223924    schedule 16.04.2014