Использование виртуальных элементов управления List-View
В этом разделе показано, как работать с элементами управления представления виртуальных списков. В сопровождающих примерах кода C++ показано, как обрабатывать сообщения уведомлений о представлении виртуального списка, как оптимизировать кэш и как получить элемент из кэша.
- Что нужно знать
- виртуальная обработка уведомлений List-View управления кодами
- Оптимизируйте кэш
- Извлечение элемента из кэша
- связанные темы
Заметка
В примере кода в этом разделе предполагается, что кэш является динамически выделенным массивом определяемых приложением структур. Структура определена в следующем примере кода C++.
struct RndItem
{
int iIcon; // Bitmap assigned to this item.
UINT state; // Item state value.
TCHAR Title[BUFFER_SIZE]; // BUFFER_SIZE is a user-defined macro value.
TCHAR SubText1[BUFFER_SIZE]; // Text for the label of the first sub-item.
TCHAR SubText2[BUFFER_SIZE]; // Text for the label of the second item.
};
Что нужно знать
Технологии
Необходимые условия
- C/C++
- Программирование пользовательского интерфейса Windows
Инструкции
Обработка кодов уведомлений виртуальных List-View
Помимо кодов уведомлений, отправленных другими элементами управления представления списка, виртуальные элементы управления представления списка также могут отправлять LVN_ODCACHEHINT и коды уведомлений LVN_ODFINDITEM.
Эта определяемая приложением функция обрабатывает сообщения уведомления, которые обычно отправляются из виртуального элемента управления представления списка.
LRESULT OnNotify(HWND hwnd, NMHDR* pnmhdr)
{
HRESULT hr;
LRESULT lrt = FALSE;
switch (pnmhdr->code)
{
case LVN_GETDISPINFO:
{
RndItem rndItem;
NMLVDISPINFO* plvdi = (NMLVDISPINFO*) pnmhdr;
if (-1 == plvdi->item.iItem)
{
OutputDebugString(TEXT("LVOWNER: Request for -1 item?\n"));
DebugBreak();
}
// Retrieve information for item at index iItem.
RetrieveItem( &rndItem, plvdi->item.iItem );
if(plvdi->item.mask & LVIF_STATE)
{
// Fill in the state information.
plvdi->item.state |= rndItem.state;
}
if(plvdi->item.mask & LVIF_IMAGE)
{
// Fill in the image information.
plvdi->item.iImage = rndItem.iIcon;
}
if(plvdi->item.mask & LVIF_TEXT)
{
// Fill in the text information.
switch (plvdi->item.iSubItem)
{
case 0:
// Copy the main item text.
hr = StringCchCopy(plvdi->item.pszText, MAX_COUNT, rndItem.Title);
if(FAILED(hr))
{
// Insert error handling code here. MAX_COUNT
// is a user-defined value. You must not enter
// more characters than specified by MAX_COUNT or
// the text will be truncated.
}
break;
case 1:
// Copy SubItem1 text.
hr = StringCchCopy( plvdi->item.pszText, MAX_COUNT, rndItem.SubText1);
if(FAILED(hr))
{
// Insert error handling code here. MAX_COUNT
// is a user-defined value. You must not enter
// more characters than specified by MAX_COUNT or
// the text will be truncated..
}
break;
case 2:
// Copy SubItem2 text.
hr = StringCchCopy(plvdi->item.pszText, MAX_COUNT, rndItem.SubText2);
if(FAILED(hr))
{
// Insert error handling code here. MAX_COUNT
// is a user-defined value. You must not enter
// more characters than specified by MAX_COUNT or
// the text will be truncated..
}
break;
default:
break;
}
}
lrt = FALSE;
break;
}
case LVN_ODCACHEHINT:
{
NMLVCACHEHINT* pcachehint = (NMLVCACHEHINT*) pnmhdr;
// Load the cache with the recommended range.
PrepCache( pcachehint->iFrom, pcachehint->iTo );
break;
}
case LVN_ODFINDITEM:
{
LPNMLVFINDITEM pnmfi = NULL;
pnmfi = (LPNMLVFINDITEM)pnmhdr;
// Call a user-defined function that finds the index according to
// LVFINDINFO (which is embedded in the LPNMLVFINDITEM structure).
// If nothing is found, then set the return value to -1.
break;
}
default:
break;
} // End Switch block.
return(lrt);
}
Оптимизация кэша
Элемент управления представлением виртуального списка отправляет уведомление LVN_ODCACHEHINT, когда содержимое его области отображения изменилось. Сообщение содержит сведения о диапазоне элементов, которые необходимо кэшировать. Получив сообщение уведомления, ваше приложение должно быть готово загрузить информацию о элементах в кэш для запрошенного диапазона, чтобы она была легко доступна при получении сообщения уведомления LVN_GETDISPINFO.
В следующем примере кода C++ определяемая приложением функция принимает диапазон элементов для кэша, отправляемого элементом управления виртуального представления списка. Он выполняет проверку, чтобы определить, что запрошенный диапазон элементов еще не кэширован, а затем выделяет необходимую глобальную память и заполняет кэш при необходимости.
void PrepCache(int iFrom, int iTo)
{
/* Global Variables
* g_priCache[ ]: the main cache.
* g_iCache: the index of the first item in the main cache.
* g_cCache: the count of items in the main cache.
*
* g_priEndCache[ ]: the cache of items at the end of the list.
* g_iEndCache: the index of the first item in the end cache.
* g_cEndCache: the count of items in the end cache.
*/
// Local Variables
int i;
BOOL fOLFrom = FALSE;
BOOL fOLTo = FALSE;
// Check to see if this is the end cache.
if ((iTo == g_cCache - 1) && ((iTo - iFrom) < 30)) // 30 entries wide.
{
// Check to see if this is a portion of the current end cache.
if ((g_cCache) && (iFrom >= g_iEndCache) && (iFrom < g_iEndCache+g_cEndCache))
return;
// If it is a part of current end cache, no loading is necessary.
// This is a new end cache. Free the old memory.
if ( g_priEndCache )
GlobalFree( g_priEndCache );
// Set the index and count values for the new end cache,
// and then retrieve the memory.
g_iEndCache = iFrom;
g_cEndCache = (iTo - iFrom + 1);
g_priEndCache = (RndItem *)GlobalAlloc(GPTR, sizeof(RndItem) * g_cEndCache);
if (! g_priEndCache)
{
// TODO: Out of memory. Perform error handling.
}
// Loop to fill the cache with the recommended items.
for (i=0; i<g_cEndCache; i++)
{
// TODO: Call a function that accesses item information and
// fills a cache element.
}
}
else
{
// It is not a member of the current end cache.
// Try the primary cache instead.
// Check to see if iFrom is within the primary cache.
if ((g_cCache) && (iFrom >= g_iCache) && (iFrom < g_iCache+g_cCache))
fOLFrom = TRUE;
// Check to see if iTo is within the primary cache.
if ((g_cCache) && (iTo >= g_iCache) && (iTo <= g_iCache+g_cCache))
fOLTo = TRUE;
// do nothing if both iFrom and iTo are within the current cache.
if (fOLFrom && fOLTo)
return;
// Enlarge the cache size rather than make it specific to this hint.
if (fOLFrom)
iFrom = g_iCache;
else if (fOLTo)
iTo = g_iCache + g_cCache;
// A new primary cache is needed. Free the old primary cache.
if ( g_priCache )
GlobalFree( g_priCache );
// Set the index and count values for the new primary cache,
// and then retrieve the memory.
g_iCache = iFrom;
g_cCache = (iTo - iFrom + 1);
g_priCache = (RndItem *)GlobalAlloc( GPTR, sizeof( RndItem ) * g_cCache );
if (!g_priCache)
{
// TODO: Out of memory. Do error handling.
}
// Loop to fill the cache with the recommended items.
for (i=0; i<g_cCache; i++)
{
// TODO: Call a function that accesses item information
// and fills a cache element.
}
}
}
Получение элемента из кэша
В этом примере функция принимает два параметра, адрес определяемой приложением структуры и целочисленное значение, представляющее индекс элемента в списке. Он проверяет значение индекса, чтобы обнаружить, кэшируется ли нужный элемент. Если это так, указатель, переданный функции, устанавливается на расположение в кэше. Если элемент не находится в основном или конечном кэше, сведения об элементе должны быть найдены вручную.
void RetrieveItem( RndItem * prndItem, int index )
{
// Global Variables
// g_priCache[ ]: the main cache.
// g_iCache: the index of the first item in the main cache.
// c_cCache: the count of items in the main cache.
//
// g_priEndCache[ ]: the cache of items at the end of the list.
// g_iEndCache: the index of the first item in the end cache.
// g_cEndCache: the count of items in the end cache.
//
// Check to see if the item is in the main cache.
if ((index >= g_iCache) && (index < g_iCache + g_cCache))
*prndItem = g_priCache[index-g_iCache];
// If it is not in the main cache, then check to see if
// the item is in the end area cache.
else if ((index >= g_iEndCache) && (index < g_iEndCache + g_cEndCache))
*prndItem = g_priEndCache[index-g_iEndCache];
else
{
// The item is not in either cache.
// Therefore, retrieve the item information manually.
}
}
Замечания
В списке сообщений окна, обработанных элементом управления представлением списка, см. Обработка сообщений по умолчанию List-View.
Полный пример
Связанные разделы
-
Справочник по элементу управления List-View