Как быстро добавить много строк в TStringGrid?

Я гуглил и нашел много советов, но все это казалось несколько лет назад, и ничего из этого не помогло.

У меня есть строковая сетка с 8 столбцами, и как только я получаю более нескольких сотен строк, для заполнения требуется более 2 секунд (я сравнивал с помощью GetTickCount).

Я попробовал StringGrid.Perform(WM_SETREDRAW, 0, 0)0, 1 в конце). Я попытался установить Visible := False во время обновления. Оба бесполезны.

BeginUpdate() метода нет.

Любой совет? Стартер Delphi XE2. Я был бы готов использовать сетку строк VCL сторонних производителей FOSS, если она будет опробована и протестирована.


[Обновление] с использованием TDrawGrid ... «TDrawGrid не имеет свойства «Ячейки», как его брат TStringGrid. Ваш код должен вычислить, где отображать данные, а затем он должен нарисовать представление данных на «холсте». «из сетки».

Это звучит как много работы для меня :-(

Использование VirtualTreeView - звучит нормально, если оно достаточно быстрое. У меня просто не будет дочерних узлов. (update++ Я только что прочитал это на домашней странице "Virtual Treeview is чрезвычайно быстро. Добавление одного миллиона узлов занимает всего 700 миллисекунд"). Тогда проблем со скоростью не будет. Но было бы неплохо просто использовать сетку строк. Особенно тот, где пользователь может щелкнуть и отсортировать.

В качестве альтернативы, stringgrid имеет высоту всего 20 строк. Может быть, я мог бы просто обрабатывать щелчки полосы прокрутки и очищать и повторно заполнять эти 20 строк, когда пользователь прокручивает?

[Дальнейшее обновление] Я перешел с TStringGrid на TListView, в коде которого есть Beginupdate()), но это имело незначительное значение. Опс, забыл "виртуальный режим" - брб.

Кстати, данные доступны только для чтения, только для отображения.

Наверняка это очень распространенная проблема?


person Mawg says reinstate Monica    schedule 12.10.2012    source источник
comment
Наилучшая производительность будет достигнута путем изменения вашего TStringGrid на виртуальную сетку, например. TDrawGrid в виртуальном режиме, который будет извлекать содержимое ячеек через событие из отдельного списка данных. Это будет намного быстрее, чем это ИМХО. Я использую TDrawGrid с тысячами строк с мгновенным доступом, например. для нашего средства просмотра журналов — например, 280 Файл журнала МБ открывается менее чем за одну секунду на моем ноутбуке. В Seven для отображения диалогового окна «Открыть файл» требуется больше времени, чем для чтения и индексации содержимого размером 280 МБ.   -  person Arnaud Bouchez    schedule 12.10.2012
comment
+1 @ArnaudBouchez Звучит превосходно. Я пойду и погуглю, как TDrawGrid в виртуальном режиме будет извлекать содержимое ячеек через событие из отдельного списка данных. Спасибо   -  person Mawg says reinstate Monica    schedule 12.10.2012
comment
Вместо TDrawGrid вы можете изучить VirtualTreeView. Это не просто древовидное представление, как может показаться ;-)   -  person TLama    schedule 12.10.2012
comment
@TLama Я понимаю, что могу использовать VirtualTreeView без дочерних узлов, но даст ли это мне желаемую производительность?   -  person Mawg says reinstate Monica    schedule 12.10.2012
comment
Каждый элемент управления, использующий виртуальный режим, даст вам лучшую производительность, чем TStringGrid. Невозможно сравнивать TDrawGrid с VirtualTreeView только потому, что они выглядят по-разному, но оба будут более эффективными, чем TStringGrid, это точно. Я предложил вам VirtualTreeView исходя из своих личных предпочтений и потому, что вы можете делать гораздо больше вещей, чем с TDrawGrid. Но если вам действительно нужна просто старая сетка с очень простой функциональностью, TDrawGrid может быть для вас достаточно.   -  person TLama    schedule 12.10.2012
comment
На ваше обновление щелкните и отсортируйте: VirtualTreeView x TDrawGrid оценка 1:0.   -  person TLama    schedule 12.10.2012
comment
@Mawg, не могли бы вы рассказать нам, для какой цели вы используете TStringGrid в этом случае - для отображения или редактирования данных? Если вам нужно только отображать данные, то даже TListView должен дать вам более чем достаточный прирост производительности, а если вы будете использовать его в виртуальном режиме, то выиграете еще больше. Тем не менее, я должен согласиться с @TLama по поводу VirtualTreeView - это просто лучший компонент. Я давно перестал использовать TStringGrid и никогда не оглядывался назад.   -  person LightBulb    schedule 12.10.2012
comment
В ответ на ваше редактирование: размещение данных в наборе данных клиента памяти и отображение их с помощью DBGrid, которое «загружает» только видимые строки, также может работать лучше.   -  person NGLN    schedule 12.10.2012
comment
+1 он только для чтения, отображает данные. Как использовать TListView в виртуальном режиме? ПОДОЖДИТЕ... DBGrid, который "загружает" только видимые строки, может также лучше работать МОЖЕТ лучше работать?? Нужно будет загрузить только 20 строк, а не 700. Я должен изучить это. Спасибо   -  person Mawg says reinstate Monica    schedule 12.10.2012
comment
@Mawg, я использовал TListView (в обычном режиме) с тысячами строк и никогда не замечал проблем с производительностью. Вы должны проверить две вещи: во-первых, как вы получаете отображаемые данные, а во-вторых, как вы вставляете данные в файл TListView. Оба они могут быть узким местом, поэтому я советую вам пересмотреть свой код. Если вы можете, обновите свой вопрос с помощью кода, который вы используете для вставки данных, чтобы мы могли оказать дополнительную помощь.   -  person LightBulb    schedule 12.10.2012
comment
@NGLN «помещает данные в набор данных клиента памяти и показывает их с помощью DBGrid, который «загружает» только видимые строки, — это надежно. Если вы опубликуете это как ответ, я награжу. Спасибо!   -  person Mawg says reinstate Monica    schedule 12.10.2012
comment
Я не думаю, что TStringGrid сильно изменился за последние несколько лет, за исключением стилей VCL.   -  person Jerry Dodge    schedule 12.10.2012
comment
@Mawg: Как использовать TListView в виртуальном режиме? Установите для его свойства OwnerData значение True и используйте его событие OnData для предоставления значений TListView, когда он их запрашивает. Храните ваши данные в памяти где угодно и как угодно. Если вам нужно реализовать более продвинутое кэширование, чтобы у вас не было всех данных в памяти одновременно, используйте событие OnDataHint, чтобы помочь вам сохранить в памяти только те данные, которые действительно нужны TListView в любой момент, и отбросить память для данных, которые ему не нужны. Я использую этот подход для отображения миллионов записей, и он работает очень хорошо.   -  person Remy Lebeau    schedule 13.10.2012


