要求:在视中绘制图片,并可以滚动窗体,为解决闪烁,我使用了内存DC.
方案:在视类中声明两个DC,一个用于内存绘图,一个用于辅助DC.
用法:内存DC主要用于绘制图像,而辅助DC主要用于解决坐标问题.
代码如下:
class CMapModeView : public CView
{
protected: // create from serialization only
CMapModeView();
DECLARE_DYNCREATE(CMapModeView)
// Attributes
public:
CMapModeDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMapModeView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
virtual void OnInitialUpdate();
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
CRect m_ClientRect;
CRect m_rect; //用逻辑标绘制矩形
void DrawBG(CDC *pDC); //绘制背景
CBitmap *oldbmp;
CBitmap bmp;
CBitmap *m_pBitmap; //兼容位图
CDC MemDC; //兼容DC
CDC *m_pDC; //辅助DC,用于控制DC原点
int nFontHeight;
//CFont m_font,*m_oldfont;
vector<CRect> m_vectorRect; //保存矩形
//尺寸
UINT m_uWidth;
UINT m_uHeight;
virtual ~CMapModeView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CMapModeView)
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnSize(UINT nType, int cx, int cy);
//}}AFX_MSG
afx_msg void OnDrawRect(WPARAM wParam,LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
实现:
//#include <vector>
//using std::vector;
/
// CMapModeView
IMPLEMENT_DYNCREATE(CMapModeView, CView)
BEGIN_MESSAGE_MAP(CMapModeView, CView)
//{{AFX_MSG_MAP(CMapModeView)
ON_WM_RBUTTONDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_CREATE()
ON_WM_KEYDOWN()
ON_WM_CHAR()
ON_WM_ERASEBKGND()
ON_WM_SIZE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_DRAWRECT,OnDrawRect)
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
/
// CMapModeView construction/destruction
CMapModeView::CMapModeView()
{
// TODO: add construction code here
m_pDC=NULL;
oldbmp=NULL;
m_pBitmap=NULL;
m_uWidth=0;
m_uHeight=0;
}
CMapModeView::~CMapModeView()
{
MemDC.SelectObject(oldbmp);
MemDC.DeleteDC();
if(m_pBitmap!=NULL)
delete m_pBitmap;
if(m_pDC!=NULL)
delete m_pDC;
}
BOOL CMapModeView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/
// CMapModeView drawing
void CMapModeView::OnDraw(CDC* pDC)
{
CMapModeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CPoint pt=m_pDC->GetViewportOrg();
MemDC.SetViewportOrg(pt);
pDC->BitBlt(0,0,m_uWidth,m_uHeight,&MemDC,0,0,SRCCOPY);
}
/
// CMapModeView printing
BOOL CMapModeView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CMapModeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CMapModeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/
// CMapModeView diagnostics
#ifdef _DEBUG
void CMapModeView::AssertValid() const
{
CView::AssertValid();
}
void CMapModeView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMapModeDoc* CMapModeView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMapModeDoc)));
return (CMapModeDoc*)m_pDocument;
}
#endif //_DEBUG
/
// CMapModeView message handlers
void CMapModeView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//CClientDC dc(this);
ASSERT_VALID(m_pDC);
m_pDC->DPtoLP(&point);
CRect rect(point.x-100,point.y-150,point.x+100,point.y+150);
m_vectorRect.push_back(rect);
m_rect.SetRect(rect.left,rect.top,rect.right,rect.bottom);
//发送消息
SendMessage(WM_DRAWRECT,NULL,NULL);
CView::OnRButtonDown(nFlags, point);
}
void CMapModeView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
ASSERT_VALID(m_pDC);
MemDC.SetMapMode(MM_ANISOTROPIC);
MemDC.SetWindowExt(CSize(4,4));
MemDC.SetViewportExt(CSize(2,2));
CView::OnPrepareDC(pDC, pInfo);
}
void CMapModeView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
if(m_pDC==NULL)
{
m_pDC=new CClientDC(this);
ASSERT_VALID(m_pDC);
if(MemDC.CreateCompatibleDC(m_pDC)==NULL)
{
TRACE("/t setup memory device context failed!");
return;
}
}
//初始化画布尺寸
m_uWidth=4000;
m_uHeight=4000;
if(m_pBitmap==NULL)
{
m_pBitmap=new CBitmap();
m_pBitmap->CreateCompatibleBitmap(m_pDC,m_uWidth,m_uHeight);
oldbmp=MemDC.SelectObject(m_pBitmap);
m_pBitmap->DeleteObject();
}
//获取客户区大小
GetClientRect(&m_ClientRect);
//绘制背景
this->DrawBG(&MemDC);
}
int CMapModeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
return 0;
}
void CMapModeView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// CClientDC dc(this);
//向上移动
CPoint pt;
pt=m_pDC->GetViewportOrg();
//确定能移动的范围
if(m_uHeight-pt.y>m_ClientRect.Height())
{
m_pDC->SetViewportOrg(CPoint(pt.x,pt.y+50));
// MemDC.SetViewportOrg(CPoint(pt.x,pt.y-50));
}
//更新屏幕
InvalidateRect(NULL);
//UpdateWindow();
CView::OnLButtonDown(nFlags, point);
}
void CMapModeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
//CClientDC dc(this);
//向下,原点应该增大
if(nChar==VK_SPACE)
{
CPoint pt=m_pDC->GetViewportOrg();
if((pt.y-50)<0)
return;
m_pDC->SetViewportOrg(CPoint(pt.x,pt.y-50));
// MemDC.SetViewportOrg(CPoint(pt.x,pt.y+50));
//更新显示
InvalidateRect(NULL);
}
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CMapModeView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CView::OnChar(nChar, nRepCnt, nFlags);
}
BOOL CMapModeView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return FALSE; //不擦除
//return CView::OnEraseBkgnd(pDC);
}
//绘制画布背景
void CMapModeView::DrawBG(CDC *pDC)
{
ASSERT_VALID(m_pBitmap);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_MEMDCBG);
CBrush brush;
brush.CreatePatternBrush(&bitmap);
//填充矩形
pDC->FillRect(CRect(0,0,m_uWidth,m_uHeight),&brush);
bitmap.DeleteObject();
brush.DeleteObject();
}
//动态获取客户区大小
void CMapModeView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
//获取客户区大小
GetClientRect(&m_ClientRect);
InvalidateRect(NULL);
}
//在内存中绘制矩形
void CMapModeView::OnDrawRect(WPARAM wParam,LPARAM lParam)
{
//用逻辑坐标绘制
CBitmap bm;
bm.LoadBitmap(IDB_WIFEBMP);
CBrush brush;
brush.CreatePatternBrush(&bm);
MemDC.FillRect(&m_rect,&brush);
bm.DeleteObject();
brush.DeleteObject();
//发送WM_PAINT消息进行绘制动作
InvalidateRect(NULL);
}