Board index » Visual Studio » Owner-draw CListCtrl selection problem

Owner-draw CListCtrl selection problem

Visual Studio243
Hello all,



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");

}

}

}


-
 

Re:Owner-draw CListCtrl selection problem

"Silvio Lopes de Oliveira" <slopes@shuf.com>wrote in message

Quote
Hi Jeff,



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.



www.google.com/groups&lr=&ie=UTF-8&oe=UTF-8&threadm=ee2fy7zbDHA.1744%40TK2MSFTNGP12.phx.gbl&rnum=1&prev=/groups%3Fq%3DRWM_INTERNALUPDATE%2Bgroup:microsoft.public.*%2Bauthor:Jeff%2Bauthor:Partch%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3Dee2fy7zbDHA.1744%2540TK2MSFTNGP12.phx.gbl%26rnum%3D1">www.google.com/groups&lr=&ie=UTF-8&oe=UTF-8&threadm=ee2fy7zbDHA.1744%40TK2MSFTNGP12.phx.gbl&rnum=1&prev=/groups%3Fq%3DRWM_INTERNALUPDATE%2Bgroup:microsoft.public.*%2Bauthor:Jeff%2Bauthor:Partch%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3Dee2fy7zbDHA.1744%2540TK2MSFTNGP12.phx.gbl%26rnum%3D1



--

Jeff Partch [VC++ MVP]





-