2014-01-20 2 views
0

У меня есть несколько элементов управления списком (TListView), которые используются для отображения данных. Все эти списки имеют режим «Подробный», и все они имеют TImageList, присвоенные их свойствам «SmallIcons».Как правильно установить размер столбца ListView в соответствии с его содержимым?

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

Во-первых, я попытался установить ширину столбца на «-1» и «-2» для их автоматической калибровки: это не только отлично работало (некоторые столбцы, содержащие локальные символы), я использую D6 и это означает, что строки ANSI - слишком низки), но он также сделал отображение столбца чрезвычайно медленным (до 30 секунд, чтобы отобразить представление списка с 6 столбцами и 150 элементами, когда оно мгновенно с фиксированной шириной).

Я попытался использовать GetTextExtent в каждой ячейке, чтобы получить ожидаемую ширину текста, добавив некоторый запас (от 2 до 10 пикселей) и расширив ширину столбца, если он меньше расчетной ширины текста. Специальная обработка применяется к первому столбцу (Items.caption), чтобы учесть отображение значка (я добавляю ширину значка плюс маржа к ширине текста ячейки).

Это также не работает: во многих случаях (например, отображение даты в формате «yyyy/mm/dd hh: nn: ss» приводит к слишком большому тексту, чтобы соответствовать столбцу).

Думаю, что проблема может возникнуть из движка темы окна, я переключился на использование GetThemeTextExtent вместо GetTextExtent, но получил тот же результат.

Единственное, что, кажется, работает, это добавить произвольный большой запас (20 пикселей) к каждой ширине столбца, но, конечно, он создает столбцы, которые больше, чем они должны быть.

Итак, есть ли альтернативная стратегия? Мне не нужно ничего, кроме того, что будет вычислять правильную ширину один раз: когда список сначала заполняется. Код, стоящий за «щелчком разделителя столбцов», работает просто отлично, но я не могу найти, как его запускать с помощью кода (ну, я думаю, я мог бы отправлять сообщения двойного щелчка в заголовок непосредственно как взломать)

Для уточнения , вот что я попробовал следующий код:

(в случае вызова есть звонок, сделанный в ListView.canvas.Font.Assign(ListView.font). Он не находится в функции тезисов, потому что одного назначения достаточно, но петли кода на всех неавторизованных столбцах списка).

Редактировать

Моя первая попытка с помощью Windows Theme API:

function _GetTextWidth1(AText: widestring; IsHeader: boolean = false): Integer; 
var 
    ATheme: HTheme; 
    rValue: TRect; 
    iPartID: integer; 
    AWidetext: WideString; 
const 
    LVP_GROUPHEADER = 6; 
begin 
    // try to get text width using theme API 
    ZeroMemory(@rValue, SizeOf(rValue)); 
    ATheme := OpenThemeData(ListView.Handle, 'LISTVIEW'); 
    try 
    if not IsHeader then 
     iPartID := LVP_LISTITEM 
    else 
     iPartID := LVP_GROUPHEADER; 
    AWidetext := AText; 
    GetThemeTextExtent(ATheme, 
         ListView.Canvas.Handle, 
         iPartID, 
         LIS_NORMAL, 
         PWideChar(AWidetext), 
         -1, 
         DT_LEFT or DT_SINGLELINE or DT_CALCRECT, 
         nil, 
         rValue 
         ); 
    finally // wrap up 
    CloseThemeData(ATheme); 
    end; // try/finally 
    result := rValue.Right; 
end; 

следующую попытку с помощью DrawText/DrawTextW:

function _GetTextWidth2(AText: widestring; IsHeader: boolean = false): Integer; 
var 
    rValue: TRect; 
    lFlags: Integer; 
begin 
    // try to get text width using DrawText/DrawTextW 
    rValue := Rect(0, 0, 0, 0); 
    lFlags := DT_CALCRECT or DT_EXPANDTABS or DT_NOPREFIX or DT_LEFT or DT_EXTERNALLEADING; 
    DrawText(ListView.canvas.Handle, PChar(AText), Length(AText), rValue, lFlags); 
    //DrawTextW(ListView.canvas.Handle, PWideChar(AText), Length(AText), rValue, lFlags); 
    result := rValue.Right; 
end; 
функция TextWidth

Третья попытка с использованием Делфи

function _GetTextWidth3(AText: widestring; IsHeader: boolean = false): Integer; 
begin 
    // try to get text width using delphi wrapped around GetTextExtentPoint32 
    result := ListView.canvas.TextWidth(Atext); 
end; 

Во всех случаях я добавляю маржу к полученной ширине: я пробовал значения до 20 пикселей. Я также учитываю возможность использования значков с изображением (в этом случае я добавляю ширину значка плюс поле снова в первый столбец).

+1

Это можно сделать с помощью 'DrawText', используя флаг' DT_CALCRECT', например: http://stackoverflow.com/questions/16343147/how-do-i-use-drawtext-dt-calcrect-properly –

+0

Спасибо но я просто попробовал это и используя DrawText дает * точно * тот же результат, что и с использованием GetTextExtent. – Stephane

ответ

0

Вы можете использовать метод canvas.TextWidth. Но обязательно используйте TListView canvas (а не другие, т. Е. TForm), и сначала назначьте шрифт холсту из TListView. Например:

var 
    s: integer; 
begin 
    ListView1.AddItem('test example item', nil); 
    ListView1.canvas.Font.Assign(ListView1.font); 
    s := ListView1.canvas.TextWidth(ListView1.Items[0].Caption) + 10; //this "+10" is a small additional margin 
    if s > ListView1.Columns[0].Width then 
    ListView1.Columns[0].Width := s; 

Он отлично работает для меня.

+0

Спасибо за ваш комментарий, но, к сожалению, это тоже не сработает. Это не удивительно, учитывая, что внутри, он использует GetTextExtentPoint32 и поэтому делает то же самое, что и с моей первой попыткой. Однако, спасибо. – Stephane

+0

Я думаю, что это скорее должно работать. Я попробовал, и все работает нормально. Возможно, попробуйте это в новом проекте. Это работает? Если да, у вас должно быть что-то в вашем проекте, которое меняет метод getTextExtentPoint32. Может быть, вы изменили где-то свойство PixelsPerInch? О, и я забыл рассчитать ширину значка в моем примере. –

+0

Нет, извините: я тестировал его снова, и он не работает. Он делает что-то: ширина столбцов * почти * правая, но она по-прежнему скопирует почти каждый столбец, который не содержит более двух слов. Это кажется хуже, когда в ячейках есть локальные или специальные символы (французские акцентированные символы, «>», «<» в моих выборках). – Stephane

Смежные вопросы