Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Сортировка ListView


Автор: kovalenko123 12.12.2009, 11:18
Всем привет я понимаю что тема уже стара как мир но обнаружился какой то странный косяк в сортирвке listview

при закидывании записей в listview (через DragADrop) записи естественно не упорядочиваются при нажитии на header в LV  записи сортируються  (не без помощи функций конечно) но получаеться совсем не то что нужно (а нужно сортировка по возврастанию) 
вот пример 
user posted image
Это уже после сортировки а по идеи должна быть от 2 до 17
подскажите пожалуйста что можно сделать 



Автор: THandle 12.12.2009, 11:52
kovalenko123, у тебя происходит сортировка строк по убыванию.

Символ '9' больше чем символа '1'.

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

Автор: kovalenko123 12.12.2009, 14:32
THandle
Цитата

у тебя происходит сортировка строк по убыванию

так тогда бы начиналось бы все с 17 (17 , 16 , 15 и т д ) а тут с 9-2 потом начинаеться 17  smile 
 
Цитата

из каждой строки вынимает это число

Откровенно говоря не совсем понял это высказывание 





Автор: THandle 12.12.2009, 15:11
Цитата(kovalenko123 @  12.12.2009,  14:32 Найти цитируемый пост)
так тогда бы начиналось бы все с 17 (17 , 16 , 15 и т д ) а тут с 9-2 потом начинаеться 17  smile 


Нет. Так бы было если бы сортировал числа, а не строки. Тут же сортировка идет по коду символа. То есть Ord('9') > Ord('1').

Чтобы получить нужный тебе результат, тебе в коде функции сортировки надо сравнивать не строчки LV, а вынутые из этих строк числа(1...17).

Напиши для этого "вынимания" функцию типа:

Код

function Compare(const AStr: String): Integer;
begin
  { А тут вынимаем из строчки AStr это число и присваиваем его Result. Можно сделать с помощью Pos, Copy, StrToInt }
end;


В параметр AStr передавай каждую строчку из столбца "Название". В результате должно возвращаться число из скобочек. Вот эти числа и нужно сравнивать в сортировке, когда переставляешь элементы.

Попробуй сам это сделать. Если не получится - дай свою функцию сортировки, попробуем её изменить вместе. smile

Автор: kovalenko123 12.12.2009, 15:58
Дело в том что если я сделаю как вы предложили
Цитата

надо сравнивать не строчки LV, а вынутые из этих строк числа(1...17)

то в случае другого примере она может не сработать Иногда моя работает правильно. я тут одну ссылочку отыскал может она пригодиться http://articles.org.ru/docum/sort.php
там общие принцпиы сортировки может и для моего тяжелого случая подойдет

Автор: amsoft 12.12.2009, 16:04
kovalenko123, 

для затравки:

в строках ищи положение символов '[' и ']' с помощью функции Pos и исходя из их значений выдергивай строку между ними через Copy,
преобразовывай в число и сравнивай  smile 

Автор: kovalenko123 12.12.2009, 16:12
amsoft 
а если их не будет этих символов?  smile 

Автор: amsoft 12.12.2009, 16:15
kovalenko123, 
как я вижу по примеру они есть  smile 

Автор: kovalenko123 12.12.2009, 16:27
amsoft 
Это был просто пример я щас могу таких пример с десяток наскринить 
щас попробую реализовать то что предложил THandle

Код

