MFC 画笔功能实现

一、4个消息处理

如果是在VS2012上,我们可以很方便的在对话框的属性栏找到消息页面添加消息

如果是以前的VC6的版本,那还是得老老实实使用Class Wizzard类向导添加消息

 

 左键按下、抬起、移动三个消息是完成画笔功能的必要消息

擦除对话框背景重载的目的是不让它闪烁

下面直接贴代码吧,基于VS2012做,还是比较简单的功能

二、代码

// TestPaintDlg.h : 头文件


// TestPaintDlg.h : 头文件
//

#pragma once

#include <vector>


class CLine
{
public:
    CPoint start;
    CPoint end;
};


// CTestPaintDlg 对话框
class CTestPaintDlg : public CDialogEx
{
// 构造
public:
	CTestPaintDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_TESTPAINT_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()

private:
    CPoint m_ptStart;
    CPoint m_ptEnd;
    BOOL m_bPen;
    std::vector<CLine *> m_lines;
    CLine *m_pCurLine;
public:
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};

// TestPaintDlg.cpp : 实现文件


// TestPaintDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "TestPaint.h"
#include "TestPaintDlg.h"
#include "afxdialogex.h"
#include "DwMemDC.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CTestPaintDlg 对话框



CTestPaintDlg::CTestPaintDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CTestPaintDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    m_bPen = FALSE;
}

void CTestPaintDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CTestPaintDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()


// CTestPaintDlg 消息处理程序

BOOL CTestPaintDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CTestPaintDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CTestPaintDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
        CPaintDC dc(this);
        DwMemDC dcMem(&dc);
        
        for (auto line : m_lines)
        {
            dcMem.MoveTo(line->start);
            dcMem.LineTo(line->end);
        }

		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CTestPaintDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CTestPaintDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值

    m_ptStart = point;
    m_bPen = TRUE;
    CLine *pLine = new CLine();
    pLine->start = m_ptStart;
    pLine->end = m_ptStart;
    m_lines.push_back(pLine);
    m_pCurLine = pLine;
    CDialogEx::OnLButtonDown(nFlags, point);
}


void CTestPaintDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    m_bPen = FALSE;
    CDialogEx::OnLButtonUp(nFlags, point);
}


void CTestPaintDlg::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (m_bPen)
    {
        m_pCurLine->end = point;
        Invalidate();
    }
    CDialogEx::OnMouseMove(nFlags, point);
}


BOOL CTestPaintDlg::OnEraseBkgnd(CDC* pDC)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    return FALSE;
    //return CDialogEx::OnEraseBkgnd(pDC);
}

双缓冲MemDC

#pragma once


#ifndef _MEMDC_H_

#define _MEMDC_H_

//

// DwMemDC - memory DC

//

// Author: Keith Rule

// Email:  keithr@europa.com

// Copyright 1996-1999, Keith Rule

//

// You may freely use or modify this code provided this

// Copyright is included in all derived versions.

//

// History - 10/3/97 Fixed scrolling bug.

//                   Added print support. - KR

//

//           11/3/99 Fixed most common complaint. Added

//                   background color fill. - KR

//

//           11/3/99 Added support for mapping modes other than

//                   MM_TEXT as suggested by Lee Sang Hun. - KR

//

// This class implements a memory Device Context which allows

// flicker free drawing.

class DwMemDC : public CDC {
protected:

    CBitmap  m_bitmap;       // Offscreen bitmap

    CBitmap* m_oldBitmap;    // bitmap originally found in DwMemDC

    CDC*     m_pDC;          // Saves CDC passed in constructor

    CRect    m_rect;         // Rectangle of drawing area.

    BOOL     m_bMemDC;       // TRUE if CDC really is a Memory DC.



    void Construct(CDC* pDC)

    {
        ASSERT(pDC != NULL); 

        // Some initialization

        m_pDC = pDC;

        m_oldBitmap = NULL;

        m_bMemDC = !pDC->IsPrinting();

        if (m_bMemDC) {
            // Create a Memory DC

            CreateCompatibleDC(pDC);

            pDC->LPtoDP(&m_rect);

            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());

            m_oldBitmap = SelectObject(&m_bitmap);



            SetMapMode(pDC->GetMapMode());

            pDC->DPtoLP(&m_rect);

            SetWindowOrg(m_rect.left, m_rect.top);

        } else {
            // Make a copy of the relevent parts of the current DC for printing

            m_bPrinting = pDC->m_bPrinting;

            m_hDC       = pDC->m_hDC;

            m_hAttribDC = pDC->m_hAttribDC;

        }

        // Fill background 

        FillSolidRect(m_rect, pDC->GetBkColor());

    }

    // TRK begin

public:

    DwMemDC(CDC* pDC                  ) : CDC() { pDC->GetClipBox(&m_rect); Construct(pDC); }

    DwMemDC(CDC* pDC, const RECT& rect) : CDC() { m_rect = rect           ; Construct(pDC); }

    // TRK end



    virtual ~DwMemDC()

    {        

        if (m_bMemDC) {
            // Copy the offscreen bitmap onto the screen.

            m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),

                this, m_rect.left, m_rect.top, SRCCOPY);            



            //Swap back the original bitmap.

            SelectObject(m_oldBitmap);        

        } else {
            // All we need to do is replace the DC with an illegal value,

            // this keeps us from accidently deleting the handles associated with

            // the CDC that was passed to the constructor.            

            m_hDC = m_hAttribDC = NULL;

        }    

    }



    // Allow usage as a pointer    

    DwMemDC* operator->() 

    {
        return this;

    }    

    // Allow usage as a pointer    

    operator DwMemDC*() 

    {
        return this;

    }

};

#endif

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值