Сортировка данных в колонках Listview

Тема в разделе "Delphi - Компоненты", создана пользователем Shouldercannon, 11 мар 2011.

  1. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Так делается сортировка для двух колонок;
    Код (Text):
    procedure TForm1.ListView1ColumnClick(Sender: TObject;
    Column: TListColumn);
    begin
    if FSortKey = Column.Index + 1 then FSortKey := -FSortKey else FSortKey := Column.Index + 1;
    if ListView1.SortType <> stText then ListView1.SortType := stText else ListView1.AlphaSort;
    end;

    procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
    Data: Integer; var Compare: Integer);
    var
    N1, N2: Integer;
    begin
    if Abs(FSortKey) = 1 then Compare := AnsiCompareText(Item1.Caption, Item2.Caption)
    else
    begin
    N1 := StrToInt(Item1.SubItems[Abs(FSortKey) - 2]);
    N2 := StrToInt(Item2.SubItems[Abs(FSortKey) - 2]);

    if N1 = N2 then Compare := 0 else if N1 < N2 then Compare := -1 else Compare := 1;
    end;
    Compare := Compare * (FSortKey div Abs(FSortKey));
    end;
    Но это только для двух колонок, а если их три, четыре или более?
    FSortKey - номер колонки.
    Код (Text):
     if Abs(FSortKey) = 1 then
    begin
    end
    else
    if Abs(FSortKey) = 2 then
    begin
    end
    else
    if Abs(FSortKey) = 3 then
    begin
    end;
    Как тут сделать сортировку не знаю.
     
  2. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Зачем такие ужастные извращения? Жалко 1 байт на Булиновую переменную? :)
    Вот так будет работать с любым количеством колонок:
    Код (Delphi):
     ...

    FSortKey: Integer;   // Теперь в самом деле используется как номер колонки
    FBackSort: Boolean; //  Направление сортировки

    ...

    procedure TForm1.ListView1ColumnClick(Sender: TObject;
    Column: TListColumn);
    begin
    if (FSortKey = Column.Index) then // Если это та же самая колонка - меняем направление сортировки
    FBackSort := not FBackSort
    else                                             // иначе - прямая сортировка
    FBackSort := False;

    FSortKey := Column.Index;
    ListView1.AlphaSort;
    end;

    procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
    Data: Integer; var Compare: Integer);
    var
    N1, N2, SubItemInd: Integer;
    begin
    if (FSortKey > 0) then // Сортируем по субайтемсам
    begin
    SubItemInd := FSortKey -1;

    // StrToInt не годится, потому как вызовет ошибку если строчка пустая
    // либо не приводится к числу. Поэтому StrToIntDef

    N1 := StrToIntDef(Item1.SubItems[SubItemInd],0);
    N2 := StrToIntDef(Item2.SubItems[SubItemInd],0);

    if FBackSort then       // Обратная сортировка
    Compare := N2 - N1
    else                     // Прямая сортировка
    Compare := N1 - N2;
    end
    else                    // Сортируем по капшену айтемса
    begin
    if FBackSort then    // Обратная сортировка
    Compare := AnsiCompareText(Item2.Caption,Item1.Caption)
    else                 // Прямая сортировка
    Compare := AnsiCompareText(Item1.Caption,Item2.Caption);
    end;
    end;
    Кстати... поскольку Вы сортируете вручную... то строчка из Вашего примера:
    Вообще смысла не имеет никакого... разве что Вы собирались запретить пользователю программы сортировку, ели это он в первый раз вообще кликнул по колонке... B)
     
  3. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Спасибо, работает. Но сортировка перестаёт работать если в колонках есть что-то на подобии: 00:12:05 или русские буквы (один символ), или латиские буквы (один символ), или данные типа 1/2.
     
  4. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Естественно... :)
    В Вашем же примере было (неявно) указано что в 1 колонке строки, а во всех остальных - числа...
    Можно в принципе любую колонку сортитовать как строки. Единственная неприятность (в случае с числами) следом за "1" встанет не "2" как ожидалось а "11"...
    Но... если переписать процедуру вот таким образом:
    Код (Delphi):
    procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
    Data: Integer; var Compare: Integer);
    var
    N1, N2, SubItemInd: Integer;
    begin
    if (FSortKey > 0) then // Сортируем по субайтемсам
    begin
    SubItemInd := FSortKey -1;

    // Если удалось привести к числу - сортируем как числа
    if (TryStrToInt(Item1.SubItems[SubItemInd],N1) and TryStrToInt(Item2.SubItems[SubItemInd],N2)) then
    begin
    if FBackSort then       // Обратная сортировка
    Compare := N2 - N1
    else                     // Прямая сортировка
    Compare := N1 - N2;
    end
    else    // если к числу не приводится - сортируем как строки
    begin
    if FBackSort then    // Обратная сортировка
    Compare := AnsiCompareText(Item2.SubItems[SubItemInd],Item1.SubItems[SubItemInd])
    else                 // Прямая сортировка
    Compare := AnsiCompareText(Item1.SubItems[SubItemInd],0,Item2.SubItems[SubItemInd]);
    end;
    end
    else                    // Сортируем по капшену айтемса
    begin
    if FBackSort then    // Обратная сортировка
    Compare := AnsiCompareText(Item2.Caption,Item1.Caption)
    else                 // Прямая сортировка
    Compare := AnsiCompareText(Item1.Caption,Item2.Caption);
    end;
    end;
    То, по всей видимости "будет Вам счясте"... B)
     
  5. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Работает. Остались ещё два вопроса:
    1. Как запертить сортировку в пустой колонке
    2. При запуске программы отсортировать второй столбец автоматически, допустим от 99 до 0
     
  6. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    :KillMe:
    1.
    Код (Delphi):
    ...
    implementation

    {$R *.dfm}
    function ColumnEmpty(LV: TListView; ColNo: Integer): Boolean;
    var
    i: Integer;
    begin
    Result := True;
    if (ColNo < 0) then
    Exit;

    if (ColNo > 0) then
    begin
    Dec(ColNo);
    for i := 0 to LV.Items.Count-1 do
    if (Trim(LV.Items[i].SubItems[ColNo]) <> '') then
    begin
    Result := False;
    Break;
    end;
    end
    else
    begin
    for i := 0 to LV.Items.Count-1 do
    if (Trim(LV.Items[i].Caption) <> '') then
    begin
    Result := False;
    Break;
    end;
    end;
    end;

    ...

    procedure TForm1.ListView1ColumnClick(Sender: TObject;
    Column: TListColumn);
    begin
    if (FSortKey = Column.Index) then // Если это та же самая колонка - меняем направление сортировки
    FBackSort := not FBackSort
    else                             // иначе - прямая сортировка
    FBackSort := False;

    FSortKey := Column.Index;

    if not ColumnEmpty(ListView1,FSortKey) then // если не пустая - сортируем
    ListView1.AlphaSort;
    else
    FSortKey := -1;
    end;
    2.
    Код (Delphi):
    ...
    FSortKey := 1;   // 2-я колонка
    FBackSort := True; // Обратная сортировка

    if not ColumnEmpty(ListView1,FSortKey) then // если не пустая - сортируем
    ListView1.AlphaSort;
    else
    FSortKey := -1;
     
  7. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Странно, но при клике на столбце, который полностью пустой возникает ошибка на строке List index out of bounds (3)
    Код (Delphi):
     if not ColumnEmpty(ListView1,FSortKey) then ListView1.AlphaSort // если не пустая - сортируем
    Видимо в функции ошибка есть.
     
  8. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    :KillMe: :KillMe: :KillMe:
    Нет. Видимо у некоторых Ваших айтемсов меньше субайтемсов чем (<кол-во колонок>-1 )
    А посему надо "ручками" добавлять недостающее количество пустых субайтемсов,
    либо отказаться сортировать за пределами "корректной ширины" таблички:
    Код (Delphi):
    function ColumnEmpty(LV: TListView; ColNo: Integer): Boolean;
    var
    i: Integer;
    begin
    Result := True;
    if (ColNo < 0) then
    Exit;

    if (ColNo > 0) then
    begin
    Dec(ColNo);

    // Проверяем - А достаточно ли у данного айтема субайтемсов
    // чтобы можно было сортировать?

    for i := 0 to LV.Items.Count-1 do
    if (ColNo >= LV.Items[i].SubItems.Count) then
    Exit;

    for i := 0 to LV.Items.Count-1 do
    if (Trim(LV.Items[i].SubItems[ColNo]) <> '') then
    begin
    Result := False;
    Break;
    end;
    end
    else
    begin
    for i := 0 to LV.Items.Count-1 do
    if (Trim(LV.Items[i].Caption) <> '') then
    begin
    Result := False;
    Break;
    end;
    end;
    end;
    Может сразу уж прогу всю за вас написать? :)
    Я кстати TListView для "комбинированных" таблиц никогда не стал бы использовать...
     
  9. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Здесь я сам :KillMe:
    Возможно тоже бы не стал этого делать, но вынудили обстоятельства
    Заинтересовало, как заставить определённую строку, например |неизвестен| при любом направлении сортировки держать в самом внизу списка. Это строка имеет значение только в одной колонке (самая первая колонка) все остальные пустые.
     
  10. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Этож элементарно
    Код (Delphi):
    ...
    if (Item2.Caption = '|неизвестен|') then
    Compare := -1
    else if (Item1.Caption = '|неизвестен|') then
    Compare := 1
    else if FBackSort then   // Обратная сортировка
    Compare := AnsiCompareText(Item2.Caption,Item1.Caption)
    else                 // Прямая сортировка
    Compare := AnsiCompareText(Item1.Caption,Item2.Caption);
    ...
     
  11. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Видимо я где-то напортачил. Сортировка чисел снова стала -1, 0, 1, 11, 13, 2, 24, 26 вместо -1, 0, 1, 2, 11, 13, 24 и после того как три раза кликнешь по какой-либо колонке, то любая другая колонка будет отсортирована только после второго клика.
     

    Вложения:

    • Sort.rar
      Размер файла:
      6,2 КБ
      Просмотров:
      9
  12. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Код (Delphi):
    procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
    Data: Integer; var Compare: Integer);
    var
    N1, N2, SubItemInd: Integer;
    begin
    if (FSortKey > 0) then // Сортируем по субайтемсам
    begin
    SubItemInd := FSortKey -1;

    // Если удалось привести к числу - сортируем как числа
    if (TryStrToInt(Item1.SubItems[SubItemInd], N1) and TryStrToInt(Item2.SubItems[SubItemInd], N2)) then
    begin
    if FBackSort then Compare := N2 - N1 // Обратная сортировка
    else Compare := N1 - N2; // Прямая сортировка
    end
    else // Если к числу не приводится - сортируем как строки
    begin
    if FBackSort then Compare := AnsiCompareText(Item2.SubItems[SubItemInd], Item1.SubItems[SubItemInd]) // Обратная сортировка
    else Compare := AnsiCompareText(Item1.SubItems[SubItemInd], Item2.SubItems[SubItemInd]); // Прямая сортировка
    end;
    end
    else // Сортируем по капшену айтемса
    begin

    if FBackSort then Compare := AnsiCompareText(Item2.Caption, Item1.Caption) // Обратная сортировка
    else Compare := AnsiCompareText(Item1.Caption, Item2.Caption); // Прямая сортировка
    end;

    if (Item2.Caption = '< Новое подключение >') then Compare := -1
    else
    if (Item1.Caption = '< Новое подключение >') then Compare := 1
    (* !!!!!!! Лишний код !!!!!
    else
    if FBackSort then Compare := AnsiCompareText(Item2.Caption,Item1.Caption) // Обратная сортировка
    else Compare := AnsiCompareText(Item1.Caption,Item2.Caption); // Прямая сортировка
    *)


    end;
     
  13. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Спасибо за помощь. Получился хороший мануал по сортировке в ListView.
     
Загрузка...
Похожие Темы - Сортировка данных колонках
  1. susinmn
    Ответов:
    4
    Просмотров:
    2.652
  2. vera2014
    Ответов:
    0
    Просмотров:
    1.076
  3. Liori
    Ответов:
    2
    Просмотров:
    1.008
  4. FCDK
    Ответов:
    0
    Просмотров:
    1.267
  5. ленарано
    Ответов:
    1
    Просмотров:
    1.106

Поделиться этой страницей