MFC 使用三点画弧

我的第一个MFC程序,花了一些时间了解了网上的很多内容,最后写出来的程序

1.**我的工程名字是: “MAP” **
2.**使用 MFC AppWizard [exe],基于 “基本对话框” **
3.大多需要解释我都加载了程序代码注释里面来了


1.由于使用了鼠标的点击取点的操作,需要在加上相关的库函数
添加在 文件MAPDlg.h 的 CMAPDlg 类里面

protected:
	afx_msg void OnLButtonDown();		//按下鼠标右键
	afx_msg void OnLButtonUp();			//鼠标起来
	afx_msg void OnMouseMove();			//鼠标移动

2.对应的鼠标操作的需要对应的消息映射
添加在 文件MAPDlg.cpp 里面

BEGIN_MESSAGE_MAP(CMAPDlg, CDialog)
	//{{AFX_MSG_MAP(CMAPDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
	//需要添加鼠标操作的的消息映射,以上三行
	ON_WM_LBUTTONDOWN()			//响应鼠标左键按下
	ON_WM_LBUTTONUP()			//响应鼠标左键放开
	ON_WM_MOUSEMOVE()			//响应鼠标移动

	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

再需要添加成员数据,用于保存鼠标取点的数据
添加在 文件MAPDlg.h 的 CMAPDlg 类里面

public:
	CPoint m_point[4]; //点坐标
	int fs,kk;			//记录鼠标状态

在CMAPDlg类的构造函数内,添加对对加入数据的初始化
添加在 文件MAPDlg.hcpp

CMAPDlg::CMAPDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMAPDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMAPDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	//绘制多边形的点数组
    m_point[0].x=0;
    m_point[0].y=0;
    m_point[1].x=0;
    m_point[1].y=0;
    m_point[2].x=0;
    m_point[2].y=0;
    m_point[3].x=0;
	m_point[3].y=0;
	int choice =0;
	fs=0;
	kk=0;
}

**在对话框里面添加一个按钮,用来清除画的线条,然后双击按钮,添加一个函数 **

void CMAPDlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	Invalidate();	//调用窗口的刷新函数
}

三点画弧就是需要注意怎么确定是顺时针还是逆时针
使用一个非成员函数来判断画出来的圆弧的方向是顺时针还是逆时针
添加在 MAPDlg.cpp 里面

	//CPoint a, b, c; 分别为按顺序使用鼠标点下的 三个点
double direction(CPoint a, CPoint b, CPoint c)
{
	return (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x);
}
	//如果返回值大于0为顺时针,小于0为逆时针。

自己定义的一个非成员函数用它来画弧
添加在 MAPDlg.cpp 里面

void DrawMultiArc ( CClientDC&  dc,CPoint p0,CPoint  p1, CPoint p2 )//用三点画弧
{
	CPen PenRed;		//定义画笔的颜色
	PenRed.CreatePen(  PS_SOLID,1,RGB(255,0,0) );//红色实线
	CPen * Oldpen=dc.SelectObject(&PenRed); //记录原始画笔的设置
	
	int iDirection = direction(p0, p1, p2) > 0 ? AD_CLOCKWISE : AD_COUNTERCLOCKWISE;
	dc.SetArcDirection(iDirection);
	
	int a1=2*(p1.x-p0.x);
	int b1=2*(p1.y-p0.y);
	int c1=p1.x * p1.x+p1.y * p1.y - p0.x * p0.x - p0.y * p0.y;
	int a2=2*(p2.x-p1.x);
	int b2=2*(p2.y-p1.y);
	
	int c2=p2.x*p2.x+p2.y*p2.y-p1.x*p1.x-p1.y*p1.y;
	
	if((a1*b2)-(a2*b1)==0|| (a1*b2)-(a2*b1)==0 )
		return ;
	double x=((c1*b2)-(c2*b1))/((a1*b2)-(a2*b1));  //之前需要判断除数是否等于零
	double y=((a1*c2)-(a2*c1))/((a1*b2)-(a2*b1));
	
	double temp_1=((x-p0.x)*(x-p0.x)+(y-p0.y)*(y-p0.y));//两点之间的距离的平方,有可能是取了符号的
	
	double temp_2=temp_1>=0 ? temp_1:-temp_1;//确定用阿里开方的数是正数
	double radius=sqrt(temp_2);   //使用库函数,需要添加头文件 #include<math.h>
	dc.Arc(x-radius , y-radius , x+radius , y+radius , p0.x ,p0.y ,p2.x , p2.y );

	dc.SelectObject(&Oldpen); //恢复原始的画笔设置
}


鼠标的相关函数的重载定义
三个都是成员函数,添加在MAPDlg.cpp里面

