📄 background_image.shtml.htm
字号:
}
CRect rcFirstItem;
GetItemRect(0, rcFirstItem, LVIR_BOUNDS);
for( int i = rcFirstItem.left; i < rcClient.right; i += m_cxBitmap )
for( int j = rcFirstItem.top; j < rcClient.bottom; j += m_cyBitmap )
pDC->BitBlt( i, j, m_cxBitmap, m_cyBitmap, &tempDC,
0, 0, SRCCOPY );
}
</b>
// Draw the background color
if( bHighlight )
{
pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
pDC->FillRect(rcHighlight, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
}
<b> else if( m_bitmap.m_hObject == NULL )
pDC->FillRect(rcHighlight, &CBrush(::GetSysColor(COLOR_WINDOW)));
</b>
// Set clip region
rcCol.right = rcCol.left + GetColumnWidth(0);
CRgn rgn;
rgn.CreateRectRgnIndirect(&rcCol);
pDC->SelectClipRgn(&rgn);
rgn.DeleteObject();
// Draw state icon
if (lvi.state & LVIS_STATEIMAGEMASK)
{
int nImage = ((lvi.state & LVIS_STATEIMAGEMASK)>>12) - 1;
pImageList = GetImageList(LVSIL_STATE);
if (pImageList)
{
pImageList->Draw(pDC, nImage,
CPoint(rcCol.left, rcCol.top), ILD_TRANSPARENT);
}
}
// Draw normal and overlay icon
pImageList = GetImageList(LVSIL_SMALL);
if (pImageList)
{
UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
pImageList->Draw(pDC, lvi.iImage,
CPoint(rcIcon.left, rcIcon.top),
(bHighlight?ILD_BLEND50:0) | ILD_TRANSPARENT | nOvlImageMask );
}
// Draw item label - Column 0
rcLabel.left += offset/2;
rcLabel.right -= offset;
pDC->DrawText(sLabel,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP
| DT_VCENTER | DT_END_ELLIPSIS);
// Draw labels for remaining columns
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH;
if( m_nHighlight == 0 ) // Highlight only first column
{
pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
}
rcBounds.right = rcHighlight.right > rcBounds.right ? rcHighlight.right :
rcBounds.right;
rgn.CreateRectRgnIndirect(&rcBounds);
pDC->SelectClipRgn(&rgn);
for(int nColumn = 1; GetColumn(nColumn, &lvc); nColumn++)
{
rcCol.left = rcCol.right;
rcCol.right += lvc.cx;
// Draw the background if needed
if( m_bitmap.m_hObject == NULL && m_nHighlight == HIGHLIGHT_NORMAL )
pDC->FillRect(rcCol, &CBrush(::GetSysColor(COLOR_WINDOW)));
sLabel = GetItemText(nItem, nColumn);
if (sLabel.GetLength() == 0)
continue;
// Get the text justification
UINT nJustify = DT_LEFT;
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
{
case LVCFMT_RIGHT:
nJustify = DT_RIGHT;
break;
case LVCFMT_CENTER:
nJustify = DT_CENTER;
break;
default:
break;
}
rcLabel = rcCol;
rcLabel.left += offset;
rcLabel.right -= offset;
pDC->DrawText(sLabel, -1, rcLabel, nJustify | DT_SINGLELINE
| DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS);
}
// Draw focus rectangle if item has focus
if (lvi.state & LVIS_FOCUSED && (GetFocus() == this))
pDC->DrawFocusRect(rcHighlight);
// Restore dc
pDC->RestoreDC( nSavedDC );
}
</FONT></TT></PRE>
<h4>Step 5: Add handler for WM_ERASEBKGND</h4>
When an image is being used as a background, erasing the background does not make sense since the image will be drawn over the background anyway. Erasing the background will simply cause a flicker. The handler returns TRUE if the bitmap object is valid.
<PRE><TT><FONT COLOR="#990000">BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
if( m_bitmap.m_hObject != NULL )
return TRUE;
return CListCtrl::OnEraseBkgnd(pDC);
}
</FONT></TT></PRE>
<h4>Step 6: Override OnNotify() and handle column resizing</h4>
When a column is resized, only the newly exposed area is painted. This causes an unattractive effect on the background image. We should therefore invalidate the right side of the control whenever a column is resized in the OnNotify() function. I tried using the HDN_TRACK notification but it appeared that this notification was not being generated. The HDN_ITEMCHANGING notification works fine though.
<PRE><TT><FONT COLOR="#990000">BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
// This code is for using bitmap in the background
// Invalidate the right side of the control when a column is resized
if(pHDN->hdr.code == HDN_ITEMCHANGINGW || pHDN->hdr.code == HDN_ITEMCHANGINGA)
{
if( m_bitmap.m_hObject != NULL )
{
CRect rcClient;
GetClientRect( &rcClient );
DWORD dwPos = GetMessagePos();
CPoint pt( LOWORD(dwPos), HIWORD(dwPos) );
ScreenToClient( &pt );
rcClient.left = pt.x;
InvalidateRect( &rcClient );
}
}
return CListCtrl::OnNotify(wParam, lParam, pResult);
}
</FONT></TT></PRE>
<h4>Step 7: Handle WM_QUERYNEWPALETTE & WM_PALETTECHANGED</h4>
The WM_QUERYNEWPALETTE message is sent to a window when it is about to receive input focus. It gives the window an oppurtunity to realize its logical palette so that it can present itself in the best form. The WM_PALETTECHANGED message is sent to a window whenever that system palette is changed. If we do not handle these messages and another application changes the system palette then the colors in our background image will look terrible. Unfortunately both these messages are sent to top level windows. We will deal with that in the next step.
<p>The OnQueryNewPalette() function first checks whether it needs to reselect the palette. Once it realizes the logical palette it invalidates the window if any of the color were remapped. The OnPaletteChanged() function returns without any further processing if the list view control itself was responsible for the message because it changed the palette. It then calls OnQueryNewPalette() to rerealize the palette.
<PRE><TT><FONT COLOR="#990000">BOOL CMyListCtrl::OnQueryNewPalette()
{
CClientDC dc(this);
if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
{
dc.SelectPalette( &m_pal, FALSE );
BOOL result = dc.RealizePalette();
if( result )
Invalidate();
return result;
}
return CListCtrl::OnQueryNewPalette();
}
void CMyListCtrl::OnPaletteChanged(CWnd* pFocusWnd)
{
CListCtrl::OnPaletteChanged(pFocusWnd);
if( pFocusWnd == this )
return;
OnQueryNewPalette();
}
</FONT></TT></PRE>
<h4>Step 8: Forward palette messages from top level window</h4>
As I've already mentioned in the previous step, the WM_QUERYNEWPALETTE & WM_PALETTECHANGED messages are sent only to top level windows. Since the list view control had changed the palette we have to forward these messages to the list view control. I had used a dialog based application to test this so here's what the handlers look like.
<PRE><TT><FONT COLOR="#990000">void CListViewDlg::OnPaletteChanged(CWnd* pFocusWnd)
{
CDialog::OnPaletteChanged(pFocusWnd);
m_listctrl.SendMessage( WM_PALETTECHANGED, (WPARAM)pFocusWnd->m_hWnd );
}
BOOL CListViewDlg::OnQueryNewPalette()
{
CDialog::OnQueryNewPalette();
return m_listctrl.SendMessage( WM_QUERYNEWPALETTE );
}
</FONT></TT></PRE>
<BR>
<P>
<HR>
<TABLE BORDER=0 WIDTH="100%" >
<TR>
<TD WIDTH="33%"><FONT SIZE=-1><A HREF="../index.htm" tppabs="http://www.codeguru.com/">Goto HomePage</A></FONT></TD>
<TD WIDTH="33%">
<CENTER><FONT SIZE=-2>© 1997 Zafir Anjum</FONT> </CENTER>
</TD>
<TD WIDTH="34%">
<DIV ALIGN=right><FONT SIZE=-1>Contact me: <A HREF="mailto:zafir@home.com">zafir@home.com</A> </FONT></DIV>
</TD>
</TR>
</TABLE>
<CENTER><IMG SRC="../cgi/Count.cgi-ft=2&dd=E-df=lv_background_image.cnt" tppabs="http://www.codeguru.com/cgi/Count.cgi?ft=2&dd=E%7cdf=lv_background_image.cnt" ALIGN="BOTTOM" BORDER="0"></CENTER>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -