Reputation: 1207
I need to process all of the items in a ListView (in report mode) that are visible to the user. While debugging, I tried this:
int item;
HWND hlist;
for( item = ListView_GetNextItem( hlist, -1, LVNI_VISIBLEONLY );
item >= 0;
item = ListView_GetNextItem( hlist, item, LVNI_VISIBLEONLY ) )
{
if( ListView_IsItemVisible( hlist, item ) )
{
OutputDebugString("DEBUG: Found a visible item!\n");
}
}
According to the documentation, the GetNextItem loop should provide all of the items that are VISIBLE (in Vista or later and I'm on Win7). However, my debug shows that it actually provides ALL items in the ListView.
So I added the redundant test of IsItemVisible, which is documented to return TRUE when the specified item is VISIBLE. Unfortunately, it returns FALSE for every single item found in the for() loop.
Obviously I'm missing something critical (and possibly obvious) here, but I'm at a total loss as to what it could be. Oh, FWIW I'm testing under Windows 7 Professional x64, and my build target is WINVER 0x0601 (_WIN32_WINNT is also 0x0601).
Any ideas what I'm missing?
[update]
I've found a work-around (see below) but I'd still love to know why neither of the visible-related functions is working (for me).
For anyone interested, here's how I'm working around the problem:
LVITEM lvi;
HWND hlist = GetDlgItem( hwnd, LST_ALARMS );
int item;
RECT rcList;
RECT rcItem;
RECT rcHead;
GetClientRect( hlist, &rcList );
// Remove the header space from the visible item area
GetClientRect( ListView_GetHeader(hlist), &rcHead );
rcList.top += (rcHead.bottom - rcHead.top);
memset( &lvi, 0, sizeof(lvi) );
for( item = ListView_GetNextItem( hlist, -1, LVNI_ALL );
item >= 0;
item = ListView_GetNextItem( hlist, item, LVNI_ALL ) )
{
if( ListView_GetItemRect( hlist, item, &rcItem, LVIR_BOUNDS )
&& (rcList.top <= rcItem.top)
&& (rcItem.bottom <= rcList.bottom) )
{ // This item is COMPLETELY visible
// -- partially visible items are NOT included.
lvi.mask = LVIF_PARAM;
lvi.iItem = item;
ListView_GetItem( hlist, &lvi );
// do stuff with item
}
}
This is working exactly as I hoped the things at the beginning of this message would do. I'd prefer the easier readability of the visibility functions, but since I need it to actually work, I'm stuck comparing rectangles.
Upvotes: 2
Views: 510
Reputation: 45172
The concept of visibility used by LVNI_VISIBLEONLY
is not "visible on screen right now". It is "has not been removed from view". (An object becomes removed from view if it belongs to a group that has been collapsed.) So it is expected that LVNI_VISIBLEONLY
returns all elements if you are not using collapsible grouping.
In other words, "visible" means "not hidden", not "on screen". This is the same sense used by IsWindowVisible
and TVNI_NEXTVISIBLE
and other APIs.
Upvotes: 3
Reputation: 4590
There's a curious note at the bottom of the LVM_GETNEXTITEM explanation that may explain your problem:
Remarks
Note that the following flags, for use only with Windows Vista, are mutually exclusive of any other flags in use: LVNI_VISIBLEONLY, LVNI_SAMEGROUPONLY, LVNI_VISIBLEORDER, LVNI_DIRECTIONMASK, and LVNI_STATEMASK.
Upvotes: 0