// 画子控件(支持滚动显示) BOOL CDuiPanel::DrawSubControls(CDC &dc, CRect rcUpdate) { // 如果不需要滚动条,则直接使用父控件的画图方法 if(!m_bEnableScroll || ((m_nVirtualHeight <= m_rc.Height()) && (m_nVirtualWidth <= m_rc.Width()))) { return __super::DrawSubControls(dc, rcUpdate); } BOOL bShowScrollV = m_nVirtualHeight > m_rc.Height(); BOOL bShowScrollH = m_nVirtualWidth > m_rc.Width(); // 计算显示位置 CDuiScrollVertical* pScrollV = (CDuiScrollVertical*)m_pControScrollV; int nCurPosV = pScrollV->GetScrollCurrentPos(); // 当前top位置 int nMaxRangeV = pScrollV->GetScrollMaxRange(); int nVirtualTop = (nMaxRangeV > 0) ? nCurPosV*(m_nVirtualHeight-m_rc.Height())/nMaxRangeV : 0; // 当前显示的是虚拟图片中什么位置开始的图片 CDuiScrollHorizontal* pScrollH = (CDuiScrollHorizontal*)m_pControScrollH; int nCurPosH = pScrollH->GetScrollCurrentPos(); // 当前top位置 int nMaxRangeH = pScrollH->GetScrollMaxRange(); int nVirtualLeft = (nMaxRangeH > 0) ? nCurPosH*(m_nVirtualWidth-m_rc.Width())/nMaxRangeH : 0; // 当前显示的是虚拟图片中什么位置开始的图片 // 根据滚动条位置画子控件 // 初始化虚拟显示dc,并复制背景到虚拟显示dc CBitmap virtualBitmap; CDC virtualDC; virtualDC.CreateCompatibleDC(&dc); virtualBitmap.CreateCompatibleBitmap(&dc, bShowScrollH ? (m_rc.left + m_nVirtualWidth) : (m_rc.right - (bShowScrollV ? m_nScrollWidth : 0)), bShowScrollV ? (m_rc.top + m_nVirtualHeight) : (m_rc.bottom - (bShowScrollH ? m_nScrollWidth : 0)) ); CBitmap* pOldVirtualBitmap = virtualDC.SelectObject(&virtualBitmap); virtualDC.BitBlt(m_rc.left+nVirtualLeft, m_rc.top+nVirtualTop, m_rc.Width()-(bShowScrollV ? m_nScrollWidth : 0), m_rc.Height()-(bShowScrollH ? m_nScrollWidth : 0), &dc, m_rc.left, m_rc.top, SRCCOPY); // 背景复制到虚拟显示dc // 更新区域按照显示区域调整 rcUpdate.OffsetRect(nVirtualLeft, nVirtualTop); // 画子控件到虚拟dc for (size_t i = 0; i < m_vecControl.size(); i++) { CControlBase * pControlBase = m_vecControl.at(i); if (pControlBase && pControlBase->GetVisible() && (pControlBase != m_pControScrollV) && (pControlBase != m_pControScrollH)) { // 如果顶部位置发生了变化,需要重画所有子控件,但会造成速度很慢 if(m_nVirtualTop != nVirtualTop) { pControlBase->UpdateControl(true); } pControlBase->Draw(virtualDC, rcUpdate); } } // 画滚动条,滚动条整个区域都需要更新 m_pControScrollV->Draw(dc, m_pControScrollV->GetRect()); m_pControScrollH->Draw(dc, m_pControScrollH->GetRect()); m_nVirtualTop = nVirtualTop; m_nVirtualLeft = nVirtualLeft; // 虚拟显示dc复制到dc(滚动条部分不用复制) dc.BitBlt(m_rc.left, m_rc.top, m_rc.Width()-(bShowScrollV ? m_nScrollWidth : 0), m_rc.Height()-(bShowScrollH ? m_nScrollWidth : 0), &virtualDC, m_rc.left + nVirtualLeft, m_rc.top + nVirtualTop, SRCCOPY); // 释放虚拟显示dc virtualDC.SelectObject(pOldVirtualBitmap); virtualDC.DeleteDC(); virtualBitmap.DeleteObject(); return TRUE; }