⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 handwritingview.cpp

📁 vc模仿手写字的源码,可以实现模仿手写字的功能
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// HandwritingView.cpp : implementation of the CHandwritingView class
//

#include "stdafx.h"
#include "Handwriting.h"
#include <math.h>
#include "HandwritingDoc.h"
#include "HandwritingView.h"

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

/////////////////////////////////////////////////////////////////////////////
// CHandwritingView

IMPLEMENT_DYNCREATE(CHandwritingView, CView)

BEGIN_MESSAGE_MAP(CHandwritingView, CView)
	//{{AFX_MSG_MAP(CHandwritingView)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_COMMAND(ID_btnCoordinate, OnbtnCoordinate)
	ON_COMMAND(ID_btnPlay, OnbtnPlay)
	ON_COMMAND(ID_btnRecord, OnbtnRecord)
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_btnOpenBmp, OnbtnOpenBmp)
	ON_COMMAND(ID_btnSample, OnbtnSample)
	ON_UPDATE_COMMAND_UI(ID_btnCoordinate, OnUpdatebtnCoordinate)
	ON_COMMAND(ID_btnEnd, OnbtnEnd)
	ON_UPDATE_COMMAND_UI(ID_btnEnd, OnUpdatebtnEnd)
	ON_UPDATE_COMMAND_UI(ID_btnOpenBmp, OnUpdatebtnOpenBmp)
	ON_UPDATE_COMMAND_UI(ID_btnPlay, OnUpdatebtnPlay)
	ON_UPDATE_COMMAND_UI(ID_btnRecord, OnUpdatebtnRecord)
	ON_UPDATE_COMMAND_UI(ID_btnSample, OnUpdatebtnSample)
	ON_COMMAND(IDC_btnRefresh, OnbtnRefresh)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CHandwritingView construction/destruction
///////////////////////////////////////
//构造函数:置初值
//
CHandwritingView::CHandwritingView()
{
	sOperated=sReady;
	Strokes=NULL;
	pCurrentStroke=NULL;
	pBuff=NULL;
	uLines=0;
	Stepth=0;
	bLining=FALSE; 
	m_hCursor=AfxGetApp()->LoadStandardCursor (IDC_CROSS);
	m_pDC=NULL;
	bmp=true;
	bErase=false;
}

CHandwritingView::~CHandwritingView()
{
}

BOOL CHandwritingView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CHandwritingView drawing

void CHandwritingView::OnDraw(CDC* pDC)
{
	CHandwritingDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	
	//初始化或者显示字体
	//
	if(!m_pDC)
		Init();
	Draw();
}

/////////////////////////////////////////////////////////////////////////////
// CHandwritingView printing

BOOL CHandwritingView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

/////////////////////////////////////////////////////////////////////////////
// CHandwritingView diagnostics

#ifdef _DEBUG
void CHandwritingView::AssertValid() const
{
	CView::AssertValid();
}

void CHandwritingView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CHandwritingDoc* CHandwritingView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CHandwritingDoc)));
	return (CHandwritingDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CHandwritingView message handlers

///////////////////////////////////////////////////////////////
//鼠标左按钮按下消息函数:启动通过沿字符笔划画线来进行笔划录制
//的过程
//
void CHandwritingView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	RECT rect;
	
	//设置画线的起点
	//
	if(sOperated==sRecording)
	{
		Stepth++;
		if(Stepth%3==1)
			oneStroke.Speed =1;
		m_pOld=point;
		m_pOrigin=point;
		SetCapture();
		bLining=true;	
		GetClientRect(&rect);
		ClientToScreen(&rect);
		ClipCursor(&rect);
	}
	CView::OnLButtonDown(nFlags, point);
}

