Сортировка TListbox - максимумы и минимумы - PullRequest
1 голос
/ 10 сентября 2009

Хорошо, у меня есть TListBox, который иногда может вызываться для отображения 43 000 строк!

Я знаю, это вряд ли когда-нибудь имеет смысл, но это так.

Теперь вот текущая проблема:

Использование встроенного метода Sort с функцией обратного вызова Compare занимает почти вечность, как и многие минуты.

Поэтому я извлекаю строки из списка в простой старый динамический массив ShortStrintgs, выполняю QuickSort () для этого, и это занимает около трех секунд. В общем, я думаю!

Немного подумав, я вижу, что QuickSort перемещает все эти строки вокруг, в которых нет необходимости, поэтому я могу изменить код, просто перемещая указатели или индексы на строки, и, вуаля, сортировка намного Снова быстрее, забираю под секунду, чтобы отсортировать 43 000 предметов. Большая победа, да?

НО, теперь, если я сделаю LB.Items.Add () или LB.Items.Assign, чтобы переместить отсортированные строки в список, ЭТО займет около 30 секунд! Даже с BEgin / EndUpdate происходит. Если я прослеживаю код, то вижу множество вещей, происходящих с delete () Insert () INsertObject () и сообщениями Windows, которые летят без веской причины.

Мгновение показывает, что у меня есть все строки в LB.TStrings, мне просто нужно, чтобы они перетасовывались вокруг моего массива QuickSorted (). Это должно быть тривиально, просто перемещая некоторые указатели.

Но я не вижу видимого способа установки необработанных указателей TStringList. Нет, Exchange () действительно очень медленный.

Есть идеи, как мне добраться до строковых указателей TString? Это должно быть тривиально, но я не вижу этого.

Спасибо

George

Ответы [ 5 ]

5 голосов
/ 10 сентября 2009

Все эти сообщения на самом деле летают по очень веской причине. Там нет волшебной функции «показать, что в списке». Он должен взять содержимое списка, построить из него дерево, по одному элементу за раз, и отобразить, какая часть этого дерева попадает в ClientRect визуального элемента управления. Ваша техника внешнего списка строк звучит как самая быстрая вещь, которую вы собираетесь получить.

Если вы хотите повысить производительность, попробуйте взглянуть на более быстрый список. Я слышал, что Virtual TreeView невероятно быстр при добавлении больших партий новых предметов, хотя я не могу порекомендовать его, так как я не использовал его и сам тестировал. Но вы, возможно, захотите взглянуть и посмотреть, подходит ли он вашим потребностям лучше, чем ваши существующие настройки.

4 голосов
/ 10 сентября 2009

Вы пытались установить TListBox.Style в lbVirtual? Затем список запрашивает данные в событии OnData ()

см. http://www.delphi3000.com/articles/article_3761.asp?SK=

1 голос
/ 10 сентября 2009

Попробуйте Виртуальное дерево . Я знаю, что это не список, и он немного сложнее, чем tlistbox, но он может действовать как TListBox (или tlistview / ttreeview) и работает намного быстрее, чем стандартный tlistbox / tlistview / ttreeview (он может добавить 1000000 элементов за 125 мс)

1 голос
/ 10 сентября 2009

Еще один метод, который вы можете использовать (я сам успешно его использовал), чтобы ускорить процесс, - это остановить приложение для перерисовки элементов управления, копирования списка во второй TStringList, сортировки этого TStringList и копирования обратно. Ключом к остановке перерисовки является команда как таковая:

SendMessage(Application.Handle, WM_SETREDRAW, 0, 0);

Первый 0 указывает приложению прекратить рисование в окне, поэтому все эти сообщения немедленно удаляются, и приложение может двигаться намного быстрее. Когда будете готовы перерисовать экран, просто поменяйте местами первые 0 на 1, а затем вызовите

RedrawWindow(Application.Handle, nil, 0, [Options])

вызвать немедленную перерисовку всего.

0 голосов
/ 10 сентября 2009

Чтобы отключить обновление элемента управления списком при переупорядочении строк, используйте BeginUpdate / EndUpdate:

ListBox.Items.BeginUpdate;
try
  // your sorting here...
finally
  ListBox.Items.EndUpdate;
end;

Редактировать: Вы также можете попробовать виртуальный стиль (Style = lbVirtual, установить свойство Count и обработать событие OnData).

...