void CMAPDlg::OnLButtonDown()	//左键点击下去 使用此来获取点的坐标,画图使用
{
	
	CPoint pos;				//定义一个表示屏幕位置的点
	GetCursorPos(&pos);		//获取鼠标位置相对于屏幕左上角的位置
	ScreenToClient(&pos);	//转换到到当前对话框上的位置
	
	CRect rc;				//定义一个矩形
	GetClientRect(rc);		//获得指定窗口的大小
	if( !rc.PtInRect(pos) )	
		return;				//判断点是否在窗口内
	CClientDC dc(this);
	
	DrawPoint(dc,pos);
	
	if(fs==0)
	{
		m_point[0]=pos;		//第一次点下鼠标
		fs=1;	//记录状态
	}
	else if(fs==1)	//	第二次点击鼠标点
	{
		m_point[1]=pos;
		fs=2;	//为了进入下行存储点
	}
 }
void CMAPDlg::OnLButtonUp()	//鼠标左键起来函数	
{
	
	
	CPoint pos;
	GetCursorPos(&pos);
	ScreenToClient(&pos);
	CClientDC dc(this);
	if(fs==2)
	{
		m_point[2]=pos;
		DrawMultiArc(dc,m_point[0],m_point[1],m_point[2]);
		fs=0 ;
		kk=0 ;		//恢复初始状态
	}
}
void CMAPDlg::OnMouseMove()			//鼠标移动
{
	if( fs==0 )	
		return;	//用1来记录是否按下了鼠标
	CPoint	pos;//获取屏幕坐标
	CRect	rc;	//矩形
	GetCursorPos(&pos); //获取鼠标点距离屏幕左上角的距离
	ScreenToClient(&pos);	//转换为客户端的的左上角的距离
	GetClientRect(rc);	//取得指定窗口的客户区域大小。
	if( !rc.PtInRect(pos) )	
		return;		//判断参数中给出的点是否在矩形区域内。
	
	CClientDC dc(this);			//当前绘图窗口的
	dc.SetROP2(R2_NOT);//选择反色的绘图模式

	if(fs==2)
	{
		m_point[2]=pos;
		if(kk==1)
			DrawMultiArc(dc,m_point[0],m_point[1],m_point[3]);
		DrawMultiArc(dc,m_point[0],m_point[1],m_point[2]);
		m_point[3]=pos;
		kk=1;	
	}
}

最后再把我的两个有添加和修改过的文件的代码贴出来
#MAPDlg.h

// MAPDlg.h : header file
//

#if !defined(AFX_MAPDLG_H__6CA3B0F0_574E_41C5_B3BA_00E46DC22986__INCLUDED_)
#define AFX_MAPDLG_H__6CA3B0F0_574E_41C5_B3BA_00E46DC22986__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CMAPDlg dialog

class CMAPDlg : public CDialog
{
// Construction
public:
	CMAPDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	//{{AFX_DATA(CMAPDlg)
	enum { IDD = IDD_MAP_DIALOG };
		// NOTE: the ClassWizard will add data members here
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CMAPDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
	//}}AFX_VIRTUAL
	
	public:
		CPoint m_point[4]; //点坐标
		int choice;			//作为跳板俩画不同的图形
		int fs,kk;			//记录鼠标状态

// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	//{{AFX_MSG(CMAPDlg)
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();

	afx_msg void OnLButtonDown();		//按下鼠标右键
	afx_msg void OnLButtonUp();			//鼠标起来
	afx_msg void OnMouseMove();			//鼠标移动

	afx_msg void OnButton1();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MAPDLG_H__6CA3B0F0_574E_41C5_B3BA_00E46DC22986__INCLUDED_)

#MAPDlg.cpp

// MAPDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MAP.h"
#include "MAPDlg.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

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

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMAPDlg dialog

CMAPDlg::CMAPDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMAPDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMAPDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	//绘制多边形的点数组
    m_point[0].x=0;
    m_point[0].y=0;
    m_point[1].x=0;
    m_point[1].y=0;
    m_point[2].x=0;
    m_point[2].y=0;
    m_point[3].x=0;
	m_point[3].y=0;
	int choice =0;
	fs=0;
	kk=0;
}

void CMAPDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMAPDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMAPDlg, CDialog)
	//{{AFX_MSG_MAP(CMAPDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, OnButton1)

	ON_WM_LBUTTONDOWN()			//响应鼠标左键按下
	ON_WM_LBUTTONUP()			//响应鼠标左键放开
	ON_WM_MOUSEMOVE()			//响应鼠标移动

	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMAPDlg message handlers

