Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: IUnknown от Май 06, 2005, 13:52



Название: Виртуальный QListView
Отправлено: IUnknown от Май 06, 2005, 13:52
Как реализовать виртуальный список для обработки огромного количества данных?


Название: Виртуальный QListView
Отправлено: Admin от Май 06, 2005, 14:51
поподробнее что значит обработка
что значит огромного?


Название: Виртуальный QListView
Отправлено: ANM от Май 06, 2005, 15:47
QListView отображает некий набор данных, обычно копия отображаемых данных хранится в самом QListView. Но если объем данных очень большой то держать копию данных в QListView нерационально. В LISTVIEW из Common Controls для этого есть режим виртуального списка, при работе в котором данные не хранятся в ListView, а сам ListView делает запрос к внешнему источнику данных когда эти данные ему нужно отобразить.
Это должно быть по идее, как же без этого...


Название: Виртуальный QListView
Отправлено: IUnknown от Май 06, 2005, 18:04
Конечно должно быть! Только мне интересно как этого добится?! В винде все понятно LVS_OWNERDATA да LVN_GETDISPINFO и виртуальность готова. Помогите если кто знает, а то уж слишком долго грузится список. Заранее благодарен.


Название: Виртуальный QListView
Отправлено: IUnknown от Май 06, 2005, 22:36
Копнул англоязычные ресурсы и понял что стандартного способа НЕТ (может плохо копал), а реализовать виртуальность нужно самому с самого начала. Есть какой-то бедненький пример с QTable, но с него толку мало. Вывод - мелкософт РУЛИТ!!


Название: Виртуальный QListView
Отправлено: Ruslan Popov от Май 07, 2005, 09:21
Твой вопрос подробно описан в одном из ежеквартальников Qt. Есть специальные обработчики у QListView, вешаешь на них подкачку данных в QListView и всё работает. Только не говори, что в WinAPI - это автоматически делается :)

updated
поискал, не нашел... но где-то видел готовый пример...

updated
Нашел! Тебе надо посмотреть в сторону QScrollView:
The contentsMoving() signal is emitted just before the contents are moved to a new position.
В обработчике этого сигнала, надо реализовать замену данных в QListView, будет всё быстро!


Название: Виртуальный QListView
Отправлено: ANM от Май 07, 2005, 14:58
Код:
void QScrollView::contentsMoving ( int x, int y ) [signal] 
This signal is emitted just before the contents are moved to position (x, y).

Это слишком низкоуровневое событие. LISTVIEW из commctl вызывает callback когда ему нужны данные для изображения элемента списка.
В параметрах callback он передает номер элемента списка по которому он запрашивает данные.
Возможно QTable реализует подобную функциональность.
Цитировать
Large tables
For large, sparse, tables using QTableItems or other widgets is inefficient. The solution is to draw the cell as it should appear and to create and destroy cell editors on demand.
This approach requires that you reimplement various functions. Reimplement paintCell() to display your data, and createEditor() and setCellContentFromEditor() to support in-place editing. It is very important to reimplement resizeData() to have no functionality, to prevent QTable from attempting to create a huge array. You will also need to reimplement item(), setItem(), takeItem(), clearCell(), and insertWidget(), cellWidget() and clearCellWidget(). In almost every circumstance (for sorting, removing and inserting columns and rows, etc.), you also need to reimplement swapRows(), swapCells() and swapColumns(), including header handling.
If you represent active cells with a dictionary of QTableItems and QWidgets, i.e. only store references to cells that are actually used, many of the functions can be implemented with a single line of code. (See the table/bigtable/main.cpp example.)
For more information on cells see the QTableItem documenation.

Правда заставляют самостоятельно рисовать элементы. И перехватить нужно кучу сигналов.


Название: Виртуальный QListView
Отправлено: IUnknown от Май 07, 2005, 23:40
А примера готового нету?


Название: Виртуальный QListView
Отправлено: ANM от Май 11, 2005, 10:21
Пример есть в qt - C:\Qt\3.3.4\examples\table\bigtable.
Код:

const int numRows = 1000000;
const int numCols = 1000000;

class MyTable : public QTable
{
public:
    MyTable( int r, int c ) : QTable( r, c ) {
items.setAutoDelete( TRUE );
widgets.setAutoDelete( TRUE );
setCaption( tr( "A 1 Million x 1 Million Cell Table" ) );
setLeftMargin( fontMetrics().width( "W999999W" ) );
    }

    void resizeData( int ) {}
    QTableItem *item( int r, int c ) const { return items.find( indexOf( r, c ) ); }
    void setItem( int r, int c, QTableItem *i ) { items.replace( indexOf( r, c ), i ); }
    void clearCell( int r, int c ) { items.remove( indexOf( r, c ) ); }
    void takeItem( QTableItem *item )
    {
items.setAutoDelete( FALSE );
items.remove( indexOf( item->row(), item->col() ) );
items.setAutoDelete( TRUE );
    }
    void insertWidget( int r, int c, QWidget *w ) { widgets.replace( indexOf( r, c ), w );  }
    QWidget *cellWidget( int r, int c ) const { return widgets.find( indexOf( r, c ) ); }
    void clearCellWidget( int r, int c )
    {
QWidget *w = widgets.take( indexOf( r, c ) );
if ( w )
   w->deleteLater();
    }

private:
    QIntDict<QTableItem> items;
    QIntDict<QWidget> widgets;

};

Насколько я понял, в этом примере оптимизация для разряженной таблицы, т.е. реально хранятся только те ячейки значения для которых были введены.
Лично мне нужна виртуальность в смысле редактирования и отображения данных в таблице. QT это позволяет делать, ну а если QT хочет хранить на каждую ячейку наследника от QTableItem и от QWidget то меня это устраивает.
Если виртуальность нужна для действительно больших таблиц то наверное лучше воспользоваться QDataTable и QDataView.


Название: Виртуальный QListView
Отправлено: Kostya. от Май 11, 2005, 11:37
Я наверно чего-то не так понял, но можно и не хранить копию данных в ListView. Достаточно отнаследоваться от QListViewItem и переопределить функцию text(), в результате имеем тоже что и если бы вызывались GETDISPINFO и т.д.

P.S. Кстати медленное заполнение ListView может быть связано с тем что данные в список добавляются не в конец, а в начало. И поэтому он постоянно перерисовывается.


Название: Виртуальный QListView
Отправлено: ANM от Май 11, 2005, 12:04
Не все так просто при таком подходе :D Текст действительно в QListViewItem хранится не будет. Но объекты QListViewItem будут созданы для каждого элемента в QListView. Допустим кол-во строк в таблице 100 000, следовательно как минимум столько же объектов QListViewItem будет создано. LISTVIEW (commctl) может не хранить никакой информации об отображаемых элементах, он запоминает только общее кол-во элементов в таблице для того чтобы правильно рисовать скроллбар.


Название: Виртуальный QListView
Отправлено: Kostya. от Май 11, 2005, 12:35
Цитата: "ANM"
Не все так просто при таком подходе :D Текст действительно в QListViewItem хранится не будет. Но объекты QListViewItem будут созданы для каждого элемента в QListView. Допустим кол-во строк в таблице 100 000, следовательно как минимум столько же объектов QListViewItem будет создано. LISTVIEW (commctl) может не хранить никакой информации об отображаемых элементах, он запоминает только общее кол-во элементов в таблице для того чтобы правильно рисовать скроллбар.


Постойте, но ведь при LVN_GETDISPINFO в параметре NMHDR*
хранится некая информация (LVITEM), т.е. Значит это не просто количество элементов, а некое описание каждого элемента, т.е. грубо говоря тот же QListViewItem.

Чем плохо что будет создано 100 000 QListViewItem?


Название: Виртуальный QListView
Отправлено: ANM от Май 11, 2005, 13:09
Наоборот, эту структуру должен заполнить пользователь LISTVIEW :).
Цитировать

Parameters
Address of an NMLVDISPINFO structure. On input, the LVITEM structure contained in this structure specifies the type of information required and identifies the item or subitem of interest. Use the LVITEM structure to return the requested information to the control.


Ну и подробнее о LISTVIEW:

Цитировать
A virtual list view is a list-view control that has the LVS_OWNERDATA style. This style enables the control to handle millions of items because the owner receives the burden of managing item data. This allows you to use the virtual list-view control with large databases of information, where specific methods of data access are already in place.

A virtual list-view control maintains very little item information itself. Except for the item selection and focus information, the owner of the control must manage all item information. Other processes request item information from the owner by using LVN_GETDISPINFO notification messages.


Полного аналога в QT этому контролу по видимому нет.
Можно использовать QDataTable QDataView но они завязаны на БД.
А если ты лог захошешь выводишь в файл и заодно отображать его в своей программе и кол-во записей в логе может быть ~1000000, то QListView наверное не поможет.


Название: Виртуальный QListView
Отправлено: Kostya. от Май 11, 2005, 13:42
Цитата: "ANM"
Наоборот, эту структуру должен заполнить пользователь LISTVIEW :).


Правильно, но не всю.
Цитата: "ANM"

Цитировать

Parameters
Address of an NMLVDISPINFO structure. On input, the LVITEM structure contained in this structure specifies the type of information required and identifies the item or subitem of interest. Use the LVITEM structure to return the requested information to the control.


Значит всетаки не просто количество записей, присутствует еще и описание записи.
Цитата: "ANM"

Ну и подробнее о LISTVIEW:

Цитировать
A virtual list view is a list-view control that has the LVS_OWNERDATA style. This style enables the control to handle millions of items because the owner receives the burden of managing item data. This allows you to use the virtual list-view control with large databases of information, where specific methods of data access are already in place.

A virtual list-view control maintains very little item information itself. Except for the item selection and focus information, the owner of the control must manage all item information. Other processes request item information from the owner by using LVN_GETDISPINFO notification messages.


Полного аналога в QT этому контролу по видимому нет.
Можно использовать QDataTable QDataView но они завязаны на БД.
А если ты лог захошешь выводишь в файл и заодно отображать его в своей программе и кол-во записей в логе может быть ~1000000, то QListView наверное не поможет.


Только вот я не могу понять почему QListViewItem не может или не выполняет функцию LVITEM? Там же тоже храниться минимум описания записи. Всю остальную информацию ты можешь выдавать ему сам.
Почему вы считаете что LVITEM != QListViewItem?


Название: Виртуальный QListView
Отправлено: ANM от Май 11, 2005, 16:33
Потому что sizeof(QListViewItem) = 44, слишком дорого для одной записи. А LISTVIEW на самом деле не хранит никакой информации записях. Объясню почему:
Цитировать
virtual list-view control maintains very little item information itself. Except for the item selection and focus information, the owner of the control must manage all item information.

Размер информации о фокусе это sizeof(int), только одна запись имеет фокус. Информация о выбранных пользователем записях имеет динамический изменяющийся размер,и если нет выбранных записей то и размер равен 0. Как это сделано? Очень просто - связанный список например.
Итог: QListView обязательно расходует 44 байта на каждую запись, LISTVIEW может вообще расходовать 0 байт на запись если одновременно разрешено выбирать только одну запись.


Название: Виртуальный QListView
Отправлено: IUnknown от Май 11, 2005, 20:52
Мне действительно очеь надо реализовать виртуальный список под Unix и я остановил свой выбор на Qt, но так как с помощью этой библиотеки полноценной виртуальности реализовать не представляется возможным, может кто посоветует другую библиотеку где это делается без проблем, а то срочно нужно портировать виндосную прогу под FreeBSD.


