Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
Таким образом, все что нам нужно, чтобы оперировать элементами списка, – это задать их количество. Никаких вызовов InsertItem, DeleteItem и т.п. Это существенно упрощает код, отвечающий за манипуляцию с данными. Конечно, это не избавляет от подобных операций с самой информацией, однако, разделение данные-представление благоприятно сказывается на ясности кода, а значит способствует уменьшению ошибок.
Содержание элементовИтак, виртуальный список хранит очень мало информации. За заполнение элементов перед отрисовкой отвечает приложение. Для этого список посылает уведомление LVN_GETDISPINFO. Обработчик несложно добавить, воспользовавшись ClassWizard.
В обработчике уведомления LVN_GETDISPINFO необходимо проверить, какая информация требуется, и заполнить соответствующие поля.
В следующем примере показан один из способов реализации.
void CMyListView::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) {
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM* pItem= &(pDispInfo)->item;
CMyDocument* pDoc = GetDocument();
int nIndex = pItem->iItem
if (pItem->mask & LVIF_TEXT) //требуется текст?
strcpy(pItem->pszText, pDoc->GetItemText(pItem->iSubItem, nIndex));
if pItem->mask & LVIF_IMAGE) //требуется картинка
pItem->iImage = pDoc->GetItemImage(nIndex);
}
Здесь GetItemText и GetItemImage функции класса документа, возвращающие текст меток и номер изображения требуемого элемента соответственно.
По умолчанию виртуальный список не хранит информацию поля state, за исключением двух флагов LVIS_SELECTED и LVIS_FOCUSED. Это приводит к тому, что использование иконок состояния (state image) невозможно. Однако эту ситуацию легко исправить. Необходимо использовать сообщение LVM_SETCALLBACKMASK, позволяющее задать маску для хранимой списком информации об элементах.
// Разрешаем использовать иконки состояния
SendMessage(LVM_SETCALLBACKMASK, LVIS_STATEIMAGEMASK, 0)
Кажущиеся трудностиИтак, список создан и замечательно работает. Возможно, в некоторых случаях, Вам захочется реализовать и более сложные вещи.
Управление кешированиемЕсли вы самостоятельно решили оперировать большими объемами информации – без кеширования не обойтись. Виртуальный список помогает оперировать процессом кеширования, посылая приложению уведомления LVN_ODCACHEHINT, в которых передает информацию о диапазоне элементов, которые необходимо отобразить на экране. Эту информацию можно использовать для динамического выделения памяти под требуемое число элементов и заполнения их корректными значениями.
void CMyListView::OnOdcachehint(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVCACHEHINT* pCacheHint = (NMLVCACHEHINT*)pNMHDR;
// Подготовить кеш
PrepareCach( pCacheHint->iFrom, pCacheHint->iTo);
*pResult = 0;
}
Реализация функции, подобной PrepareCach, зависит от того, каким способом вы храните и обрабатываете данные, и может быть различной в зависимости от решаемой задачи. Данное уведомление всего лишь своевременная подсказка.
Нахождение специфических элементовКогда списку необходимо найти специфический элемент, он посылает уведомление LVN_ODFINDITEM. Это может случиться, если требуется реализовать нажатие быстрой клавиши (поиск по имени), или элемент получил сообщение LVM_FINDITEM. Информация для поиска передается в двух структурах NMLVFINDITEM и LVFINDINFO. В них содержится: номер элемента, с которого следует начать поиск; элемент искомой строки; направление поиска и т.п.
void CMyListView::OnOdfinditem(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR;
LVFINDINFO FindItem = pFindInfo->lvfi;
if (FindItem.flags & LVFI_STRING)
//ищем FindItem.psz начиная pFindInfo->iStart
*pResult = GetDocument()->FindItem(FindItem.psz, pFindInfo->iStart);
return;
}
*pResult = –1;
}
Обработчик уведомления должен вернуть номер искомого элемента или –1 в случае неудачи.
СортировкаТрудности? Это еще что такое? Однако бесплатный сыр сами знаете где. Дело в том, что, так как сами элементы в списке не хранятся, придется самим заботится о сортировке. Не удастся воспользоваться функцией CListCtrl::SortItems, бесполезно писать CompareItems и т.п. Все, что у вас есть – это порядковый номер элемента.
Но, нет худа без добра. Действительно, обладая дополнительной информацией об используемых данных, можно выбрать более подходящую функцию сортировки, а значит – повысить производительность. Кроме того, в ряде случаев, даже такая проблема не стоит. Если информация берется из базы данных, нет необходимости самостоятельно сортировать элементы, достаточно учесть это при составлении запроса. При использовании в качестве хранилища элементов контейнеров из STL, можно использовать возможности этой библиотеки. В большинстве практических случаев этого бывает достаточно.
Альтернатива в заключениеВиртуальный режим – не единственный способ заставить список запрашивать информацию об элементах. Можно при добавлении элемента задать значение pszText структуры LVITEM равным LPSTR_TEXTCALLBACK. В этом случае, также будут приходить уведомления LVN_GETDISPINFO. Однако при этом, придется самостоятельно заботиться о добавлении|удалении элементов, вместо одного вызова SetItemCount для виртуального режима. Кроме того, не будет заметного выигрыша в экономии памяти и скорости. Более подробно данный способ описан в статье Chris Maunder. Using text callbacks in ListView Controls.
Напоследок, небольшое резюме. Как вы уже поняли, элемент управления ListView достаточно гибок в использовании, и для написания качественного кода, важно не ошибиться в выборе необходимого режима работы. У каждого, как всегда, свои плюсы и минусы. Выбор (и ответственность) за Вами. Я всего лишь хотел помочь разобраться с этим.
P.S. Специальное спасибо Willi за подсказку об иконках состояния.
ЭКЗАМЕН
В этой новой рубрике будут публиковаться вопросы из самых различных экзаменов и тестов по Visual C++, WinAPI, MFC и др., а также конечно ответы на них ;-). Надеюсь вы найдете эту рубрику полезной.
What synchronization object can only be used to synchronize threads for a single process?
1. CriticalSection
2. Semaphore
3. Mutex
4. Timer
5. Event
Верный ответ – 1. Critical Section. Критические секции не могут быть использованы для синхронизации потоков, принадлежащих разным процессам.
Это все на сегодня. До встречи!
Алекс Jenter [email protected] Duisburg, 2001. Рассылка является частью проекта RSDN.Программирование на Visual C++
Выпуск №52 от 28 октября 2001 г.
Здравствуйте, уважаемые подписчики!
Как вы заметили, внешний вид выпусков немного изменился – чтобы отметить новый сезон. Я надеюсь, в лучшую сторону ;-) Но судить конечно вам. Присылайте свои соображения.
Сегодня в рассылке впервые будет затронута тема DirectX (давно пора, надо сказать). И, конечно, вас ждут еще рубрики "Вопрос-Ответ" и "Экзамен".
CТАТЬЯ
Введение в Direct3D8
Автор: Александров Алексей
Демонстрационное приложение (только .exe) (72 kb)
Демонстрационное приложение (исходный код) (44 kb)
Рисунок: демонстрационное приложение
Компьютерная графика всегда была одним из самых интересных проявлений развития информационных технологий. Давным-давно, во времена текстовых терминалов никто даже и представить себе не мог, что пройдет совсем немного времени и образы фантастических монстров будут создаваться не с помощью папье-маше и пластилина, а прямо на экране компьютера. Это сейчас все привыкли к графическому интерфейсу, и изображением на экране уже никого не удивишь. На самом деле надо поставить памятник человеку, который впервые решил нарисовать картинку из текстовых символов – такого рода искусство было очень распространено в свое время, и его отголоски до сих пор встречаются в различного рода конференциях. История развития компьютерной графики интересна сама по себе и заслуживает отдельной книги, но данный документ имеет чисто технический характер, поэтому мы не будем останавливаться на этапах становления искусства рисования на экране монитора, а обратимся сразу к нашим дням. Стандартом де-факто на компьютерах под управлением операционной системы Windows стали две 3D библиотеки: OpenGL и Direct3D (часть библиотеки DirectX). OpenGL, разработанный фирмой Silicon Graphics, уже стал классикой и характеризуется своей устойчивостью и стабильностью интерфейсов. Напротив, Direct3D, детище Microsoft, постоянно изменяется, совершенствуется и двигается вперед. Последняя версия этого продукта имеет номер 8, и это не конец. В этой статье я бы хотел познакомить читателя с некоторыми аспектами использования этого нового продукта, указать на его отличия от предыдущей версии и продемонстрировать его использование для решения одной из весьма распространенных задач – построения графика функции двух переменных. Исходный код примера вы может получить с этого сайта и свободно использовать в своих приложениях.