Click to See Complete Forum and Search --> : listview - Subclassing & double buffering


fputil
January 20th, 2006, 04:44 PM
Hi, I have hacked together a prog to double buffer a listview after reading this thread.


http://www.codeguru.com/forum/showthread.php?t=351537

mostly using runt888's code.

However there are two issues confusing me.


1.

To test I have a red background for the listview and a green for the
underlying window.
Now if I resize I still get the green flickering under the red and I dont
understand why as I have blitted all to a back buffer first (I think).

2.
I wish to update the listview text regularly (maybe several times a second).
I have a timer loop in the
prog to update a specific subitem(s).
I only wish that one item to be updated - hopefully increasing the
preformance of the prog.
However no matter what I do *most* of the items sub items are updated each
time ie a WM_NOTIFY message always produced for the subitems each WM_TIMER
pass. Is it possible to just select several subitems for update each pass?

I include the whole of the hack below.

Thanks for any pointers.

fputil
January 20th, 2006, 04:58 PM
/*++


--*/

#include <windows.h>
#include <commctrl.h>
#include <strsafe.h>
#include "hello.h"

//utility Macro
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))


WNDPROC OldListProc;
LRESULT CALLBACK ListProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;



HWND CreateListView (HWND);
VOID OnGetDispInfo(NMLVDISPINFO *);

HINSTANCE hInst;
HWND hWndListView;

// Used for subitems.
PETINFO rgPetInfo [ ] =
{
{TEXT("Dog"), TEXT("Poodle"), TEXT("$300.00"),300},
{TEXT("Cat"), TEXT("Siamese"), TEXT("$100.00"),100},
{TEXT("Fish"), TEXT("Angel Fish"), TEXT("$10.00"),10},
};

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdParam, int nCmdShow)
{
static TCHAR szAppName[ ] = TEXT("HelloWin");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;

if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL,
IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
// wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
wndclass.hbrBackground = CreateSolidBrush(RGB(0,200,0));
// wndclass.hbrBackground = CreateSolidBrush(RGB(200,0,0));
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

RegisterClass (&wndclass);
}

hInst = hInstance;
hwnd = CreateWindow(szAppName,
TEXT("The List-View Program - REPORT VIEW"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);

ShowWindow (hwnd, nCmdShow);
UpdateWindow (hwnd);

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;

switch (message)
{
case WM_CREATE:
CreateListView (hwnd);
OldListProc = (WNDPROC)SetWindowLong(hWndListView, GWL_WNDPROC, (LONG)ListProc);
SetTimer(hwnd, NULL, 100, NULL);
return 0;

// case WM_ERASEBKGND:
// {
// return true;
// }


case WM_NOTIFY:
// OutputDebugString(TEXT("WM_NOTIFY\n"));
// Process notification messages.
switch (((LPNMHDR) lParam)->code)
{

case NM_CUSTOMDRAW:
{
switch( ((LPNMLVCUSTOMDRAW)lParam)->nmcd.dwDrawStage )
{
case CDDS_PREPAINT:
return CDRF_NOTIFYITEMDRAW;


case CDDS_ITEMPREPAINT: //Before an item is drawn
if (((int)lplvcd->nmcd.dwItemSpec%2)==0)
{
//customize item appearance
lplvcd->clrText = RGB(255,0,0);
lplvcd->clrTextBk = RGB(200,200,200);
return CDRF_NEWFONT;
}
else{
lplvcd->clrText = RGB(0,0,255);
lplvcd->clrTextBk = RGB(255,255,255);

return CDRF_NEWFONT;
}
break;
}
default:
return CDRF_DODEFAULT;
}

// Fill subitems.
case LVN_GETDISPINFO:
OnGetDispInfo((NMLVDISPINFO *) lParam);
break;


}
return 0;

case WM_TIMER:
OutputDebugString(TEXT("WM_TIMER\n"));


ListView_RedrawItems( hWndListView,2,2);

// ListView_SetItemText(hWndListView, 1,2,LPSTR_TEXTCALLBACK);
// ListView_SetItemText(hWndListView, 2,2,"Hello");
return 0;

case WM_DESTROY:
PostQuitMessage (0);
return 0;
}

return DefWindowProc (hwnd, message, wParam, lParam);
}