///////////////////////////////////////////////////////////////
//鼠标左按钮释放消息函数:一次画线结束,如果当次画线类型是指定
//笔划轨迹(三步循环周期中的第一步,即Stepth的值为3的倍数余1)或者
//指定笔划起始宽度(三步循环周期中的第二步,即Stepth的值为3的
//倍数余2),则保留相应数据,并准备继续画线;若为指定终端笔划
//宽度(三步循环周期中的第三步,即Stepth的值为3的倍数),则
//保存数据并生成一个新的笔划节点插入到字符笔划链表中。
//
void CHandwritingView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	UINT tmp;
	RECT rect,rectTip;
	double dWidth;
	UINT uWidth;
	STROKES *pTmp;

	//根据步骤索引值决定进行存储当前笔划等操作
	//
	m_pDC->SetTextColor(RGB(0,0,0));
	if(bLining)
	{
		dWidth=sqrt((m_pOld.x-m_pOrigin.x)*(m_pOld.x-m_pOrigin.x)+(m_pOld.y-m_pOrigin.y)*(m_pOld.y-m_pOrigin.y));
		uWidth=dWidth;
		uWidth=uWidth?uWidth:1;

		GetClientRect(&rect);
		rectTip=rect;
		rectTip.top=rect.bottom -20;
		
		tmp=Stepth%3;
		switch(tmp)
		{
		//完成一个笔划所有属性的指定,则生成笔划节点并插入字符链表
		//
		case 0:oneStroke.Width2=uWidth;			
			pTmp= new _STROKES;
			if(pTmp==NULL)
			{
				MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
				exit(0);
			}
			pTmp->Stroke.x1=oneStroke.x1 ;
			pTmp->Stroke.y1=oneStroke.y1 ;
			pTmp->Stroke.x2=oneStroke.x2 ;
			pTmp->Stroke.y2=oneStroke.y2 ;
			pTmp->Stroke.x1=oneStroke.x1 ;
			pTmp->Stroke.Width1=oneStroke.Width1;
			pTmp->Stroke.Width2=oneStroke.Width2;
			pTmp->Stroke.Speed=oneStroke.Speed;
			pTmp->pStroke =NULL;

			//字符节点链接到字符笔划单链表中
			if(pCurrentStroke)
			{
				pCurrentStroke->pStroke=pTmp;
				pCurrentStroke=pTmp;
			}
			if(Strokes==NULL)
			{
				Strokes=pTmp;
				pCurrentStroke=pTmp;
			}
			m_pDC->LineTo (m_pOrigin);
			m_pDC->TextOut (rectTip.left,rectTip.top,"操作提示:请指定下一个笔划线段......       "); 
			break;

		//完成一个笔划轨迹的指定
		//
		case 1:oneStroke.x1=m_pOrigin.x;
			oneStroke.y1=m_pOrigin.y;
			oneStroke.x2=m_pOld.x;
			oneStroke.y2=m_pOld.y;
			m_pDC->TextOut (rectTip.left,rectTip.top,"操作提示:请指定笔划线段起始端宽度......   ");
			break;
		
		//完成一个笔划起始宽度的指定
		//
		case 2:oneStroke.Width1=uWidth;
			m_pDC->LineTo (m_pOrigin);
			m_pDC->TextOut (rectTip.left,rectTip.top,"操作提示:请指定笔划线段终止端宽度......   ");
			break;
		default:;
		}

		//释放鼠标和光标
		bLining=FALSE;
		ReleaseCapture();
		ClipCursor(NULL);
	}	
	CView::OnLButtonUp(nFlags, point);
}

/////////////////////////////////////////////////////////////////
//鼠标右按钮单击消息函数:在一个笔划的录制过程中,每单击一次,笔
//划绘制速度提高一个因子
//
void CHandwritingView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	//为当前笔划指定绘制速度因子
	//
	oneStroke.Speed++;	
	CView::OnRButtonDown(nFlags, point);
}

////////////////////////////////////////////
//数据显示消息:将当前录制的字符笔划属性数据
//显示出来
//
void CHandwritingView::OnbtnCoordinate() 
{
	RECT rect;
	int x,y;
	int Num;
	char x1[5],y1[5],x2[5],y2[5],w1[5],w2[5],s[5],No[5];
	CString strResult,strStroke(" ");
	
	//分四列依笔划定义结构的顺序显示当前录制的字符的笔划数据
	//
	bErase=false;
	GetClientRect(&rect);
	x=0;
	Num=0;
	y=rect.bottom/2; 
	y=0;
	STROKES *p=Strokes;

	while(p)
	{
		//显示数据
		//
		_itoa(p->Stroke.x1 ,x1,10);
		_itoa(p->Stroke.y1 ,y1,10);
		_itoa(p->Stroke.x2 ,x2,10);
		_itoa(p->Stroke.y2 ,y2,10);
		_itoa(p->Stroke.Width1 ,w1,10);
		_itoa(p->Stroke.Width2,w2,10);
		_itoa(p->Stroke.Speed,s,10);
		_itoa(Num,No,10);
		strResult=strStroke+No+":"+x1+","+y1+"-"+x2+","+y2+";"+w1+"-"+w2+";"+s;
		m_pDC->TextOut (x,y,strResult);
		
		//调整下一个数据显示位置
		Num++;
		if(Num%4)
		{
			x+=rect.right/4;
		}
		else
		{
			x=0;
			y+=15;
		}
		p=p->pStroke;
	}	
}

