Практика
Сортировка ListView в режиме vsReport при нажатии на заголовок колонки

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика


Довольно интересная, а главное полезная функция. Те, кто работают с Total Commander, понимают, о чем идет речь. И сейчас мы постараемся разобраться, как это делается.

Итак, в наш ListView мы загрузим все файлы, находящиеся в той директории, которую мы выберем. Не будем сканировать подкаталоги, сейчас нам это не нужно. В ListView будет пять колонок, по которым мы будем проводить сортировку. В первую колонку мы поместим имя файла, во вторую - его расширение, в третьей колонке будет размер файла, четвертая и пятая будут содержать дату и время последнего изменения файла. Обратите внимание, дата и время именно последнего изменения, а не создания файла.

Добавим в программу целочисленную переменную Sort. Она будет отвечать за направление сортировки - прямое или обратное.

var
  Form1: TForm1;
  Sort: integer = 1;

Далее нужно выбрать директорию, списком файлов из которой мы будем манипулировать. Желательно, чтобы в директории было побольше файлов, директория Windows вполне подойдет. Следующая функция вызывает диалог выбора каталога (не забудьте подключить FileCtrl).

procedure TForm1.Button1Click(Sender: TObject);
var
  Dir1: string; // Dir1 - начальная директория
  Dir2: string; // Dir2 - выбранный каталог
begin
   if SelectDirectory( 'Выбор каталога', Dir1, Dir2 ) then
   begin
      ListView1.Clear;  // Очищаем ListView
      GetFiles( Dir2 ); // Запускаем поиск файлов
   end;
end;

В приведенном выше коде процедура GetFiles ищет файлы и выводит всю информацию о них в ListView. Разберем поподробней эту процедуру.

procedure GetFiles( APath: string );
var
  sr: TSearchRec;
  isFound: boolean;
  ListItem: TListItem;
  temp: string;
begin
   // Поиск первого файла в директории
   isFound := FindFirst( APath + '\*.*', faAnyFile, sr ) = 0;
   // Если он найден, получаем информацию о нем, и ищем дальше
   while isFound do
   begin
      // Если файл не является папкой
      if ( sr.Name <> '.' ) and ( sr.Name <> '..' ) and
         ( ( sr.Attr and faDirectory ) <> faDirectory ) then
         begin
            // Добавляем новый item
            ListItem := Form1.ListView1.Items.Add;
            // Получаем имя файла
            temp := ExtractFileName( sr.Name );
            if LastDelimiter( '.', temp ) <> 0 then
               ListItem.Caption := Copy( temp, 0, LastDelimiter( '.', temp )-1 )
            else
               ListItem.Caption := temp;
            // Получаем расширение файла
            temp := ExtractFileExt( sr.Name );
            ListItem.SubItems.Add( Copy( temp, Pos( '.', temp )+1, Length( temp ) ) );
            // Размер файла
            ListItem.SubItems.Add( IntToStr( sr.Size ) );
            // Дата последнего изменения файла
            ListItem.SubItems.Add( DateToStr( FileDateToDateTime( 
                                   FileAge( APath + '\' + sr.Name ) ) ) );
            // Время последнего изменения файла
            ListItem.SubItems.Add( TimeToStr( FileDateToDateTime( 
                                   FileAge( APath + '\' + sr.Name ) ) ) );
         end;
      // Пытаемся найти следующий файл
      isFound := FindNext( sr ) = 0;
   end;
   // Прекращаем поиск
   FindClose( sr );
end;

Теперь, когда все готово, можем приступать к сортировке. Обработаем щелчок мыши по заголовку колонок, и в зависимости от того, по какой колонке щелкнули, выполним соответствующую процедуру сортировки.

procedure TForm1.ListView1ColumnClick(Sender: TObject;
  Column: TListColumn);
begin
   Sort := -Sort;
   // Если щелкнули по первой колонке - Caption
   if Column = ListView1.Columns[0] then
      ListView1.CustomSort( @SortCaptionAsString, Sort )
   else
   // Если щелкнули по второй колонке - SubItem1
   if Column = ListView1.Columns[1] then
      ListView1.CustomSort( @SortFirstSubItemAsString, Sort )
   else
   // Если щелкнули по третьей колонке - SubItem2
   if Column = ListView1.Columns[2] then
      ListView1.CustomSort( @SortSecondSubItemAsInteger, Sort )
   else
   // Если щелкнули по четвертой колонке - SubItem3
   if Column = ListView1.Columns[3] then
      ListView1.CustomSort( @SortThirdSubItemAsDate, Sort )
   else
   // Если щелкнули по пятой колонке - SubItem4
   if Column = ListView1.Columns[4] then
      ListView1.CustomSort( @SortFourthSubItemAsTime, Sort );
end;

Помните, в самом начале мы объявили переменную Sort, которая отвечает за направление сортировки. Здесь, при каждом клике по заголовку, мы меняем значение Sort на противоположное (Sort может принимать значения 1 и -1), тем самым мы меняем направление сортировки.

Ну и наконец, сами процедуры сортировки.

// Сортируем по первой колонке
// Caption - текстовое поле
function SortCaptionAsString(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall;
begin
   Result := 0;
   if AnsiUpperCase( Item1.Caption ) > AnsiUpperCase( Item2.Caption ) then
      Result := ParamSort
   else
   if AnsiUpperCase( Item1.Caption ) < AnsiUpperCase( Item2.Caption ) then
      Result := -ParamSort;
end;

// Сортируем по второй колонке
// SubItem1 - текстовое поле<
function SortFirstSubItemAsString(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall;
begin
   Result := 0;
   if AnsiUpperCase( Item1.SubItems[0] ) > AnsiUpperCase( Item2.SubItems[0] ) then
      Result := ParamSort
   else
   if AnsiUpperCase( Item1.SubItems[0] ) < AnsiUpperCase( Item2.SubItems[0] ) then
      Result := -ParamSort;
end;

// Сортируем по третьей колонке
// SubItem2 - числовое поле
function SortSecondSubItemAsInteger(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall;
begin
   Result := 0;
   if StrToInt( Item1.SubItems[1] ) > StrToInt( Item2.SubItems[1] ) then
      Result := ParamSort
   else
   if StrToInt( Item1.SubItems[1] ) < StrToInt( Item2.SubItems[1] ) then
      Result := -ParamSort;
end;

// Сортируем по четвертой колонке
// SubItem3 - поле с датой
function SortThirdSubItemAsDate(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall;
begin
   Result := 0;
   if StrToDate( Item1.SubItems[2] ) > StrToDate( Item2.SubItems[2] ) then
      Result := ParamSort
   else
   if StrToDate( Item1.SubItems[2] ) < StrToDate( Item2.SubItems[2] ) then
      Result := -ParamSort;
end;

// Сортируем по пятой колонке
// SubItem4 - поле с временем
function SortFourthSubItemAsTime(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall;
begin
   Result := 0;
   if StrToTime( Item1.SubItems[3] ) > StrToTime( Item2.SubItems[3] ) then
      Result := ParamSort
   else
   if StrToTime( Item1.SubItems[3] ) < StrToTime( Item2.SubItems[3] ) then
      Result := -ParamSort;
end;

Ну вот, еще один секрет раскрыт. Удачи в программировании.

.: Пример к данной статье :.


При использовании материала - ссылка на сайт обязательна