Subclassing ListView in win32 api

Hello friends,
I wish to have alternate row color in a ListView. I know that I need a subclassing of the control, but my subclassing doesn't work.
Here's the code. It compiles but doesn't give alternate colors.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
HWND	PrevWndFunc;

WNDPROC	prevWndFunc;

//---------------------------------------------------------------------------
COLORREF colorShade (COLORREF c, float fPercent)
//	create a lighter shade (by fPercent %) of a given colour
{
	return RGB ((BYTE) ((float) GetRValue (c) * fPercent / 100.0),
					(BYTE) ((float) GetGValue (c) * fPercent / 100.0),
					(BYTE) ((float) GetBValue (c) * fPercent / 100.0));
}

void PaintAlternatingRows (HWND hWnd)
//	re-draw rows with the appropriate background colour
{
	RECT	rectUpd,		//	rectangle to update
			rectDestin,	//	temporary storage
			rect;			//	row rectangle
	POINT	pt;
	int 	iItems,
			iTop;
	COLORREF
			c;				//	temporary storage

//	get the rectangle to be updated
	GetUpdateRect (hWnd, &rectUpd, FALSE);
//	allow default processing first
	CallWindowProc (
	(WNDPROC)	PrevWndFunc, hWnd, WM_PAINT, 0, 0);
// set the row horizontal dimensions
	SetRect (&rect, rectUpd.left, 0, rectUpd.right, 0);
//	number of displayed rows
	iItems = ListView_GetCountPerPage (hWnd);
//	first visible row
	iTop = ListView_GetTopIndex (hWnd);

	ListView_GetItemPosition (hWnd, iTop, &pt);
	for (int i=iTop ; i<=iTop+iItems ; i++) {
//		set row vertical dimensions
		rect.top = pt.y;
		ListView_GetItemPosition (hWnd, i+1, &pt);
		rect.bottom = pt.y;
//		if row rectangle intersects update rectangle then it requires re-drawing
		if (IntersectRect (&rectDestin, &rectUpd, &rect)) {
//			change text background colour accordingly
			c = (i % 2) ?
				colorShade (GetSysColor (COLOR_WINDOW), 95.0) :
				GetSysColor (COLOR_WINDOW);
			ListView_SetTextBkColor (hWnd, c);
//			invalidate the row rectangle then...
			InvalidateRect (hWnd, &rect, FALSE);
//			...force default processing
			CallWindowProc (
				(WNDPROC) prevWndFunc, hWnd, WM_PAINT, 0, 0);
		}
	}
}

void EraseAlternatingRowBkgnds (HWND hWnd, HDC hDC)
//	re-draw row backgrounds with the appropriate background colour
{
	RECT		rect;			//	row rectangle
	POINT		pt;
	int 		iItems,
				iTop;
	HBRUSH	brushCol1,	//	1st colour
				brushCol2;	//	2nd colour

//	create coloured brushes
	brushCol1 = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
	brushCol2 = CreateSolidBrush (colorShade (GetSysColor (COLOR_WINDOW), 95.0));
//	get horizontal dimensions of row
	GetClientRect (hWnd, &rect);
//	number of displayed rows
	iItems = ListView_GetCountPerPage (hWnd);
//	first visible row
	iTop = ListView_GetTopIndex (hWnd);
	ListView_GetItemPosition (hWnd, iTop, &pt);

	for (int i=iTop ; i<=iTop+iItems ; i++) {
//		set row vertical dimensions
		rect.top = pt.y;
		ListView_GetItemPosition (hWnd, i+1, &pt);
		rect.bottom = pt.y;
//		fill row with appropriate colour
		FillRect (hDC, &rect, (i % 2) ? brushCol2 : brushCol1);
	}
	
//	cleanup
	DeleteObject (brushCol1);
	DeleteObject (brushCol2);
}

LRESULT CALLBACK ListViewWndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
//	subclassed window procedure
{
	switch (iMessage) {
		case WM_PAINT:
			Beep(500,400);
//			intercept the WM_PAINT message which is called each time an area
//			of the control's client area requires re-drawing
			PaintAlternatingRows (hWnd);
			return 0;
		case WM_ERASEBKGND:
//			intercept the WM_ERASEBKGRN message which is called each time an area
//			of the control's lient area background requires re-drawing
			EraseAlternatingRowBkgnds (hWnd, (HDC) wParam);
			return 0;
	}

// continue with default message processing
	return CallWindowProc (
		(WNDPROC) prevWndFunc, hWnd, iMessage, wParam, lParam);

}

Particularly doesn' work the WM_PAINT message in the LRESULT CALLBACK ListViewWndProc procedure.
Any help is too much appreciated.
Thanks
I don't know what's wrong with your code but I have done this in a different way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
BOOL customdraw_handler(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);

BOOL CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
// ...
switch(message)
  {

    case WM_NOTIFY:
    	 switch(LOWORD(wParam))
	    {
                 case LISTVIEW_CONTROL_ID:
                    return customdraw_handler(hwnd,message,wParam,lParam);
                    break;
              }

            break;

// ...
   default: return false;
  }



BOOL customdraw_handler(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
LPNMLISTVIEW  pnm    = (LPNMLISTVIEW)lParam;


switch (pnm->hdr.code)
 {
    case NM_CUSTOMDRAW:
      LPNMLVCUSTOMDRAW  lplvcd;
                        lplvcd = (LPNMLVCUSTOMDRAW)lParam;

     switch(lplvcd->nmcd.dwDrawStage)
       {
          case CDDS_PREPAINT :
            SetWindowLong(hwnd,DWL_MSGRESULT,CDRF_NOTIFYITEMDRAW); // Comment this line out if this is not a dialog obx
            return CDRF_NOTIFYITEMDRAW;
           break;

          case CDDS_ITEMPREPAINT:
               int row; 
               row=lplvcd->nmcd.dwItemSpec;
               
               if(row==1)
                {
                    lplvcd->clrText=RGB(136,66,66); // change the  text color
                    // ...
                }


               return CDRF_NEWFONT;
            break;

       }
   break;

  }


return FALSE;
}


http://msdn.microsoft.com/en-us/library/bb774773(VS.85).aspx
http://msdn.microsoft.com/en-us/library/bb774778(VS.85).aspx
Last edited on
Topic archived. No new replies allowed.