Owner -
worked example
(task 1, task 2, task 3)
key : purple - original code / blue - new code
Task 1 : Displaying the image and names
Continue with the program names.
Add the LVS_OWNERDRAWFIXED style to the ListCtrl :
void CNameListView::SetListStyle()
{
Add the virtual function DrawItem() to the ListCtrl :
Edit the code to allow the images and names to be displayed :
void CNameListView::DrawItem( LPDRAWITEMSTRUCT
lpdis )
{
CListCtrl& m_listCtrl = GetListCtrl();
CRect rc = lpdis->rcItem;
CDC *pdcTmp = CDC::FromHandle( lpdis->hDC );
// get item data
LV_ITEM lvi;
lvi.iItem = lpdis->itemID;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = 0;
m_listCtrl.GetItem(&lvi);
// Creates a pointer to the CName class
CName* pName = (CName*)lvi.lParam;
// Sets the string values
CString strSecondName = pName->GetSecondName();
CString strTitle = pName->GetTitle();
CString strFirstName = pName->GetFirstName();
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH;
lvc.iSubItem = COLUMN_SECOND_NAME;
// To draw the image
CImageList* pImages = m_listCtrl.GetImageList(LVSIL_SMALL);
if( strTitle == "Mr" || strTitle == "Sir")
{pImages->DrawIndirect(pdcTmp, 0, rc.TopLeft(), CSize(16, 16), CPoint(0, 0));
}
else if( strTitle == "Dr" || strTitle == "Prof")
{pImages->DrawIndirect(pdcTmp, 2, rc.TopLeft(), CSize(16, 16), CPoint(0, 0));
pImages->DrawIndirect(pdcTmp, 1, rc.TopLeft(), CSize(16, 16), CPoint(0, 0));
Task 2 : Displaying the image and names
Add the following code to the DrawItem() function :
void CNameListView::DrawItem( LPDRAWITEMSTRUCT
lpdis )
{
// this is the window focus boolean variable
BOOL bFocus = (GetFocus() == this);// move the rectangle to the right to allow space for the image
rc.left = 17;
// Handle item highlighting:
COLORREF clrBackground;
COLORREF clrText;
COLORREF clrOldBackground;
COLORREF clrOldText;
CBrush* pbrOld;
BOOL bSelectFlag = FALSE;
if( lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT) )
{clrBackground = GetSysColor( COLOR_HIGHLIGHT );
clrText = GetSysColor( COLOR_HIGHLIGHTTEXT );clrBackground = GetSysColor( COLOR_WINDOW );
clrText = GetSysColor( COLOR_WINDOWTEXT );// draw focus rectangle if item has focus
// this will leave the focus rectangle there even
// if the item is not selected
if ( (lpdis->itemState & ODS_FOCUS && bFocus) )
{pdcTmp->DrawFocusRect( rc );
}
// turning grey when the window focus has gone:
if( (lpdis->itemState & ODS_FOCUS && !bFocus) )
{clrBackground = GetSysColor( COLOR_INACTIVECAPTION );
clrText = GetSysColor( COLOR_WINDOWTEXT );
// Fill the item's rectangle with the new color
CBrush brHighlight( clrBackground );
pdcTmp->FillRect( rc, &brHighlight );}
// move the rectangle back to the left
rc.left = 0;pImages->DrawIndirect(pdcTmp, 0, rc.TopLeft(), CSize(16, 16), CPoint(0, 0));
}
else if( strTitle == "Dr" || strTitle == "Prof")
{pImages->DrawIndirect(pdcTmp, 2, rc.TopLeft(), CSize(16, 16), CPoint(0, 0));
pImages->DrawIndirect(pdcTmp, 1, rc.TopLeft(), CSize(16, 16), CPoint(0, 0));
Task 3 : Trimming the strings
Step 3.1 :
Add the new function MakeShortString() :
BOOL
CNameListView::MakeShortString(CDC *pDC, CString &strTemp,
int nColumnWidth, int nOffset)
{
// if the string does not need trimming then leave this function
if( (pDC->GetTextExtent(strTemp).cx + nOffset) < nColumnWidth )
{return(FALSE);
}
// tell the program that the string HAS been changed
bool bChanged = TRUE;
int nStringLength = strTemp.GetLength();
int nTrim = nStringLength;
int nInc = 1;
// calculate the required number of letters needed to be trimmed from
// the string to allow the three dots to appear
do
{strTemp = strTemp.Left(nTrim - nInc);
nInc++;
nStringLength = strTemp.GetLength();
// never allow all the letters to be chopped!!!
if( nStringLength == 1 )
break;}
while( (pDC->GetTextExtent(strTemp, nStringLength).cx) +
(pDC->GetTextExtent("...").cx) + nOffset > nColumnWidth);
// change the value of strTemp in the memory to include the three dots
strTemp = strTemp + "...";
return(bChanged);
}
Step 3.2 :
Call this function before each DrawText() command in the DrawItem() function :
// Draws the text in the rectangle - leaving room for the icon
rc.left += nOffset;
BOOL bHasStringBeenShortened = FALSE;
bHasStringBeenShortened = MakeShortString( pdcTmp, strSecondName,
lvc.cx, nOffset );
pdcTmp->DrawText( strSecondName, rc, DT_LEFT | DT_SINGLELINE );
rc.left -= nOffset;
if( bSelectFlag ) // Item currently selected
{// Pen and background colours need to be changed back to normal
// the second two columns will be penned in black not white!
pdcTmp->SetBkColor( clrOldBackground );
pdcTmp->SetTextColor( clrOldText );
pdcTmp->SelectObject( pbrOld );}
nOffset = 6;
lvc.iSubItem = COLUMN_TITLE;
m_listCtrl.GetColumn(COLUMN_TITLE, &lvc);
rc.left = rc.right;
rc.right += lvc.cx;
rc.left += nOffset;
bHasStringBeenShortened = MakeShortString( pdcTmp, strTitle, lvc.cx, nOffset );
pdcTmp->DrawText( strTitle, rc, DT_LEFT | DT_SINGLELINE );
rc.left -= nOffset;
if( bHasStringBeenShortened )m_listCtrl.InvalidateRect(rc, FALSE);
lvc.iSubItem = COLUMN_FIRST_NAME;
m_listCtrl.GetColumn(COLUMN_FIRST_NAME, &lvc);
rc.left = rc.right;
rc.right += lvc.cx;
rc.left += nOffset;
bHasStringBeenShortened = MakeShortString( pdcTmp, strFirstName, lvc.cx, nOffset );
pdcTmp->DrawText( strFirstName, rc, DT_LEFT | DT_SINGLELINE );
rc.left -= nOffset;
if( bHasStringBeenShortened )m_listCtrl.InvalidateRect(rc, FALSE);
}
Click here for the basic exercise
Click here for the source code
Click here to return to menu