Ответы (3)


Добавляя к другим, предлагающим виртуальную сетку строк, я хотел бы подключить TdzVirtualStringGrid, которая строится на TDrawGrid и добавляет события для возврата строк для отображения. Я использую его для очень «больших» сеток, и он отлично работает.

Загрузите его здесь.

(Вам нужно больше файлов из того же репозитория, это просто исходный код основного компонента.)

РЕДАКТИРОВАТЬ: Под «больше файлов из того же репозитория» я имею в виду, что этот компонент использует другие модули из библиотеки dzlib, поэтому вам, вероятно, следует проверить весь шебанг и либо добавить его в путь поиска вашей программы (есть гораздо больше полезного вещи там, потому что я добавляю к нему всякий раз, когда сталкиваюсь с чем-то, что требует более общего решения) или просто извлекаю те единицы, от которых зависит компонент. dzlib находится под лицензией MPL.

person dummzeuch    schedule 12.10.2012
comment
+1 @dummzeuch Плюс еще за объяснение того, что нужно дополнительно ;-) - person Mawg says reinstate Monica; 12.10.2012
comment
вы получите ответ, если объясните больше файлов из того же репозитория - person Mawg says reinstate Monica; 13.10.2012

Добавьте строки снизу вверх и/или установите RowCount после этого. Я только что сделал небольшой тест, добавив 90 000 строк, получив ок. 25% в скорости.

Хотя это занимает максимум 1,5 секунды. Поскольку вы говорите всего о нескольких сотнях строк, я уверен, что заполнение сетки здесь не является проблемой. Вместо этого кажется, что время, необходимое для извлечения и/или преобразования данных.

person NGLN    schedule 12.10.2012
comment
@Mawg Тогда необходимое время уменьшается более чем на 50%: скорость увеличивается более чем вдвое. - person NGLN; 14.10.2012

BeginUpdate() метода нет.

TStringGrid имеет BeginUpdates: вам нужно получить к нему доступ через массивы Rows[] или Cols[] массива TStrings, хотя для добавления новых данных наиболее целесообразно использовать массив Cols[]:

for i := 0 to Grid.ColCount - 1 do
begin
  Grid.Cols[i].BeginUpdate;
  try
    //Add row data
    for j := 1 to Grid.RowCount - 1 do
      Grid.Cols[i][j] := ...;
  finally  
    Grid.Cols[i].EndUpdate;
  end;
end;

Я уверен, что использовал это раньше с отмеченным увеличением скорости.

person Matt Allwood    schedule 12.10.2012
comment
Rows и Cols являются индексируемыми свойствами и не дают доступа ни к BeginUpdate, ни к EndUpdate. Однако заполнение сетки не является проблемой. - person NGLN; 12.10.2012
comment
cols - это просто массив TStrings, и каждый элемент этого массива имеет BeginUpdate/EndUpdate for i:= 0 to grid.colcount-1 do grid.cols[i].beginupdate с соответствующим try..finally - person Matt Allwood; 12.10.2012
comment
+1 Это действительно ускоряет процесс! Извините, что не понял с первого раза. - person NGLN; 12.10.2012