I have a class named CMyListCtrl derived from CListCtrl using LVS_REPORT
with multiple columns. It is owner draw and overrides both OnPaint() and
DrawItem(). OnPaint() is called to draw a series of rectangles that create a
grid-like effect. Then it iterates through all items, populating a
DRAWITEMSTRUCT and calling DrawItem().
Selections are drawn using a distinct background color for the row (which
must be done in OnPaint() so as to preserve the grid effect) and a different
text color (done in DrawItem() ). This works great when the user selects any
item on the list--except the very first one! If the user selects the first
item, the previously selected item is deselected and drawn with the
non-selection colors, but the new selection (index 0) is not drawn with the
selection colors. As soon as I switch the focus to another window or
control, however, the item is repainted correctly and we see it properly
highlighted.
Using breakpoints, I can actually see the correct colors being selected and
the appropriate drawing functions ( FillSolidRect() and DrawText() ) being
called in OnPaint() and DrawItem(), and yet the item remains the same! It's
like it is not being repainted at all. Because when execution hits the
breakpoint the focus switches to the Visual Studio window, a second paint
message is sent to the control. This time it gets redrawn correctly. It is
almost like something is "locking" or maybe even clipping the area of the
first item when the user selects it, but switching the focus seems to
somehow unlock it.
I noticed that if I override only DrawItem and just let the base-class's
OnPaint() do its thing, everything works properly. I also notice the base
class only repaints the old selection and the new selection when the user
clicks on an item, while my version always repaints all items regardless of
what triggered OnPaint()--quite frankly I don't even know how to tell what
triggered the painting so I have no option but to redraw everything.
Does this seem bizarre to anyone or is it just me? I included the code for
DrawItem() and OnPaint() below--sorry, they are still a little rough...
Any help is appreciated!
Thanks,
Silvio
void CMyListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
CBrush brush;
brush.CreateSolidBrush( RGB(255, 255, 0) );
CRect rc;
rc = lpDrawItemStruct->rcItem;
CString csItemText;
GetItemText( lpDrawItemStruct->itemID, 0, csItemText.GetBuffer(255), 255);
csItemText.ReleaseBuffer( -1 );
COLORREF textColor;
if( lpDrawItemStruct->itemState & ODS_SELECTED )
textColor = g_MyLookAndFeel.m_ListItemSecondaryForegroundColor;
else
textColor = g_MyLookAndFeel.m_ListItemPrimaryForegroundColor;
::SetTextColor( lpDrawItemStruct->hDC, textColor );
::SetBkMode( lpDrawItemStruct->hDC, TRANSPARENT );
::DrawText( lpDrawItemStruct->hDC, csItemText.GetBuffer(0),
csItemText.GetLength(), &rc, DT_LEFT );
}
void CMyListCtrl::OnPaint()
{
TRACE("CMyListCtrl::OnPaint()\n");
if( ! (GetStyle() & LVS_REPORT) )
CListCtrl::OnPaint();
else
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Used later to determine which items to draw (not all are visible)
int nFirstVisibleItemIndex = -1;
// Finds the first visible item in the list (in case the list has been
scrolled)
// We use it to figure out where to place the origin of our grid and to
obtain the height of each row
CRect rcFirstVisibleItem( -1, -1, -1, -1 );
for(int nItemIndex = 0; nItemIndex < this->GetItemCount(); nItemIndex++)
{
GetItemRect( nItemIndex, &rcFirstVisibleItem, LVIR_BOUNDS );
if( rcFirstVisibleItem.top > 0)
{
nFirstVisibleItemIndex = nItemIndex;
break;
}
}
// Obtains the rect of the list view window in client coords
CRect rcWindowRect;
int nVisibleRowCount;
GetWindowRect ( &rcWindowRect );
rcWindowRect -= rcWindowRect.TopLeft();
nVisibleRowCount = rcWindowRect.Height() / rcFirstVisibleItem.Height();
// Now we draw each column with the grid effect
CRect rcItemRect;
LVCOLUMN lvColumn;
lvColumn.mask = LVCF_WIDTH;
rcItemRect.left = rcFirstVisibleItem.left;
for( int nColumn = 0; GetColumn( nColumn, &lvColumn ); nColumn++ )
{
// Initializes cell rect
rcItemRect.top = rcFirstVisibleItem.top;
rcItemRect.right = rcItemRect.left + lvColumn.cx;
rcItemRect.bottom = rcItemRect.top + rcFirstVisibleItem.Height();
for( int nRow = 0; nRow < nVisibleRowCount; nRow++ )
{
CRect rcCellRect( &rcItemRect );
// If cell rect falls outside the window rect, then we need not go
through the other rows.
if( rcItemRect.top >= rcWindowRect.bottom )
break;
rcCellRect.DeflateRect(0, 0, 1, 1);
// Draws cell rect
COLORREF cellColor;
if( GetItemState( nRow, LVIS_SELECTED ) )
cellColor = g_MyLookAndFeel.m_ListItemSecondaryBackgroundColor;
else
cellColor = g_MyLookAndFeel.m_ListItemPrimaryBackgroundColor;
dc.FillSolidRect( &rcCellRect, cellColor );
// Adjusts rect for the next row
rcItemRect.OffsetRect(0, rcItemRect.Height() );
}
// Adjusts rect for the next column
rcItemRect.OffsetRect( lvColumn.cx, 0 );
}
// Now we must call DrawItem() for each visible item!
// Finds the first visible item in the list (in case the list has been
scrolled)
// We use it to figure out where to place the origin of our grid and to
obtain the height of each row
for( nItemIndex = nFirstVisibleItemIndex; nItemIndex <
this->GetItemCount(); nItemIndex++ )
{
DRAWITEMSTRUCT drawItemStruct;
CRect rcItemRect;
UINT itemState;
GetItemRect( nItemIndex, &rcItemRect, LVIR_BOUNDS );
// Break if item is past the bottom of the window
if( rcItemRect.top >= rcWindowRect.bottom )
break;
itemState = GetItemState( nItemIndex, -1 );
drawItemStruct.itemState = 0;
drawItemStruct.itemState |= ( itemState & LVIS_SELECTED ? ODS_SELECTED :
0 );
drawItemStruct.itemState |= ( itemState & LVIS_FOCUSED ? ODS_FOCUS : 0 );
drawItemStruct.CtlType = ODT_LISTVIEW;
drawItemStruct.CtlID = GetDlgCtrlID();
drawItemStruct.itemID = nItemIndex;
drawItemStruct.itemAction = ODA_DRAWENTIRE;
drawItemStruct.hwndItem = GetSafeHwnd( );
drawItemStruct.hDC = dc.GetSafeHdc( );
drawItemStruct.rcItem = rcItemRect;
DrawItem( &drawItemStruct );
TRACE("Drawing item %d style: %d", nItemIndex,
drawItemStruct.itemState);
TRACE("\n");
}
}
}
"Silvio Lopes de Oliveira" <slo...@shuf.com> wrote in message
news:bj5ni9$o...@dispatch.concentric.net...
Thanks for your response. However, I can't find any follow-ups to my posts
from last week, from you or anyone else.
If you could do a cut and paste of your reply from last week and repost it I
would greatly appreciate it.
Thanks,
Silvio
"Jeff Partch" <je...@mvps.org> wrote in message
news:%23L0toZm...@TK2MSFTNGP12.phx.gbl...