用VC & GDI+画一颗树

前些天看到一个使用Python写的画树的程序,感觉很好玩,就用VC实现了一下,使用GDI+画也挺简单的。

一、生成一个对话框工程

启动VS,选择新建一个工程,工程名填Tree,工程类型选对话框,点击完成。

二、新建类CDrawTree

声明4个变量和6个函数:

class CDrawTree
{
public:
	CDrawTree();
	CDrawTree(CWnd* pWnd);
	~CDrawTree();

	void DrawTree(double nStep, double nLength);
	void Froward(Gdiplus::REAL nLength);
	void Left(double nAngle);
	void Right(double nAngle);
	void SetPenColor(int r, int g, int b);
	void SetPenWidth(Gdiplus::REAL nWidth);

protected:
	Gdiplus::Graphics* m_pDC;
	Gdiplus::Pen* m_pPen;
	CWnd* m_pWnd;
	CDC* m_pOrgDc;
};

构造函数:

CDrawTree::CDrawTree(CWnd* pWnd)
{
	ASSERT(pWnd);

	m_pWnd = pWnd;
	m_pOrgDc = pWnd->GetDC();
	m_pOrgDc->SetMapMode(MM_LOMETRIC);

	m_pDC = Gdiplus::Graphics::FromHDC(m_pOrgDc->GetSafeHdc());
	m_pDC->SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeHighQuality);

	CRect rect;
	pWnd->GetClientRect(rect);

	m_pOrgDc->DPtoLP(rect);

	Gdiplus::PointF pt = Gdiplus::PointF(rect.Width() / 2, rect.Height()+100);
	m_pDC->TranslateTransform(pt.X, pt.Y);

	m_pPen = new Gdiplus::Pen(Gdiplus::Color::Red, 1);
	
	m_pDC->DrawRectangle(m_pPen, -20, -20, 40, 40);

	SetPenColor(0, 0, 255);
	m_pDC->DrawRectangle(m_pPen, -100, -100, 200, 200);

	SetPenWidth(5);

	Left(90);
}

画树的主要功能函数:


void CDrawTree::DrawTree(double nStep, double nLength)
{
	int clr = -nStep * 10 + 200;
	SetPenColor(60, clr, 20);
	SetPenWidth(nStep);
	Froward(nLength);
	
	if (nStep > 0)
	{
		double b = (rand() % 150) / 10.0 + 10; // 右分支偏转角度
		double c = (rand() % 150) / 10.0 + 10; // 左分支偏转角度
		double d = nLength*((rand() % 25) / 100.0 + 0.7);// 下一个分支的长度
		Gdiplus::GraphicsState state = m_pDC->Save();
		// 画右分支
		Right(b);
		DrawTree(nStep - 1, d);
		m_pDC->Restore(state);

		// 画左分支
		Left(c);
		DrawTree(nStep - 1, d);
	}
	else
	{
        // 树叶
		SetPenColor(100, 100 + rand() % 150, 100);
		m_pDC->DrawEllipse(m_pPen, -8, -8, 16, 16);

		// 落叶
		if (rand() %10 > 6)
		{
			Gdiplus::Matrix mat;
			m_pDC->GetTransform(&mat);

			Gdiplus::REAL elements[6];
			mat.GetElements(elements);

            // 从当前角度, 转到和x轴正方向下-15度. 先要计算当前坐标的旋转角度
			double nAngle = acos(elements[0]) / 3.1515926 * 180;
			Right(nAngle + 15);

			double dis = 800.0 * (rand() % 50) / 100.0 + 400 * (rand() % 30) / 100.0 + 200 * rand() % 20 / 100.0;
			m_pDC->TranslateTransform(dis * 3, 0);

			SetPenColor(150, 130+rand()%50, 150);
			m_pDC->DrawEllipse(m_pPen, -5, -5, 10, 10);
		}
	}
}

几个辅助函数:

void CDrawTree::Left(double nAngle)
{
	m_pDC->RotateTransform(nAngle);
}
void CDrawTree::Right(double nAngle)
{
	m_pDC->RotateTransform(-nAngle);
}
void CDrawTree::SetPenColor(int r, int g, int b)
{
	ASSERT(m_pPen);
	Gdiplus::Color color(r, g, b);
	m_pPen->SetColor(color);
}

画线函数:

需要特别注意的是,坐标的变换,在每次画线之前,都已经通过旋转和偏移坐标,让当前坐标处于(0,0)点,角度为0,即沿x轴坐标画线。坐标旋转和偏移具有累加性,所以画完线需要把坐标偏移到下一点处。

void CDrawTree::Froward(Gdiplus::REAL nLength)
{
	m_pDC->DrawLine(m_pPen, 0.0, 0.0, nLength, 0.0);
	m_pDC->TranslateTransform(nLength, 0);
}

三、初始化GDI+环境

VC程序中默认使用GDI,要使用GDI+,需要自己初始化加载一下。

在程序的 InitInstance()函数中,打开对话框前,添加如下语句加载GDI+资源:

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

关闭对话框后,使用Gdiplus::GdiplusShutdown(m_gdiplusToken);释放GDI+资源。


BOOL CTreeApp::InitInstance()
{
    ULONG_PTR m_gdiplusToken;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

    。。。。。。

    Gdiplus::GdiplusShutdown(m_gdiplusToken);
}

四、画树

在对话框上添加一个按钮,添加按钮的响应函数,调用DrawTree画树。

#include "DrawTree.h"
void CTreeDlg::OnBnClickedButton1()
{
	Invalidate();
	UpdateWindow();

	CDrawTree tree(this);
	tree.DrawTree(12, 300);
}

五、树的效果图

由于所有变量都是随机的,每次画的数的形状都不相同。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值