HWND CreateListView (HWND hWndParent)
{
RECT rcl;
HICON hIcon;
int index;
HIMAGELIST hSmall, hLarge;
LV_COLUMN lvC;
TCHAR szText[50];
LV_ITEM lvI;
INITCOMMONCONTROLSEX icex;

// Ensure that the common control DLL is loaded.
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
GetClientRect(hWndParent, &rcl);

// Create a list-view control in icon view.
hWndListView = CreateWindowEx(0L, WC_LISTVIEW, TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER |
LVS_REPORT | LVS_NOCOLUMNHEADER ,
0, 0, rcl.right - rcl.left, rcl.bottom - rcl.top, hWndParent,
(HMENU) ID_LISTVIEW, hInst, NULL);

if(hWndListView == NULL)
return NULL;
//WS_BORDER | WS_EX_CLIENTEDGE
// Create the image lists.

// Create columns.
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvC.fmt = LVCFMT_LEFT;
lvC.cx = 75;
lvC.pszText = szText;

// Load the column labels from the resource file.
for (index = 0; index < 3; index++)
{
lvC.iSubItem = index;
LoadString(hInst, IDS_PETS + index, szText, ARRAYSIZE(szText));
if(ListView_InsertColumn(hWndListView, index, &lvC) == -1)
return NULL;
}

// Insert items.
lvI.mask = LVIF_TEXT | LVIF_STATE;
lvI.state = 0;
lvI.stateMask = 0;

for (index = 0; index < 3; index++)
{
lvI.iItem = index;
lvI.iImage = index;
lvI.iSubItem = 0;
lvI.pszText = LPSTR_TEXTCALLBACK;
// lvI.pszText = rgPetInfo[index].szPrice;

if(ListView_InsertItem(hWndListView, &lvI) == -1)
return NULL;
}

return (hWndListView);
}

// OnGetDispInfo - processes the LVN_GETDISPINFO
// notification message.
int ivalue=100;
int iloop=0;
char buffer[65];
VOID OnGetDispInfo(NMLVDISPINFO *plvdi)
{
char buffer[128];

// OutputDebugString(TEXT("Entered service code\n"));
// sprintf( buffer, " plvdi->item.iItem:%s ; plvdi->item.iItem:%s ;\n", s );
sprintf( buffer, " plvdi->item.iItem/subItem:%i|%i\n",
plvdi->item.iItem,plvdi->item.iSubItem);
OutputDebugString(buffer);

/*
if(iloop>3)
{ if(plvdi->item.iItem < 2)
return;
}
*/

switch (plvdi->item.iSubItem)
{

case 0:
plvdi->item.pszText = rgPetInfo[plvdi->item.iItem].szKind;
break;

case 1:
plvdi->item.pszText = rgPetInfo[plvdi->item.iItem].szBreed;
break;

case 2:
{
// plvdi->item.pszText = rgPetInfo[plvdi->item.iItem].szPrice;
iloop++;
int iVal=rgPetInfo[plvdi->item.iItem].iPrice;
if(plvdi->item.iItem==2)
{ iVal=rgPetInfo[plvdi->item.iItem].iPrice*iloop;
}

// itoa(rgPetInfo[plvdi->item.iItem].iPrice, buffer, 10 );
itoa(iVal, buffer, 10 );
plvdi->item.pszText = buffer;
}


default:
break;
}
}


LRESULT drawListView(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)

{
//Double buffer the window to avoid flickering.
PAINTSTRUCT ps;
HDC dc = BeginPaint( hwnd, &ps );

RECT rectClient;
GetClientRect( hwnd, &rectClient );

HDC memoryDC = CreateCompatibleDC( dc );
HBITMAP bitmap = CreateCompatibleBitmap( dc, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top );
// HBRUSH brush = CreateSolidBrush( GetBkColor( dc ) );
HBRUSH brush = CreateSolidBrush(RGB(200,0,0));

HBITMAP oldBitmap = (HBITMAP)SelectObject( memoryDC, bitmap );

//Fill Background color.
RECT fillRect = { rectClient.left, rectClient.top, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top };
FillRect( memoryDC, &fillRect, brush );


LRESULT retVal=0;
//Draw Listview
CallWindowProc(OldListProc,hwnd, message,(WPARAM)memoryDC, lParam);
BitBlt( dc, rectClient.left, rectClient.top, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top, memoryDC, 0, 0, SRCCOPY );

SelectObject( memoryDC, oldBitmap );

DeleteObject( brush );
DeleteObject( bitmap );

DeleteDC( memoryDC );
EndPaint( hwnd, &ps );

return retVal;
}

LRESULT CALLBACK ListProc (HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)
{
switch(message)
{


case WM_PAINT:
{
LRESULT retVal=drawListView(hwnd, message,wParam, lParam);

return 0;
}


case WM_ERASEBKGND:
{
return true;
}

}
return CallWindowProc (OldListProc,
hwnd, message, wParam, lParam);

}