Сортировка максимумов и минимумов TListbox

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

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

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

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

Итак, я извлекаю строки из списка в простой старый динамический массив ShortStrings, выполняю для него QuickSort(), и это занимает около трех секунд. Ура я думаю!

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

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

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

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

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

Спасибо,

Джордж


person Community    schedule 10.09.2009    source источник
comment
И нельзя перевернуть все с ног на голову и использовать массив для строк и что-то вроде TVirtualListbox для представления?   -  person Vegar    schedule 10.09.2009
comment
Ничего себе, я только что погуглил, и да, это похоже на отличное решение! (В качестве временного клада я просто сохраняю индексы сортировки и использую их в качестве руководства относительно того, какую строку рисовать в методе drawitem).   -  person    schedule 10.09.2009


Ответы (5)


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

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

person Mason Wheeler    schedule 10.09.2009
comment
Почему TListbox строит тройку? - person Vegar; 10.09.2009
comment
Спасибо, но я уже делаю BeginUpdate, чтобы отключить все обновления дисплея. И это TListBox, а не дерево, поэтому VirtualTreeView не подходит (хотя, думаю, у меня могло бы быть действительно ПЛОСКОЕ дерево :) Спасибо. - person ; 10.09.2009
comment
Поле со списком функционирует как действительно плоское дерево внутри, потому что его узлы данных имеют ссылки в двух направлениях: вниз, к следующему элементу, и вправо, к подэлементам (если они есть). - person Mason Wheeler; 10.09.2009

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

см. http://www.delphi3000.com/articles/article_3761

person jasonpenny    schedule 10.09.2009
comment
+1 Это, безусловно, лучшее решение, если вы хотите придерживаться стандартных элементов управления VCL. Это очень быстро, а в виртуальном режиме намного проще синхронизировать вашу модель в памяти и графический интерфейс. - person Wouter van Nifterick; 12.09.2009

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

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

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

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

, чтобы немедленно перерисовать все.

person Tom A    schedule 10.09.2009

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

person bmeric    schedule 10.09.2009
comment
+1. Вы можете легко настроить VirtualTreeView так, чтобы он выглядел и вел себя точно так же, как список, для пользователя, а также избавил вас от необходимости добавлять элементы в виртуальный список, поскольку они уже есть в списке, просто установите для rootnodecount количество в вашем list и используйте функцию GetText для прямого извлечения из списка. - person skamradt; 10.09.2009

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

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

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

person Ondrej Kelle    schedule 10.09.2009
comment
Согласно ОП, он уже сделал это, и у него все еще есть проблемы с этим. - person Mason Wheeler; 10.09.2009
comment
Сделал это, как я упоминал в вопросе. Не очень помогло. Спасибо, в любом случае. - person ; 10.09.2009
comment
Прошу прощения, я пропустил эту часть. Отредактировал ответ, чтобы также предложить виртуальный стиль. - person Ondrej Kelle; 10.09.2009