/////////////////////////////////////////////////////////
//手写展示命令函数:启动动态显示当前录制的手写字符的过程
//
void CHandwritingView::OnbtnPlay() 
{
	//播放录制的字符
	//
	bErase=true;
	sOperated=sPlaying;
	Writing(Strokes,1,5,false,1,10,10,m_pDC,false);
	bErase=false;
	bmp=false;
	sOperated=sPlayed;	
}

/////////////////////////////////////////////////
//录制按钮函数:启动字符录制过程
//
void CHandwritingView::OnbtnRecord() 
{
	//启动字符笔划的录制过程
	//
	if(m_pDC==NULL)
		Init();
	sOperated=sRecording;
	Stepth=0;

	//删除存在的字符笔划链表
	DeleteStrokes();	
}

//////////////////////////////////////////////////////////////
//鼠标移动消息函数:动态显示或者擦除鼠标的画线
//
void CHandwritingView::OnMouseMove(UINT nFlags, CPoint point) 
{
	//消除或者显示笔划及其宽度轨迹
	//
	if(bLining)
	{
		SetCursor(m_hCursor);
		m_pDC->SetROP2 (R2_NOT);
		m_pDC->MoveTo (m_pOrigin);
		m_pDC->LineTo (m_pOld);
		m_pDC->MoveTo (m_pOrigin);
		m_pDC->LineTo (point);
		m_pOld=point;
	}
	
	CView::OnMouseMove(nFlags, point);
}

///////////////////////////////
//初始函数
//
void CHandwritingView::Init()
{
	m_pDC=new CClientDC(this);
	sOperated=sReady;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//手写字符动态显示函数:遍历字符链表的笔划,并根据笔划信息
//将笔划直线段象素化,然后根据笔划的宽度创建相应的画笔,按
//增量绘制直线的方式逐个绘制象素,并根据速度因子进行必要延
//时。
//
void CHandwritingView::Writing(STROKES *Strokes, BYTE Style, BYTE Interval, bool Fast, BYTE Ratio,int x0, int y0,CClientDC *dc,bool bFlash)
{
	int dx,dy;
	int sx,sy;
	int t1,t2,e;
	int x1,y1,x2,y2;
	int x,y;
	int i;
	BYTE Width1,Width2;
	BYTE bStyle,bRatio;
	int iWidth;
	float dWidth;
	DWORD Delay,Upper,Now;
	CPen Pen;
	STROKES *pStroke,*pTemp;
	
	//根据指定的各种属性实际逐象素绘制手写字符
	//
	dc->SetROP2 (R2_COPYPEN);
	Upper=Fast?100000:1000000;
	Upper=bFlash?0:Upper;
	bStyle=Style%10?Style%10:1;
	bRatio=Ratio%10?Ratio%10:1;
	pStroke=Strokes;

    //展示笔划书写过程
	//
	while(pStroke!=NULL)
	{
		//字符放大ratio倍
		//
		x1=pStroke->Stroke.x1*bRatio+x0 ;
		y1=pStroke->Stroke.y1*bRatio+y0 ;
		x2=pStroke->Stroke.x2*bRatio+x0 ;
		y2=pStroke->Stroke.y2*bRatio+y0;
		
		Width1=pStroke->Stroke.Width1 *bStyle;
		Width2=pStroke->Stroke.Width2 *bStyle;
		
		//笔划段象素化
		//
		dx=abs(x2-x1);
		dy=abs(y2-y1);

		sx=-1;
		if(x2>x1) 
			sx=1;
		sy=-1;
		if(y2>y1) 
			sy=1;

		x=x1;
		y=y1;
		dc->MoveTo (x,y);

		if(dx>dy)
		{
			t1=2*dy;
			t2=2*(dy-dx);
			e=2*dy-dx;
			dWidth=1.0*(Width2-Width1)/dx;
			for(i=0;i<dx;i++)
			{
				//创建相应宽度的笔
				//
				iWidth=Width1+dWidth*i;
				Pen.CreatePen (PS_SOLID,iWidth,RGB(0,0,0));
				dc->SelectObject(&Pen);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -