DonationCoder.com forum
 
Read-only archive. This is a static copy of the DonationCoder.com forum. Reading and searching work as before; logging in, posting and private messages do not.
Archive of 2026-10-21 · About this archive · Main site

Author Topic: Contrary ListView Control  (Read 4,482 times)

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,652
    • Cody Award
    • Participated in NANY Challenge Five Times
Contrary ListView Control
« on: October 16, 2010, 07:16 PM »
Okay, so I've had this nagging ongoing issue with ListView control behavior for a year or so. I thought I'd find a fix for it eventually...But damn-it that's taking too long :)

Here's the rub. I have a standard ListView control that has the grid lines alternate color going down to make it easier to read. Now this control works just fine right up until I add the (below code) use XP style controls line to stdafx.h.
Code: (cpp)
// This line Allows the Application to Use the XP Themes Control Styles!
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")

Then it becomes completely EviL; when program starts all the lines are white, and the last line of the report is a complete artifact nightmare. Below pic is of two different copies of Page Countster, both with the same report open to demonstrate the issue. The top copy is with out the above code, and looks fine. The bottom copy contains the above (XP style controls) code and has an echo of the last line of the report as an artifact that appears to be a line that isn't quite scrolled into view. It also opens as plain white and screws-up the last few lines of the report leaving them as all gray.

ListView Madness.jpg

I've tried calling InvalidateRect(...) in a variety of places that caused the control to flicker so badly it was a seizure risk...But still no joy.


What am I missing?

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,652
    • Cody Award
    • Participated in NANY Challenge Five Times
Re: Contrary ListView Control
« Reply #1 on: October 17, 2010, 01:33 PM »
Hm... Okay, I'll assume by the lack of response that there's not enough information. So here's (the code I'm working with) a bit more detail:

ListView control is subclassed in WM_CREATE like so:
Code: (cpp)
/////////////////////////////////////////////////////////////

	prevWndFunc = (FARPROC)(LONG_PTR)GetWindowLong (g_hListBox, GWL_WNDPROC);
	SetWindowLong (g_hListBox, GWL_WNDPROC, (LONG)(LRESULT)ListViewWndProc);

/////////////////////////////////////////////////////////////

And here is the procedure:
Code: (cpp)

#include "stdafx.h"

#define ROW_SHADE 90
extern FARPROC	prevWndFunc;
 //=========================================================
//-> create a lighter shade (by fPercent %) of a given color
COLORREF colorShade(COLORREF c, BYTE fPercent) {
  return RGB((GetRValue (c) * fPercent / 100.0),
			 (GetGValue (c) * fPercent / 100.0),
			 (GetBValue (c) * fPercent / 100.0));
}
 //====================================================
//-> re-draw rows with the appropriate background color
void PaintAlternatingRows(HWND hWnd) {
	int 	iItems, iTop;
	RECT	rectDestin,	//	temporary storage
			rectUpd,	//	rectangle to update
			rect;		//	row rectangle
	POINT	pt;			//  >>>--->.<---<<<
	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++) {
		char szPCount[MIN_BUFF] = {0};
//		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), ROW_SHADE) :
				GetSysColor(COLOR_WINDOW);
			ListView_SetTextBkColor(hWnd, c);
//-------------------------------------------------------------------------------------------->
			ListView_GetItemText(hWnd, i, 5, szPCount, sizeof(szPCount));
			if(strcmp(szPCount, "OffLine!")) { //---++++++---> String Match = 0 <-> So...
				ListView_SetTextColor(hWnd, CLR_DEFAULT); //-> OnLine Printers Stay Black
			}else{ //------------------------------------------------->	...and...
				ListView_SetTextColor(hWnd, RGB(255, 0, 0)); // OffLine Printers Turn Red
			}
//-------------------------------------------------------------------------------------------->
//			invalidate the row rectangle then...
			InvalidateRect(hWnd, &rect, FALSE);
//			...force default processing
			CallWindowProc((WNDPROC)prevWndFunc, hWnd, WM_PAINT, 0, 0);
		}
	}
}
//	re-draw row backgrounds with the appropriate background colour
void EraseAlternatingRowBkgnds(HWND hWnd, HDC hDC) {
	int 	iItems, iTop;
	HBRUSH	brushCol1,	//	1st color
			brushCol2;	//	2nd color
	RECT	rect;		//	row rectangle
	POINT	pt;

//	create colored brushes
	brushCol1 = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
	brushCol2 = CreateSolidBrush(colorShade(GetSysColor(COLOR_WINDOW), ROW_SHADE));
//	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 color
		FillRect(hDC, &rect, (i % 2) ? brushCol2 : brushCol1);
	}
	
//	cleanup
	DeleteObject(brushCol1);
	DeleteObject(brushCol2);
}
 //=======================================================================================
//-----------------------------------------------------------> SubClassed Window Procedure
LRESULT CALLBACK ListViewWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
	switch(iMessage) {
		case WM_PAINT:
//			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 client area background requires re-drawing
			EraseAlternatingRowBkgnds(hWnd, (HDC) wParam);
			return 0;
	} 
  // continue with default message processing
  return CallWindowProc((WNDPROC)prevWndFunc, hWnd, iMessage, wParam, lParam);
}

Original address: https://www.donationcoder.com/forum/index.php?topic=24279.0