存在的问题:
(1)鼠标移动画方框时,直线动画不稳,闪烁,有时出现边框线擦除不净和重影的现象,不象PhotoShop中选择框非常稳定无闪烁;
(2)双击点击子窗体标题栏时,方框出现在鼠标点击处。
(3)pDoc->m_pDrawInfo->m_rect.NormalizeRect(); 并不能调整m_rect,就是鼠标移动点在开始点上方或左侧时,方框变成一条直线,并跟着鼠标移动,为何?
(4)不用多线程,而用定时器时,当不按鼠标连续移动时,动画就不动了,为何?
1.用Visual Studio创建一个多文档项目:
文件→新建→项目,在“新建项目”对话框中:Visual C++→MFC→MFC应用程序,在“名称”栏中输入“DrawAntLine”,点击“确定”。
2.在“MFC应用程序向导”中,应用类型选择“多个文档”和“文档/视图结构支持”,点击“完成”。
3.在stdafx.h头文件中定义如下结构:
typedef struct CDrawInfo
{
HDC    m_hDC;
CRect  m_rect;
}CDrawInfo;
4.添加一个多线程类。在“类视图”中:添加→类→MFC→MFC类→类名“CAntLineThread”→基类“CWinThread”→“确定”。清单如下:
/////AntLineThread.h//////////////////
#pragma once
#include "stdafx.h"
//---------------------------------------------------------------------------
void DrawTheRect(LPARAM pParam);
class CAntLineThread : public CWinThread
{
DECLARE_DYNCREATE(CAntLineThread)protected:
void DrawAntLine();public:
CDrawInfo *m_DrawInfo;
bool m_bContinue;
bool m_bDraw; CAntLineThread();           // 动态创建所使用的受保护的构造函数
virtual ~CAntLineThread();public:
virtual BOOL InitInstance();
virtual int ExitInstance();protected:
DECLARE_MESSAGE_MAP()
};
//---------------------------------------------------------------------------
/////AntLineThread.cpp//////////////////
#include "stdafx.h"
#include "DrawAntLine.h"
#include "AntLineThread.h"
DWORD Counter = 0;
DWORD CounterStart = 0;
void CALLBACK MovingDots(int X, int Y, LPARAM lpData)
{
CDrawInfo *pInfo = (CDrawInfo*)lpData;
CDC *pDC = CDC::FromHandle(pInfo->m_hDC); Counter = (Counter + 1) % 10; COLORREF vColor;
if (Counter < 5) vColor = RGB(255,255,255);
else vColor = RGB(0,0,0);
pDC->SetPixel(X,Y,vColor);
}
//---------------------------------------------------------------------------void DrawTheRect(LPARAM pParam)
{
CDrawInfo *pDrawInfo = (CDrawInfo*)pParam;
CRect R = pDrawInfo->m_rect; // Determines starting  pixel color of Rect
Counter = CounterStart;
  
// Use LineDDA to draw each of the 4 edges of the rectangle
LineDDA(R.right, R.top,    R.left, R.top,    (LINEDDAPROC)MovingDots, (long)pDrawInfo);
LineDDA(R.left,  R.bottom, R.left, R.top,    (LINEDDAPROC)MovingDots, (long)pDrawInfo);
LineDDA(R.right, R.bottom, R.right,R.top,    (LINEDDAPROC)MovingDots, (long)pDrawInfo);
     LineDDA(R.right, R.bottom, R.left, R.bottom, (LINEDDAPROC)MovingDots, (long)pDrawInfo);  
}
//---------------------------------------------------------------------------IMPLEMENT_DYNCREATE(CAntLineThread, CWinThread)
BEGIN_MESSAGE_MAP(CAntLineThread, CWinThread)
END_MESSAGE_MAP()
//---------------------------------------------------------------------------CAntLineThread::CAntLineThread()
{
m_DrawInfo = NULL;
m_bDraw    = false;
}
//---------------------------------------------------------------------------CAntLineThread::~CAntLineThread()
{
}
//---------------------------------------------------------------------------BOOL CAntLineThread::InitInstance()
{
DrawAntLine();
return true;
}
//---------------------------------------------------------------------------int CAntLineThread::ExitInstance()
{
return CWinThread::ExitInstance();
}
//---------------------------------------------------------------------------void CAntLineThread::DrawAntLine()
{
m_bContinue = true;
m_bDraw     = false; while (m_bContinue)
{
if (m_DrawInfo && m_bDraw)
{
CounterStart = (CounterStart+1) % 0XFFFFFFFF;
DrawTheRect((LPARAM)m_DrawInfo);
}
Sleep(60);
} if (!m_bContinue) AfxEndThread(0); 
}
//---------------------------------------------------------------------------

解决方案 »

  1.   

    5.在“资源视图”中新建菜单项:Menu→IDR_DrawAntLineTYPE添加菜单“线程”其中包括“启动”和“停止”,其ID分别为“ID_BUTTON_STOP”和“ID_BUTTON_STOP”。
    6.在DrawAntLine.h中的CDrawAntLineApp添加
    ...
    public:
    CAntLineThread *m_pAntLineThread;
    DWORD m_Tool;
    ...
    7.在DrawAntLine.cpp中添加如下代码:
    CDrawAntLineApp::CDrawAntLineApp()
    {
    m_pAntLineThread = NULL;
    m_Tool = 0;
    }CDrawAntLineApp::~CDrawAntLineApp()
    {
    if (m_pAntLineThread != NULL) m_pAntLineThread->m_bContinue = false;
    m_pAntLineThread = NULL;
    }BOOL CDrawAntLineApp::InitInstance()
    {
    CWinApp::InitInstance(); m_pAntLineThread = (CAntLineThread *)AfxBeginThread(RUNTIME_CLASS(CAntLineThread));
    ...
    }
    8.在类CDrawAntLineDoc中添加:
    public:
    CDrawInfo* m_pDrawInfo;
    并在其构造函数中写:m_pDrawInfo=NULL;
    9.在类CDrawAntLineView中分别添加以下消息函数:
    WM_SETFOCUS、WM_KILLFOCUS、WM_ERASEBKGND、WM_CREATE、WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP、ID_BUTTON_RUN、ID_BUTTON_STOP。
    清单如下:
    /////DrawAntLineView.h//////////////////
    // DrawAntLineView.h : CDrawAntLineView 类的接口
    //#pragma onceclass CDrawAntLineView : public CView
    {
    protected: // 仅从序列化创建
    CDrawAntLineView();
    DECLARE_DYNCREATE(CDrawAntLineView)// 属性
    public:

    CDrawAntLineDoc* GetDocument() const;// 操作
    public:
    // 重写
    public:
    virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    protected:// 实现
    public:
    virtual ~CDrawAntLineView();
    #ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
    #endifprotected:// 生成的消息映射函数
    protected:
    DECLARE_MESSAGE_MAP()
    public:
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnButtonRun();
    afx_msg void OnButtonStop();
    afx_msg void OnUpdateButtonRun(CCmdUI *pCmdUI);
    afx_msg void OnUpdateButtonStop(CCmdUI *pCmdUI);
    afx_msg void OnSetFocus(CWnd* pOldWnd);
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    };#ifndef _DEBUG  // DrawAntLineView.cpp 中的调试版本
    inline CDrawAntLineDoc* CDrawAntLineView::GetDocument() const
       { return reinterpret_cast<CDrawAntLineDoc*>(m_pDocument); }
    #endif
      

  2.   


    /////DrawAntLineView.cpp//////////////////
    // DrawAntLineView.cpp : CDrawAntLineView 类的实现
    //
    //---------------------------------------------------------------------------
    #include "stdafx.h"
    #include "DrawAntLine.h"
    #include "DrawAntLineDoc.h"
    #include "DrawAntLineView.h"
    //---------------------------------------------------------------------------
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    //---------------------------------------------------------------------------
    IMPLEMENT_DYNCREATE(CDrawAntLineView, CView)
    //---------------------------------------------------------------------------
    BEGIN_MESSAGE_MAP(CDrawAntLineView, CView)
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_COMMAND(ID_BUTTON_RUN, &CDrawAntLineView::OnButtonRun)
    ON_COMMAND(ID_BUTTON_STOP, &CDrawAntLineView::OnButtonStop)
    ON_UPDATE_COMMAND_UI(ID_BUTTON_RUN, &CDrawAntLineView::OnUpdateButtonRun)
    ON_UPDATE_COMMAND_UI(ID_BUTTON_STOP, &CDrawAntLineView::OnUpdateButtonStop)
    ON_WM_SETFOCUS()
    ON_WM_KILLFOCUS()
    ON_WM_ERASEBKGND()
    ON_WM_CREATE()
    END_MESSAGE_MAP()
    //---------------------------------------------------------------------------// CDrawAntLineView 构造/析构
    CDrawAntLineView::CDrawAntLineView()
    {
    }
    //-----------------------------------------------------------------------------CDrawAntLineView::~CDrawAntLineView()
    {
    }
    //-----------------------------------------------------------------------------BOOL CDrawAntLineView::PreCreateWindow(CREATESTRUCT& cs)
    {
    return CView::PreCreateWindow(cs);
    }
    //-----------------------------------------------------------------------------int CDrawAntLineView::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CView::OnCreate(lpCreateStruct) == -1) return -1; CDrawAntLineDoc* pDoc = GetDocument();
    if (!pDoc) return -1;
        
    if (pDoc->m_pDrawInfo == NULL)
    {
    pDoc->m_pDrawInfo = new CDrawInfo;
    pDoc->m_pDrawInfo->m_rect = CRect(-1,-1,-1,-1);
    pDoc->m_pDrawInfo->m_hDC  = GetDC()->m_hDC;
    theApp.m_pAntLineThread->m_DrawInfo = pDoc->m_pDrawInfo;
    }
    return 0;
    }
    //-----------------------------------------------------------------------------// CDrawAntLineView 绘制
    void CDrawAntLineView::OnDraw(CDC* pDC)
    {
    CDrawAntLineDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc || pDoc->m_pDrawInfo == NULL) return; CDC dcMem; // 用于缓冲作图的内存DC
    CBitmap bm; // 内存中承载临时图象的位图
    CRect rect;
    GetClientRect(&rect); // Step 1:为屏幕DC创建兼容的内存DC :CreateCompatibleDC()
    dcMem.CreateCompatibleDC(pDC); // Step 2:创建位图:CreateCompatibleBitmap()
    bm.CreateCompatibleBitmap(&dcMem, rect.Width(), rect.Height()); // Step 3:把位图选入设备环境:SelectObject(),可以理解为选择画布
    dcMem.SelectObject(&bm); // 按原来背景填充客户区,不然会是黑色
    dcMem.FillSolidRect(rect,pDC->GetBkColor()); pDoc->m_pDrawInfo->m_hDC = dcMem.m_hDC; // 画图(矩形)
    DrawTheRect((LPARAM)pDoc->m_pDrawInfo);

    // Step 4:把绘制好的图形“拷贝“到屏幕上:BitBlt()
    pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);

    dcMem.DeleteDC(); // 删除DC
    bm.DeleteObject(); // 删除位图
    pDoc->m_pDrawInfo->m_hDC = GetDC()->m_hDC;

    }
    //-----------------------------------------------------------------------------BOOL CDrawAntLineView::OnEraseBkgnd(CDC* pDC)
    {
    return CView::OnEraseBkgnd(pDC);
    }
    //-----------------------------------------------------------------------------// CDrawAntLineView 诊断
    #ifdef _DEBUG
    void CDrawAntLineView::AssertValid() const
    {
    CView::AssertValid();
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::Dump(CDumpContext& dc) const
    {
    CView::Dump(dc);
    }
    //-----------------------------------------------------------------------------CDrawAntLineDoc* CDrawAntLineView::GetDocument() const // 非调试版本是内联的
    {
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDrawAntLineDoc)));
    return (CDrawAntLineDoc*)m_pDocument;
    }
    #endif //_DEBUG
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnLButtonDown(UINT nFlags, CPoint point)
    {
    CDrawAntLineDoc *pDoc = GetDocument();
    if (!pDoc || pDoc->m_pDrawInfo == NULL) return;
    OnUpdate(this, NULL, NULL); // RemoveTheRect, Erase any existing rectangle
      
    switch (theApp.m_Tool)
    {
    case ID_BUTTON_RUN:
    pDoc->m_pDrawInfo->m_rect.left   = point.x;
    pDoc->m_pDrawInfo->m_rect.top    = point.y;
    pDoc->m_pDrawInfo->m_rect.right  = point.x;
    pDoc->m_pDrawInfo->m_rect.bottom = point.y; theApp.m_pAntLineThread->m_DrawInfo = pDoc->m_pDrawInfo;
    break; default : // 没有选择蚂蚁线工具,若已经设置了选取,则清空选区
    pDoc->m_pDrawInfo->m_rect = CRect(-1,-1,-1,-1);
    break;
    } CView::OnLButtonDown(nFlags, point);
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnMouseMove(UINT nFlags, CPoint point)
    {
    CDrawAntLineDoc* pDoc = GetDocument();
    if ( pDoc == NULL || pDoc->m_pDrawInfo == NULL) return; switch (theApp.m_Tool)
    {
    case ID_BUTTON_RUN:
    if (nFlags == MK_LBUTTON)
    {
    OnUpdate(this, NULL, NULL); // RemoveTheRect
    pDoc->m_pDrawInfo->m_rect.right  = point.x;
    pDoc->m_pDrawInfo->m_rect.bottom = point.y;
    // pDoc->m_pDrawInfo->m_rect.NormalizeRect(); // 并不能调整m_rect?
    theApp.m_pAntLineThread->m_DrawInfo = pDoc->m_pDrawInfo;
    }
    break;
    } CView::OnMouseMove(nFlags, point);
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnLButtonUp(UINT nFlags, CPoint point)
    {
    CDrawAntLineDoc *pDoc = GetDocument();
    if (!pDoc || pDoc->m_pDrawInfo == NULL) return;

    switch (theApp.m_Tool)
    {
    case ID_BUTTON_RUN :
    pDoc->m_pDrawInfo->m_rect.right  = point.x;
    pDoc->m_pDrawInfo->m_rect.bottom = point.y;
    theApp.m_pAntLineThread->m_DrawInfo = pDoc->m_pDrawInfo;
    break;
    } CView::OnLButtonUp(nFlags, point);
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnButtonRun()
    {
    theApp.m_Tool = ID_BUTTON_RUN;
    theApp.m_pAntLineThread->m_bDraw = true;
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnButtonStop()
    {
    theApp.m_Tool = ID_BUTTON_STOP;
    theApp.m_pAntLineThread->m_bDraw = false;
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnUpdateButtonRun(CCmdUI *pCmdUI)
    {
    pCmdUI->Enable(theApp.m_Tool != ID_BUTTON_RUN);
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnUpdateButtonStop(CCmdUI *pCmdUI)
    {
    pCmdUI->Enable(theApp.m_Tool == ID_BUTTON_RUN);
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnSetFocus(CWnd* pOldWnd)
    {
    CView::OnSetFocus(pOldWnd);
    CDrawAntLineDoc *pDoc = GetDocument();
    if (!pDoc || pDoc->m_pDrawInfo == NULL) return;
    theApp.m_pAntLineThread->m_DrawInfo = pDoc->m_pDrawInfo;
    }
    //-----------------------------------------------------------------------------void CDrawAntLineView::OnKillFocus(CWnd* pNewWnd)
    {
    CView::OnKillFocus(pNewWnd); // 当前视图失去焦点时,更新视图,抹去一些绘图信息(动画选区)
    OnUpdate(this, NULL, NULL);
    }
    //-----------------------------------------------------------------------------