function CustomNameSortProc(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall;
begin
Result := CompareText(Item1.Caption,Item2.Caption);
end;

procedure Tmain.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
try
if column =ListView1.columns[0] then
 ListView1.CustomSort(@CustomNameSortProc, 0);
 except
 end;
end;


Вот функция для сортировки

Автор: amsoft 12.12.2009, 16:38
тогда сравнивай по каждому символу, если символ - цифра, то сравнивай число, если нет - сравнивай код символа

Автор: kovalenko123 12.12.2009, 17:08
amsoft
А можно какой нить кодовый пример на эту тему? 

Автор: amsoft 12.12.2009, 18:02
1. (на всякий случай) код символа определяется по функции Ord()

2. Вопрос: у тебя наименования имеют один формат:

abcd1234
abcd1234
...

или же в некоторых случаях кол-во букв перед цифрами разное:

abcd1234
abc1234
a1234
...

?

Автор: kovalenko123 13.12.2009, 07:32
amsoft
К сожалению определенного правила формата нету так что может быть и как в 1 случае так и во втором но точно могу сказать что одна цифра будет например

abcd1.pdf
abcd2.pdf
abcd3.pdf

либо все доки будут начинаться с цифры например

1abcd.pdf
2abcd.pdf
3abcd.pdf

Автор: amsoft 13.12.2009, 07:34
Код

procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
var
S1,S2,S1Int,S2Int: string;
begin
S1 := Item1.Caption;
S2 := Item2.Caption;
Compare := 0;
while Compare = 0 do
      begin
      if ((S1 = '') and (S2 = '')) then Exit;
      if S1 = ''
      then begin
           Compare := -1;
           Exit;
           end;
      if S2 = ''
      then begin
           Compare := 1;
           Exit;
           end;
      if ((Ord(S1[1]) in [48..57]) and (Ord(S2[1]) in [48..57]))
      then begin
           S1Int := '';
           while (Ord(S1[1]) in [48..57]) do
                 begin
                 S1Int := S1Int + S1[1];
                 S1 := Copy(S1,2,Length(S1));
                 if S1 = '' then Break;
                 end;
           S2Int := '';
           while (Ord(S2[1]) in [48..57]) do
                 begin
                 S2Int := S2Int + S2[1];
                 S2 := Copy(S2,2,Length(S2));
                 if S2 = '' then Break;
                 end;
           Compare := StrToInt(S1Int) - StrToInt(S2Int);
           end
      else begin
           Compare := Ord(S1[1]) - Ord(S2[1]);
           S1 := Copy(S1,2,Length(S1));
           S2 := Copy(S2,2,Length(S2));
           end;
      end;
end;


ЗЫ Здесь я сравниваю только Caption, если надо по другим столбцам, то можешь подкорректировать в самом начале.
ЗЗЫ Сортировка идет по возрастанию

Автор: kovalenko123 13.12.2009, 11:13
amsoft и THandle Спасибо Вам с задачей справился следующим образом

Код

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;

procedure Tmain.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
    Sort := -Sort;
if Column = ListView1.Columns[0] then
  ListView1.CustomSort( @SortCaptionAsString, Sort);
end;


результат в принципе устраевает тока вот с 10 все равно проблемы а со всем остальным нормально но ниче DAD подвинет куда надо будет эту 10  smile 

Успехов ВАМ!

Автор: kovalenko123 14.12.2009, 18:00
блин ребята, седня еще раз проверил нифига она не работает как надо там косяк если есть строк с номерками больше 9
десятка идет после 1 (( что можно сделать?

Автор: amsoft 14.12.2009, 19:12
kovalenko123, я же написал процедуру по сортировке 2 поста назад

Автор: kovalenko123 15.12.2009, 05:51
amsoft
так она не работает  smile 

Автор: amsoft 15.12.2009, 06:49
kovalenko123, у меня все работает

Чтобы убедиться в работоспособности кода, закинь его в событие ListView1Compare
Создай кнопку и повесь код на OnClick:

Код

Listview1.AlphaSort;


Все сортирует как надо  smile 


Автор: amsoft 15.12.2009, 07:11
вот результат:
user posted image

Автор: kovalenko123 15.12.2009, 07:45
amsoft
 smile Огромное спасибо все работает!
 smile 
буду в Астане с меня пиво smile 

Автор: amsoft 15.12.2009, 07:58
kovalenko123, договорились smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)