BOOL CMAPDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

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

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

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

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMAPDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		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;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMAPDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void DrawPoint(CClientDC &dc,CPoint p0)	//画点
{
	dc.SetPixel( p0,RGB(84,84,84) );
}

void CMAPDlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	Invalidate();	//调用窗口的刷新函数
}

double direction(CPoint a, CPoint b, CPoint c)
{
	return (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x);
}

//如果返回值大于0为顺时针,小于0为逆时针。
void DrawMultiArc(CClientDC& dc,CPoint p0,CPoint p1,CPoint p2)			//用三点画弧
{
	CPen PenRed;
	PenRed.CreatePen(  PS_SOLID,1,RGB(255,0,0) );	//红色实线
	CPen * Oldpen=dc.SelectObject(&PenRed);
	
	int iDirection = direction(p0, p1, p2) > 0 ? AD_CLOCKWISE : AD_COUNTERCLOCKWISE;
	dc.SetArcDirection(iDirection);
	
	int a1=2*(p1.x-p0.x);
	int b1=2*(p1.y-p0.y);
	int c1=p1.x * p1.x+p1.y * p1.y - p0.x * p0.x - p0.y * p0.y;
	int a2=2*(p2.x-p1.x);
	int b2=2*(p2.y-p1.y);
	
	int c2=p2.x*p2.x+p2.y*p2.y-p1.x*p1.x-p1.y*p1.y;
	if((a1*b2)-(a2*b1)==0|| (a1*b2)-(a2*b1)==0 )
		return ;
	double x=((c1*b2)-(c2*b1))/((a1*b2)-(a2*b1));  //之前需要判断除数是否等于零
	double y=((a1*c2)-(a2*c1))/((a1*b2)-(a2*b1));
	
	double temp_1=((x-p0.x)*(x-p0.x)+(y-p0.y)*(y-p0.y));	//两点之间的距离的平方,有可能是取了符号的
	
	double temp_2=temp_1>=0 ? temp_1:-temp_1;	//确定用阿里开方的数是正数
	double radius=sqrt(temp_2);
	dc.Arc(x-radius , y-radius , x+radius , y+radius , p0.x ,p0.y ,p2.x , p2.y );
	
	dc.SelectObject(&Oldpen);
}

void CMAPDlg::OnLButtonDown()	//左键下去 使用此来获取点的坐标,画图使用
{
	
	CPoint pos;				//定义一个表示屏幕位置的点
	GetCursorPos(&pos);		//获取鼠标位置相对于屏幕左上角的位置
	ScreenToClient(&pos);	//转换到到当前对话框上的位置
	
	CRect rc;				//定义一个矩形
	GetClientRect(rc);		//获得指定窗口的大小
	if( !rc.PtInRect(pos) )	
		return;				//判断点是否在窗口内
	CClientDC dc(this);
	
	DrawPoint(dc,pos);
	
	if(fs==0)
	{
		m_point[0]=pos;		//第一次点下鼠标
		fs=1;	//记录状态
	}
	else if(fs==1)	//	第二次点击鼠标点
	{
		m_point[1]=pos;
		fs=2;	//为了进入下行存储点
	}
 }

void CMAPDlg::OnLButtonUp()	//鼠标左键起来函数	
{
	
	
	CPoint pos;
	GetCursorPos(&pos);
	ScreenToClient(&pos);
	CClientDC dc(this);
	if(fs==2)
	{
		m_point[2]=pos;
		DrawMultiArc(dc,m_point[0],m_point[1],m_point[2]);
		fs=0 ;
		kk=0 ;		//恢复初始状态
	}
}

void CMAPDlg::OnMouseMove()			//鼠标移动
{
	if( fs==0 )	
		return;	//用1来记录是否按下了鼠标
	CPoint	pos;//获取屏幕坐标
	CRect	rc;	//矩形
	GetCursorPos(&pos); //获取鼠标点距离屏幕左上角的距离
	ScreenToClient(&pos);	//转换为客户端的的左上角的距离
	GetClientRect(rc);	//取得指定窗口的客户区域大小。
	if( !rc.PtInRect(pos) )	
		return;		//判断参数中给出的点是否在矩形区域内。
	
	CClientDC dc(this);			//当前绘图窗口的
	dc.SetROP2(R2_NOT);//选择反色的绘图模式

	if(fs==2)
	{
		m_point[2]=pos;
		if(kk==1)
			DrawMultiArc(dc,m_point[0],m_point[1],m_point[3]);
		DrawMultiArc(dc,m_point[0],m_point[1],m_point[2]);
		m_point[3]=pos;
		kk=1;	
	}
}

猜你喜欢

转载自blog.csdn.net/hongtao45/article/details/82313251
今日推荐