Click here to Skip to main content
13,862,523 members
Click here to Skip to main content

Stats

2.1M views
58.3K downloads
447 bookmarked
Posted 3 Sep 2008
Licenced CPOL

CGridListCtrlEx - Grid Control Based on CListCtrl

, 16 Mar 2015
A custom draw CListCtrl with subitem editing and formatting
CGridListCtrlEx
DemoApplication
res
CGridListCtrlEx.ico
FLGDEN.ICO
FLGFRAN.ICO
FLGGERM.ICO
FLGGREEC.ico
FLGSPAIN.ICO
FLGSWED.ICO
Documentation
CGridListCtrlEx
screenshot.png
vs2003
CGridListCtrlEx.vcproj
vs2005
CGridListCtrlEx.vcproj
vs2008
CGridListCtrlEx.vcproj
vs6
CGridListCtrlEx.dsp
CGridListCtrlEx.dsw
Release
CGridListCtrlEx.exe
msvcp120.dll
msvcr120.dll
CGridListCtrlEx.ico
FLGDEN.ICO
FLGFRAN.ICO
FLGGERM.ICO
FLGGREEC.ico
FLGSPAIN.ICO
FLGSWED.ICO
screenshot.png
Doxygen
Doxyfile
html
arrowdown.png
arrowright.png
bc_s.png
bdwn.png
class_c_grid_column_trait.png
class_c_grid_column_trait_combo.png
class_c_grid_column_trait_date_time.png
class_c_grid_column_trait_edit.png
class_c_grid_column_trait_hyper_link.png
class_c_grid_column_trait_image.png
class_c_grid_column_trait_multiline_edit.png
class_c_grid_column_trait_text.png
class_c_grid_editor_combo_box.png
class_c_grid_editor_combo_box_edit.png
class_c_grid_editor_date_time_ctrl.png
class_c_grid_editor_text.png
class_c_grid_list_ctrl_ex.png
class_c_grid_list_ctrl_groups.png
class_c_grid_multiline_editor_text.png
class_c_grid_row_trait.png
class_c_grid_row_trait_text.png
class_c_grid_row_trait_x_p.png
class_c_view_config_section.png
class_c_view_config_section_default.png
class_c_view_config_section_default_1_1_c_view_config_section_local.png
class_c_view_config_section_profiles.png
class_c_view_config_section_win_app.png
closed.png
doc.png
doxygen.png
folderclosed.png
folderopen.png
ftv2blank.png
ftv2cl.png
ftv2doc.png
ftv2folderclosed.png
ftv2folderopen.png
ftv2lastnode.png
ftv2link.png
ftv2mlastnode.png
ftv2mnode.png
ftv2mo.png
ftv2node.png
ftv2ns.png
ftv2plastnode.png
ftv2pnode.png
ftv2splitbar.png
ftv2vertline.png
nav_f.png
nav_g.png
nav_h.png
open.png
search
close.png
mag_sel.png
search_l.png
search_m.png
search_r.png
splitbar.png
sync_off.png
sync_on.png
tab_a.png
tab_b.png
tab_h.png
tab_s.png
CGridListCtrlEx.vcproj
CGridListCtrlEx.vcproj
CGridListCtrlEx.vcproj
CGridListCtrlEx.dsp
CGridListCtrlEx.dsw
//------------------------------------------------------------------------
// Author:  Rolf Kristensen	
// Source:  http://www.codeproject.com/KB/list/CGridListCtrlEx.aspx
// License: Free to use for all (New BSD License)
//------------------------------------------------------------------------

#include "stdafx.h"
#pragma warning(disable:4100)	// unreferenced formal parameter

#include "CGridRowTraitText.h"

#include "CGridRowTraitVisitor.h"
#include "CGridListCtrlEx.h"

//------------------------------------------------------------------------
//! CGridRowTraitText - Constructor
//------------------------------------------------------------------------
CGridRowTraitText::CGridRowTraitText()
	:m_pOldFont(NULL)
	,m_FontAllocated(false)
	,m_TextColor((COLORREF)-1)
	,m_BackColor((COLORREF)-1)
	,m_AltTextColor((COLORREF)-1)
	,m_AltBackColor((COLORREF)-1)
	,m_InvertCellSelection(false)
{}

//------------------------------------------------------------------------
//! Sets the same row coloring for all rows
//!
//! @param backColor The background color to use for all rows
//! @param textColor The text color to use for all rows
//------------------------------------------------------------------------
void CGridRowTraitText::SetRowColor(COLORREF textColor, COLORREF backColor)
{
	m_TextColor = textColor;
	m_BackColor = backColor;
}

//------------------------------------------------------------------------
//! Activates alternate row coloring
//!
//! @param backColor The background color to use for every second row
//! @param textColor The text color to use for every second row
//------------------------------------------------------------------------
void CGridRowTraitText::SetAltRowColor(COLORREF textColor, COLORREF backColor)
{
	m_AltTextColor = textColor;
	m_AltBackColor = backColor;
}

//------------------------------------------------------------------------
//! Accept Visitor Pattern
//------------------------------------------------------------------------
void CGridRowTraitText::Accept(CGridRowTraitVisitor& visitor)
{
	visitor.Visit(*this);
}

//------------------------------------------------------------------------
//! Changes the text color if one is specified
//!
//! @param nRow The index of the row
//! @param textColor Current text color
//! @return New text color was specified (true / false)
//------------------------------------------------------------------------
bool CGridRowTraitText::UpdateTextColor(int nRow, COLORREF& textColor)
{
	if (m_AltTextColor!=COLORREF(-1) && nRow % 2)
	{
		textColor = m_AltTextColor;
		return true;
	}

	if (m_TextColor!=COLORREF(-1))
	{
		textColor = m_TextColor;
		return true;
	}

	return false;
}

//------------------------------------------------------------------------
//! Changes the background color if one is specified
//!
//! @param nRow The index of the row
//! @param backColor Current background color
//! @return New background color was specified (true / false)
//------------------------------------------------------------------------
bool CGridRowTraitText::UpdateBackColor(int nRow, COLORREF& backColor)
{
	if (m_AltBackColor!=COLORREF(-1) && nRow % 2)
	{
		backColor = m_AltBackColor;
		return true;
	}

	if (m_BackColor!=COLORREF(-1))
	{
		backColor = m_BackColor;
		return true;
	}

	return false;
}

//------------------------------------------------------------------------
//! Overrides the custom draw handler, to allow custom coloring of rows.
//!		- Focus rectangle display
//!		- Use font size to increase row-height, but keep cell font-size
//!		- Alternate row coloring
//!
//! @param owner The list control drawing
//! @param pLVCD Pointer to NMLVCUSTOMDRAW structure
//! @param pResult Modification to the drawing stage (CDRF_NEWFONT, etc.)
//------------------------------------------------------------------------
void CGridRowTraitText::OnCustomDraw(CGridListCtrlEx& owner, NMLVCUSTOMDRAW* pLVCD, LRESULT* pResult)
{
	int nRow = (int)pLVCD->nmcd.dwItemSpec;

	switch (pLVCD->nmcd.dwDrawStage)
	{
		case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
		{
			// Remove the selection color for the focus cell, to make it easier to see focus
			if (m_InvertCellSelection)
			{
				int nCol = pLVCD->iSubItem;
				if (pLVCD->nmcd.uItemState & CDIS_SELECTED)
				{
					if (owner.GetFocusCell()==nCol && owner.GetFocusRow()==nRow)
					{
						pLVCD->nmcd.uItemState &= ~CDIS_SELECTED;
					}
				}
			}

			// Bug in Vista causes the cell color from previous cell to be used in the next
			// even if having reverted the cell coloring in subitem-post-paint
			if (pLVCD->clrText <= RGB(255,255,255) || pLVCD->clrTextBk <= RGB(255,255,255))
			{
				pLVCD->clrText = CLR_DEFAULT;
				pLVCD->clrTextBk = CLR_DEFAULT;

				if (UpdateTextColor(nRow, pLVCD->clrText))
					*pResult |= CDRF_NEWFONT;

				if (UpdateBackColor(nRow, pLVCD->clrTextBk))
					*pResult |= CDRF_NEWFONT;

				if (owner.OnDisplayRowColor(nRow, pLVCD->clrText, pLVCD->clrTextBk))
					*pResult |= CDRF_NEWFONT;
			}
		} break;

		// Before painting a row
		case CDDS_ITEMPREPAINT:
		{
			if (UpdateTextColor(nRow, pLVCD->clrText))
				*pResult |= CDRF_NEWFONT;

			if (UpdateBackColor(nRow, pLVCD->clrTextBk))
				*pResult |= CDRF_NEWFONT;

			if (owner.OnDisplayRowColor(nRow, pLVCD->clrText, pLVCD->clrTextBk))
				*pResult |= CDRF_NEWFONT;

			LOGFONT newFont = {0};
			if (owner.OnDisplayRowFont(nRow, newFont))
			{
				// New font provided
				CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
				CFont* pNewFont = new CFont;
				VERIFY( pNewFont->CreateFontIndirect(&newFont) );
				m_pOldFont = pDC->SelectObject(pNewFont);
				m_FontAllocated = true;
				*pResult |= CDRF_NOTIFYPOSTPAINT;	// We need to restore the original font
				*pResult |= CDRF_NEWFONT;
			}
			else
			{
				if (owner.GetFont()!=owner.GetCellFont())
				{
					// Using special cell font because of SetMargin()
					CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
					m_pOldFont = pDC->SelectObject(owner.GetCellFont());
					*pResult |= CDRF_NOTIFYPOSTPAINT;	// We need to restore the original font
					*pResult |= CDRF_NEWFONT;
				}
			}

			if (pLVCD->nmcd.uItemState & CDIS_FOCUS)
			{
				// If drawing focus row, then remove focus state and request to draw it later
				//	- Row paint request can come twice, with and without focus flag
				//	- Only respond to the one with focus flag, else DrawFocusRect XOR will cause solid or blank focus-rectangle
				if (owner.GetFocusRow()==nRow)
				{
					if (owner.GetFocusCell() >= 0)
					{
						// We want to draw a cell-focus-rectangle instead of row-focus-rectangle
						pLVCD->nmcd.uItemState &= ~CDIS_FOCUS;
						*pResult |= CDRF_NOTIFYPOSTPAINT;
					}
					else
					if (owner.GetExtendedStyle() & LVS_EX_GRIDLINES)
					{
						// Avoid bug where bottom of focus rectangle is missing when using grid-lines
						//	- Draw the focus-rectangle for the entire row (explicit)
						pLVCD->nmcd.uItemState &= ~CDIS_FOCUS;
						*pResult |= CDRF_NOTIFYPOSTPAINT;
					}
				}
			}
		} break;

		// After painting a row
		case CDDS_ITEMPOSTPAINT:
		{
			if (m_pOldFont!=NULL)
			{
				// Restore the original font
				CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
				CFont* pNewFont = pDC->SelectObject(m_pOldFont);
				if (m_FontAllocated)
				{
					m_FontAllocated = false;
					delete pNewFont;
				}
				m_pOldFont = NULL;
			}

			if (CRect(pLVCD->nmcd.rc)==CRect(0,0,0,0))
				break;

			if (owner.GetFocusRow()!=nRow)
				break;

			// Perform the drawing of the focus rectangle
			if (owner.GetFocusCell() >= 0)
			{
				// Draw the focus-rectangle for a single-cell
				CRect rcHighlight;
				CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);

				VERIFY( owner.GetCellRect(nRow, owner.GetFocusCell(), LVIR_BOUNDS, rcHighlight) );

				int cxborder = ::GetSystemMetrics(SM_CXBORDER);

				// When the label column is placed first it has a left-margin 
				if (owner.GetFocusCell()==0 && owner.GetFocusCell()==owner.GetFirstVisibleColumn())
				{
					rcHighlight.left += cxborder*2;
				}
				else
				// Prevent focus rectangle to overlap with cell-image (Only room for this when not first column)
				if (owner.GetFirstVisibleColumn()!=owner.GetFocusCell())
				{
					rcHighlight.left -= cxborder;
				}

				// Adjust rectangle according to grid-lines
				if (owner.GetExtendedStyle() & LVS_EX_GRIDLINES)
				{
					rcHighlight.bottom -= cxborder;
				}

				pDC->DrawFocusRect(rcHighlight);
			}
			else
			if (owner.GetExtendedStyle() & LVS_EX_GRIDLINES)
			{
				// Avoid bug where bottom of focus rectangle is missing when using grid-lines
				//	- Draw the focus-rectangle for the entire row (explicit)
				CRect rcHighlight;
				CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
				// Using LVIR_BOUNDS to get the entire row-rectangle
				VERIFY( owner.GetItemRect(nRow, rcHighlight, LVIR_BOUNDS) );
				
				// Adjust rectangle according to grid-lines
				int cxborder = ::GetSystemMetrics(SM_CXBORDER);
				rcHighlight.bottom -= cxborder;
				pDC->DrawFocusRect(rcHighlight);
			}
		} break;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rolf Kristensen
Software Developer
Denmark Denmark
No Biography provided

You may also be interested in...

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.190214.1 | Last Updated 16 Mar 2015
Article Copyright 2008 by Rolf Kristensen
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid