Windows GDI+坐标系统详解(二)

4 篇文章 1 订阅
在上一篇中,作者详细介绍了GDI+中坐标系的概念,并以示例的方式进行了解释。
以下代码,是根据作者的示例,编写的VC++代码:

1.首先新建一个基于对话框的MFC程序项目名称GDIMan,在其app的头文件中声明Gdiplus的令牌,用于Gdiplus的初始化

ULONG_PTR m_gdiplusToken;

2.在app的InitInstance()函数中编写以下代码,进行Gdiplus的初始化

Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

3.重载app的ExitInstance()虚函数,释放Gdiplus资源

int CGDIManApp::ExitInstance()
{
	// TODO: 在此添加专用代码和/或调用基类
	Gdiplus::GdiplusShutdown(m_gdiplusToken);
	return CWinApp::ExitInstance();
}


4.在CGDIManDlg的头文件中声明如下成员变量:

private:
	PointF pHead;
	PointF pBody;
	PointF pLeftArm;
	PointF pRightArm;
	PointF pLeftLeg;
	PointF pRightLeg;
	SizeF sHead;
	SizeF sBody;
	SizeF sArm;
	SizeF sLeg;
  CRect m_Rect;//当前对话框的区域
  并在cpp文件中在CGDIManDlg的构造函数中对其赋值:
  CGDIManDlg::CGDIManDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CGDIManDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	sHead.Width=30;
	sHead.Height=30;
	sBody.Width=50;
	sBody.Height=70;
	sArm.Width=10;
	sArm.Height=60;
	sLeg.Width=20;
	sLeg.Height=70;
}

5.重载CGDIManDlg的OnSize函数,主要是为了获取当前对话框的区域值m_Rect

void CGDIManDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialogEx::OnSize(nType, cx, cy);
	// TODO: 在此处添加消息处理程序代码
	GetWindowRect(&m_Rect);
}

6.在CGDIManDlg的OnPaint函数中绘制上一篇示例:

void CGDIManDlg::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
	{
		CDialogEx::OnPaint();
	}
	Graphics graphi(GetDC()->m_hDC);
	Pen pen(Color(255,0,0,255));

	pHead=PointF(m_Rect.Width()/2.0,100.0);
	graphi.TranslateTransform(pHead.X,pHead.Y);
	graphi.DrawEllipse(&pen,-sHead.Width/2.0,-sHead.Height/2.0,sHead.Width,sHead.Height);
	graphi.ResetTransform();

	pBody=PointF(pHead.X-sBody.Width/2,pHead.Y+sHead.Height/2.0);
	graphi.TranslateTransform(pBody.X,pBody.Y);
	graphi.DrawRectangle(&pen,(REAL)0,(REAL)0,sBody.Width,sBody.Height);
	graphi.ResetTransform();

	pLeftArm=PointF(pBody.X,pBody.Y);
	graphi.TranslateTransform(pLeftArm.X,pLeftArm.Y);
	graphi.RotateTransform(45);
	graphi.DrawRectangle(&pen,(REAL)0,(REAL)0,sArm.Width,sArm.Height);
	graphi.ResetTransform();
	
	pRightArm=PointF(pLeftArm.X+sBody.Width,pLeftArm.Y);
	graphi.TranslateTransform(pRightArm.X,pRightArm.Y);
	graphi.RotateTransform(-45);
	graphi.DrawRectangle(&pen,(REAL)0-sArm.Width,(REAL)0,sArm.Width,sArm.Height);
	graphi.ResetTransform();

	pLeftLeg=PointF(pBody.X,pBody.Y+sBody.Height);
	graphi.TranslateTransform(pLeftLeg.X,pLeftLeg.Y);
	graphi.RotateTransform(45);
	graphi.DrawRectangle(&pen,(REAL)0,(REAL)0,sLeg.Width,sLeg.Height);
	graphi.ResetTransform();

	pRightLeg=PointF(pLeftLeg.X+sBody.Width,pLeftLeg.Y);
	graphi.TranslateTransform(pRightLeg.X,pRightLeg.Y);
	graphi.RotateTransform(-45);
	graphi.DrawRectangle(&pen,(REAL)0-sLeg.Width,(REAL)0,sLeg.Width,sLeg.Height);
	graphi.ResetTransform();
}

以我个人的理解,graphi.TranslateTransform(pRightLeg.X,pRightLeg.Y);的作用简单说来就是将(pRightLeg.X,pRightLeg.Y)作为graphi下面绘制的world坐标系的原点,
graphi.RotateTransform(-45);意思是在绘制的基础上逆时针旋转45度,而每次利用graphi.DrawXXX绘制完图形后,需要进行重置Gdiplus的page坐标系:graphi.ResetTransform();
如不重置,下面的绘制将无法进行。



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值