Click to See Complete Forum and Search --> : Change Color of single row in CListCtrl and CTreeCtrl


Markus Grossmann
April 26th, 1999, 09:58 AM
How may I change a single row in a CListCtrl and a CTreeCtrl? SetTextColor changes all rows!

Thanks
Markus

Jonathan
May 23rd, 1999, 09:05 PM
I have the same problem as your. Did you find out the solution?
Will appreciate your help.
Thanks.

Jim Watters
May 25th, 1999, 05:53 PM
Do your own DrawItem and control the color from within there. I send a message back to the control's owner to config the color and another message to config the font.
This is a farly lengthly function it comes from several locations mostly CodeGuru.

void CMyListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// Get the display context for the control.
CDC* pCDC = CDC::FromHandle(lpDrawItemStruct->hDC);
RECT UpdateRect = lpDrawItemStruct->rcItem;
RECT UpdateRect2;
pCDC->GetClipBox(&UpdateRect2);

// Use mask if there is one.
UINT uiFlags(ILD_TRANSPARENT);

COLORREF OldTextColor = pCDC->GetTextColor();
COLORREF OldBackColor;
COLORREF TextColor, NewTextColor;

// Check to see if this item is selected.
if(lpDrawItemStruct->itemState & ODS_SELECTED)
{
TextColor = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
OldBackColor = pCDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
uiFlags |= ILD_BLEND50;
}
else
{
TextColor = GetTextColor();// ::GetSysColor(COLOR_WINDOWTEXT); //
OldBackColor = pCDC->SetBkColor(GetBkColor()); // ::GetSysColor(COLOR_WINDOW));
}

CPen* penOld;
// Create the pen used to draw the gridlines.
CPen pen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNFACE));//COLOR_WINDOWTEXT 1999 05 18

bool bVert = m_dwFlag & fVertGrid ? true : false;
bool bHorz = m_dwFlag & fHorizGrid ? true : false;

if(bVert || bHorz)
{
penOld = pCDC->SelectObject(&pen);
}

// Now walk through columns and draw text.
char szText[256]; // Increase this if you have longer text.
char * pStr;
int offset;
LV_COLUMN lvc;
memset(&lvc, 0, sizeof(lvc));
lvc.mask = LVCF_WIDTH | LVCF_SUBITEM | LVCF_FMT | LVCF_ORDER; // *** added LVCF_SUBITEM and LVCF_FMT to get the columne id and justification
// Get the image list and draw.
CImageList* plistImages = GetImageList(LVSIL_SMALL);
LV_ITEM lvi;

CFont * pOldFont = pCDC->GetCurrentFont();
LOGFONT defaultLF, curLF, newLF;

memset(&defaultLF, 0, sizeof(defaultLF));
GetFont()->GetLogFont(&defaultLF);

if(lpDrawItemStruct->itemState & ODS_FOCUS)
defaultLF.lfWeight = FW_BOLD;

// Create a font now and load it in
HFONT hNewFont = ::CreateFontIndirect(&defaultLF);
SelectObject(pCDC->m_hDC, hNewFont);
curLF = defaultLF;

// Calculate the start and end column from the rectangel that needs to be updated
int nStartCol = 0;
int nEndCol = -1;
bool bDidColorChange = false;

for (int nColumn = nStartCol; GetColumn(nColumn, &lvc); nColumn++)
{
CRect rTextClip;

// First time.
if (nStartCol == nColumn)
{
rTextClip.left = lpDrawItemStruct->rcItem.left + (plistImages ? 16 : 0);
rTextClip.top = lpDrawItemStruct->rcItem.top;
rTextClip.right = lpDrawItemStruct->rcItem.left + lvc.cx;
rTextClip.bottom = lpDrawItemStruct->rcItem.bottom;
}
else
{
// Just "move" the rect to the right.
rTextClip.left = rTextClip.right;
rTextClip.right = rTextClip.left + lvc.cx;
}

// Second column selected and only selecting first column
if( lpDrawItemStruct->itemState & ODS_SELECTED &&
false == bDidColorChange &&
1 <= nColumn &&
fHighRowSelect != (m_dwFlag & fHighRowSelect) )
{
bDidColorChange = true;
TextColor = GetTextColor();//TextColor = ::GetSysColor(COLOR_WINDOWTEXT);
pCDC->SetBkColor(GetBkColor()); //pCDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
}

// Check to see if this needs to be updated If not go to the next column
if(UpdateRect2.right < rTextClip.left || UpdateRect2.left > rTextClip.right)
continue;

memset(&lvi, 0, sizeof(lvi));
lvi.mask = LVIF_IMAGE | LVIF_STATE;
lvi.iItem = lpDrawItemStruct->itemData;
lvi.iSubItem = lvc.iSubItem;

if(m_fpGetItemText != NULL && m_pOwnerWnd != NULL)
{
GetItem(&lvi);
pStr = (m_pOwnerWnd->*m_fpGetItemText)(lvc.iSubItem, lpDrawItemStruct->itemData);//itemID);
}
else
{
// Get the text.
lvi.mask |= LVIF_TEXT;
lvi.iItem = lpDrawItemStruct->itemID;
lvi.iSubItem = lvc.iOrder;
lvi.pszText = szText;
lvi.cchTextMax = sizeof(szText);
GetItem(&lvi);
pStr = szText;
}

// If valid, draw.
if (plistImages)
{
if(lvi.iImage)
{
//CPoint ptAt(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top);
CPoint ptAt(rTextClip.left, rTextClip.top);
plistImages->Draw(pCDC, lvi.iImage, ptAt, uiFlags);
}
}

if(m_dwFlag & fCellFont)
{
newLF = defaultLF;
GetParent()->SendMessage(UM_MLC_GETFONT, (WPARAM)&newLF, MAKELONG(lvi.iItem, lvi.iSubItem));
if(memcmp(&newLF, &curLF, sizeof(curLF)) != 0)// Something changed then change the DC
{
HFONT hOldFont = hNewFont;
hNewFont = ::CreateFontIndirect(&newLF);
SelectObject(pCDC->m_hDC, hNewFont);
::DeleteObject(hOldFont);
curLF = newLF;
}
}

NewTextColor = TextColor;
if(m_dwFlag & fCellColor)
GetParent()->SendMessage(UM_MLC_GETCOLOR, (WPARAM)&NewTextColor, MAKELONG(lvi.iItem, lvi.iSubItem));
pCDC->SetTextColor(NewTextColor);

// Add ellipses if necessary.
int nTextCount(lstrlen(pStr));
CSize sizText(pCDC->GetOutputTextExtent(pStr, nTextCount));

// Make the clipping rectangle a little smaller for a gap effect between columns.
rTextClip.right -= 4;

if (sizText.cx >= rTextClip.Width())
{
// Make a shorter string, including "..." that fits.
CSize sizEllipse = pCDC->GetOutputTextExtent("...", 3);

// Now start dropping characters at the tail until width is correct.
while (sizText.cx+sizEllipse.cx > (rTextClip.Width()) && nTextCount > 1)
{
pStr[--nTextCount] = 0;
sizText = pCDC->GetOutputTextExtent(pStr, nTextCount);
}

// Ok, append "...".
pStr[nTextCount] = '.';
pStr[nTextCount + 1] = '.';
pStr[nTextCount + 2] = '.';
pStr[nTextCount + 3] = 0;

sizText = pCDC->GetOutputTextExtent(pStr, lstrlen(pStr));
}

// Restore full rect.
rTextClip.right += 4;

// we know know it will fit know check the justification
offset =0; //default if(lvc.fmt == LVCFMT_LEFT)
if((lvc.fmt & LVCFMT_RIGHT) == LVCFMT_RIGHT)
offset = max((rTextClip.Width() - sizText.cx) -8 , 0);
else if((lvc.fmt &LVCFMT_CENTER) == LVCFMT_CENTER)
offset = ((rTextClip.Width() - sizText.cx) -4)/2;

// Print the text.
pCDC->ExtTextOut(rTextClip.left + offset + 2, rTextClip.top + 1,
ETO_CLIPPED | ETO_OPAQUE, &rTextClip, pStr,
lstrlen(pStr), NULL);

// Draw the gridlines. leave a gap iff both hor and vert
if (bHorz)
{
pCDC->MoveTo(rTextClip.left + bVert*2, rTextClip.bottom - 1);
pCDC->LineTo(rTextClip.right - bVert, rTextClip.bottom - 1);
}

if (bVert)
{
pCDC->MoveTo(rTextClip.right - 1, rTextClip.top + bHorz);
pCDC->LineTo(rTextClip.right - 1, rTextClip.bottom - bHorz);
}
}

// Reset Font
pCDC->SelectObject(pOldFont);
::DeleteObject(hNewFont);

// Reset colors
pCDC->SetTextColor(OldTextColor); //::GetSysColor(COLOR_WINDOWTEXT));
pCDC->SetBkColor(OldBackColor); //::GetSysColor(COLOR_WINDOW));

// If focused draw focus rect.
if (lpDrawItemStruct->itemState & ODS_FOCUS)
{
CRect rTextClip(lpDrawItemStruct->rcItem);
// rTextClip.left += (plistImages ? 16 : 0);
pCDC->DrawFocusRect(&rTextClip);
}

// We must leave the display context as we found it.
if(bVert || bHorz)
pCDC->SelectObject(penOld);
}


void CMyListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
TEXTMETRIC tm;
HDC hDC = ::GetDC(NULL);
CFont* pFont = GetFont();
HFONT hFontOld = (HFONT)SelectObject(hDC, pFont->GetSafeHandle());
GetTextMetrics(hDC, &tm);
lpMeasureItemStruct->itemHeight = tm.tmHeight + tm.tmExternalLeading + 1;
SelectObject(hDC, hFontOld);
::ReleaseDC(NULL, hDC);
}




In the view I capture my UserMessages


ON_MESSAGE(UM_MLC_GETFONT, OnGetFont)
ON_MESSAGE(UM_MLC_GETCOLOR, OnGetColor)

void CView_List::OnGetFont(WPARAM Wparm, LPARAM Lparm)
{
int row = LOWORD(Lparm);
int col = HIWORD(Lparm);
LOGFONT * pLF = (LOGFONT *)Wparm;
if(pLF)
{
if(col == ID_DESCRIPTION)
pLF->lfItalic = TRUE;
}
}

void CView_List::OnGetColor(WPARAM Wparm, LPARAM Lparm)
{
int row = LOWORD(Lparm);
int col = HIWORD(Lparm);
COLORREF * pColor = (COLORREF *)Wparm;

if(pColor)
{
BYTE Red = GetRValue(*pColor);
BYTE Green = GetGValue(*pColor);
BYTE Blue = GetBValue(*pColor);
double top, bottom, depth;

GetDocument()->GetTopBottom(&top, &bottom);
depth = ((GetItemDouble(LDL_Depth, row) * 2) + GetItemDouble(LDL_Length, row))/2;

Red = (BYTE)((depth + top) * (255.0 / max(1, top - bottom)));
Blue = 255 - Red;

COLORREF Color = RGB(Red, Green, Blue);
*pColor = Color;
}
}