Название: Виртуальный QListView
Отправлено: Kostya. от Май 12, 2005, 09:02
Цитата: "ANM"
Потому что sizeof(QListViewItem) = 44, слишком дорого для одной записи. А LISTVIEW на самом деле не хранит никакой информации записях. Объясню почему:
Цитировать
virtual list-view control maintains very little item information itself. Except for the item selection and focus information, the owner of the control must manage all item information.

Размер информации о фокусе это sizeof(int), только одна запись имеет фокус. Информация о выбранных пользователем записях имеет динамический изменяющийся размер,и если нет выбранных записей то и размер равен 0. Как это сделано? Очень просто - связанный список например.
Итог: QListView обязательно расходует 44 байта на каждую запись, LISTVIEW может вообще расходовать 0 байт на запись если одновременно разрешено выбирать только одну запись.


Я просто взял в тупую сделал sizeof(LVITEM), у меня получилось 40. Согласитесь что разница не большая.
Т.е. CListView обязательно расходует 40 байт на запись.
Почему вы фразу  "maintains very little item information " переводите как "вообще не расходует"?

То IUnknown: Что вы понимаете под полноценным виртуальным списком?


Название: Виртуальный QListView
Отправлено: ANM от Май 13, 2005, 10:17
Дело в том, что LVITEM не хранится в LISTVIEW, это структура просто часть интерфейса. Поэтому sizeof(LVITEM) может быть любым, даже большим чем  sizeof(QListViewItem).
В подтверждении моих слов я нашел пример: LISTVIEW отображающий 100 000 000 записей, после запуска программа потребляет всего 408 Кб оперативной памяти. Причем я пробовал изменять кол-во записей от 100 000 до 100 000 000, объем потребляемой памяти не менялся.
Программу можно взять здесь (http://ftp://195.112.96.114/tmp/vlistvw.zip) (исходные тексты + исполняемый файл).
Сможете сделать такой же пример, используя QListView? :wink:


Название: Виртуальный QListView
Отправлено: Racheengel от Май 13, 2005, 13:41
Может, контест проведем? :)))))))))))))))


Название: Виртуальный QListView
Отправлено: Kostya. от Май 13, 2005, 14:15
Цитата: "ANM"
Дело в том, что LVITEM не хранится в LISTVIEW, это структура просто часть интерфейса. Поэтому sizeof(LVITEM) может быть любым, даже большим чем  sizeof(QListViewItem).

В принципе конечно, возможно

Цитата: "ANM"

В подтверждении моих слов я нашел пример: LISTVIEW отображающий 100 000 000 записей, после запуска программа потребляет всего 408 Кб оперативной памяти. Причем я пробовал изменять кол-во записей от 100 000 до 100 000 000, объем потребляемой памяти не менялся.
Программу можно взять здесь (http://ftp://195.112.96.114/tmp/vlistvw.zip) (исходные тексты + исполняемый файл).
Сможете сделать такой же пример, используя QListView? :wink:


Это всеж таки немного не тот пример :). Т.к. число элементов известно заранее, что делать если число элементов не известно.

Кстати  откуда взялась цифра 406К. LISTVIEW, НЕ хранит все 10 000 000 в памяти, а подгружает их из кэша. Поэтому он и занимает постоянно 406К, даже если используется 1 элемент.
А отсюда, вы не можете делать вывод, что он не хранить всю структуру LVITEM


Название: Виртуальный QListView
Отправлено: ANM от Май 13, 2005, 16:48
Цитировать
Это всеж таки немного не тот пример . Т.к. число элементов известно заранее, что делать если число элементов не известно.

Разговор шел именно о выводе известного кол-ва элементов. Вывод неизвестного кол-ва элементов наверное будет выглядеть чуть по другому, например явно не нужно отображать скроллбар.
Цитировать

Кстати откуда взялась цифра 406К. LISTVIEW, НЕ хранит все 10 000 000 в памяти, а подгружает их из кэша. Поэтому он и занимает постоянно 406К, даже если используется 1 элемент.
А отсюда, вы не можете делать вывод, что он не хранить всю структуру LVITEM

А это не одно и тоже? Разговор шел о том что QListView обязательно создает QListViewItem на каждый элемент находящийся в таблице. LISTVIEW имеет режим виртуального вывода при котором LISTVIEW не хранит никакой информации связанной с элементом, а всю информацию запрашивает у пользователя.
Можете привести аналогичный пример с QListView, чтобы показывал 100 000 000 записей?


Название: Виртуальный QListView
Отправлено: Sergeich от Май 13, 2005, 18:15
с QListView ниче такого не получится, но виртуальный список легко реализуется через QTable


Название: Виртуальный QListView
Отправлено: Kostya. от Май 14, 2005, 08:47
Цитата: "ANM"
Разговор шел именно о выводе известного кол-ва элементов. Вывод неизвестного кол-ва элементов наверное будет выглядеть чуть по другому, например явно не нужно отображать скроллбар.

Ну, значит упустил :)

Цитата: "ANM"

Цитировать

Кстати откуда взялась цифра 406К. LISTVIEW, НЕ хранит все 10 000 000 в памяти, а подгружает их из кэша. Поэтому он и занимает постоянно 406К, даже если используется 1 элемент.
А отсюда, вы не можете делать вывод, что он не хранить всю структуру LVITEM

А это не одно и тоже? Разговор шел о том что QListView обязательно создает QListViewItem на каждый элемент находящийся в таблице. LISTVIEW имеет режим виртуального вывода при котором LISTVIEW не хранит никакой информации связанной с элементом, а всю информацию запрашивает у пользователя.
Можете привести аналогичный пример с QListView, чтобы показывал 100 000 000 записей?


Да, QListView, при неизвестном количестве элементов, будет создавать на каждый элемент QListViewItem, впрочем как и CListCtrl!
Для реализации списка с известным числом элементов, есть QTable.
Я забыл, в MFC есть класс наподобие QTable?
Если нет, то можно переобозвать QTable в QListView и повторить ваш пример с CListCtrl :)


Название: Виртуальный QListView
Отправлено: ANM от Май 14, 2005, 10:03
Цитата: "Sergeich"
с QListView ниче такого не получится, но виртуальный список легко реализуется через QTable

Да можно, но какой ценой? Заставляют самостоятельно отрисовывать элементы. :x Нет бы просто данные запрашивать.
Цитата: "Kostya."
Да, QListView, при неизвестном количестве элементов, будет создавать на каждый элемент QListViewItem, впрочем как и CListCtrl!

Да, известно кол-во элементов, просто оно очень большое.
CListCtrl это обертка над LISTVIEW, так что все что умеет LISTVIEW умеет и CListCtrl.

Я кстати прочитал что в принципе можно использовать и LISTVIEW в QT. Сделать C++ обертку (наследника от QWidget) чтоб интерфейс нормальный был, и назвать это WListView  :lol:


Название: Виртуальный QListView
Отправлено: Kostya. от Май 14, 2005, 10:33
Цитата: "ANM"
Я кстати прочитал что в принципе можно использовать и LISTVIEW в QT. Сделать C++ обертку (наследника от QWidget) чтоб интерфейс нормальный был, и назвать это WListView  :lol:


 :)


Название: Виртуальный QListView
Отправлено: Виталий от Май 20, 2005, 22:06
Действительно, большие объемы данных можно выводить при помощи QTable. Я имел дело с классом, отнаследованным от QListView, в котором полностью подменялся (по моему) правый scroll bar. В общем работало. Я хочу предложить новое решение - Qt4. Там реализован паттерн Model/View. Это позволит с легкостью решить вашу проблему. Qt4 пока только в beta-версии.

Виталий


Название: Виртуальный QListView
Отправлено: Const от Май 24, 2005, 14:17
Цитата: "Виталий"
Я имел дело с классом, отнаследованным от QListView, в котором полностью подменялся (по моему) правый scroll bar.

А можно по подробнее, как это все было устроено?  :oops: