📄 handwritingview.cpp
字号:
x+=sx;
if(e>=0)
{
y+=sy;
e+=t2;
}
else
{
e+=t1;
}
dc->LineTo (x,y);
//在象素的绘制之间进行延迟
//
Now=Upper/pStroke->Stroke.Speed ;
for(Delay=0;Delay<Now;Delay++);
dc->SelectStockObject(BLACK_PEN);
Pen.DeleteObject();
}
dc->LineTo(x+1,y);
}
else
{
t1=2*dx;
t2=2*(dx-dy);
e=2*dx-dy;
dWidth=dy?1.0*(Width2-Width1)/dy:Width2-Width1;
for(i=0;i<dy;i++)
{
//创建相应宽度的笔
//
iWidth=Width1+dWidth*i;
Pen.CreatePen (PS_SOLID,iWidth,RGB(0,0,0));//Style0
dc->SelectObject(&Pen);
y+=sy;
if(e>=0)
{
x+=sx;
e+=t2;
}
else
{
e+=t1;
}
dc->LineTo (x,y);
//在象素的绘制之间进行延迟
//
Now=Upper/pStroke->Stroke.Speed;
for(Delay=0;Delay<Now;Delay++);
dc->SelectStockObject(BLACK_PEN);
Pen.DeleteObject();
}
dc->LineTo(x+1,y);
}
pTemp=pStroke;
pStroke=pStroke->pStroke ;
//笔划书写间隔要进行一定延时,以模拟笔移动的效果
//
if(pStroke!=NULL)
{
if((pTemp->Stroke.x2-pStroke->Stroke.x1)*(pTemp->Stroke.x2-pStroke->Stroke.x1)+(pTemp->Stroke.y2-pStroke->Stroke.y1)*(pTemp->Stroke.y2-pStroke->Stroke.y1)>(Interval*Interval))
for(Delay=0;Delay<Upper*Interval;Delay++);
}
}
}
//////////////////////////////////////////////
//位图文件打开按钮函数:启动打开并显示含有要录制的
//手写字符的位图文件的过程。
//
void CHandwritingView::OnbtnOpenBmp()
{
RECT rect;
//打开字符位图文件并进行显示
//
sOperated=sOpenning;
bErase=false;
ReadBitmap();
sOperated=sOpened;
GetClientRect(&rect);
InvalidateRect(&rect,TRUE);
}
//////////////////////////////////////////////
//位图文件读取函数:打开、构造与缓冲含有手写字
//符的位图文件。
//
void CHandwritingView::ReadBitmap()
{
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B') //"BM"
CFile f;
CFileException e;
BITMAPFILEHEADER bmfHead;
BITMAPINFOHEADER bmHead;
DWORD rdBytes,svBytes,nPixel;
UINT nEntries;
UINT nScan,tmp;
BYTE *pTemp=NULL,*pRGBQUARD=NULL;
int i,j;
DWORD index;
BYTE iRGB,OneByte;
LONG lOffset;
CString pFileName;
//通过文件对话框获取有效的文件名
//
pFileName=CString("");
CFileDialog fDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, "bitmap Files (*.bmp)||",NULL );
if((fDlg.DoModal())!=IDOK)
{
return;
}
pFileName=fDlg.GetPathName ();
if(!pFileName)
{
return;
}
//打开位图文件
//
if(!f.Open(pFileName, CFile::modeRead, &e ))
{
MessageBox("Hi,file.","File operating.",MB_OK);
exit(0);
}
//读取位图文件并构造显示数据:关于解压算法可参见位图文件
//的有关存储格式介绍
//
f.Read (&bmfHead,sizeof(BITMAPFILEHEADER));
if(bmfHead.bfType!=DIB_HEADER_MARKER)
{
MessageBox("File is not BMP!",NULL,MB_OK);
return;
}
f.Seek(14,CFile::begin);
f.Read (&bmHead,sizeof(BITMAPINFOHEADER));
if(bmHead.biCompression)
{
MessageBox("cannot open this compressed file!",NULL,MB_OK);
exit(1);
}
//从堆中分配逐象素缓冲所需要容量的内存
//
tmp=bmHead.biWidth*bmHead.biBitCount;
nScan=tmp%32?(tmp/32*4+(tmp%32+32)/32*4):tmp/8;
rdBytes=nScan*bmHead.biHeight ;
svBytes=bmHead.biWidth*bmHead.biHeight;
pTemp=new BYTE[rdBytes];
if(pBuff)
delete pBuff;
pBuff=new _MYBITMAP[svBytes];
if(!pBuff||!pTemp)
{
MessageBox("Cannot allocate memory","Memory allocate",MB_OK);
exit(0);
}
//读取数据
//
lOffset=bmfHead.bfOffBits;
f.Seek (lOffset,CFile::begin);
f.Read (pTemp,rdBytes);
if(bmHead.biBitCount<24)
{
nEntries=Pow2(bmHead.biBitCount);
pRGBQUARD=new BYTE[nEntries*4];
f.Seek (54l,CFile::begin);
f.Read (pRGBQUARD,nEntries*4);
}
f.Close();
//进行数据构造
//
switch(bmHead.biBitCount)
{
case 1:nPixel=0;
for(i=bmHead.biHeight-1;i>=0;i--)
for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
{
OneByte=pTemp[index+j/8];
iRGB=(OneByte&Pow2(7-j%8))?1:0;
pBuff[nPixel++].clrRGBA =RGB(pRGBQUARD[iRGB*4+2],pRGBQUARD[iRGB*4+1],pRGBQUARD[iRGB*4]);
}
break;
case 4:nPixel=0;
for(i=bmHead.biHeight-1;i>=0;i--)
for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
{
OneByte=pTemp[index+j*4/8];
iRGB=j%2?OneByte&0x0f:OneByte>>4;
pBuff[nPixel++].clrRGBA =RGB(pRGBQUARD[iRGB*4+2],pRGBQUARD[iRGB*4+1],pRGBQUARD[iRGB*4]);
}
break;
case 8:nPixel=0;
for(i=bmHead.biHeight-1;i>=0;i--)
for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
{
OneByte=pTemp[index+j];
iRGB=OneByte;
pBuff[nPixel++].clrRGBA =RGB(pRGBQUARD[iRGB*4+2],pRGBQUARD[iRGB*4+1],pRGBQUARD[iRGB*4]);
}
break;
case 24:nPixel=0;
for(i=bmHead.biHeight-1;i>=0;i--)
for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
{
pBuff[nPixel++].clrRGBA =RGB(pTemp[index+2],pTemp[index+1],pTemp[index]);
index+=3;
}
break;
default:
MessageBox("File not supported.",NULL,MB_OK);
exit(1);
}
//保存变量状态及释放临时资源
//
biWidth=bmHead.biWidth;
biHeight=bmHead.biHeight;
bmp=true;
if(pTemp)
delete pTemp;
if(pRGBQUARD)
delete pRGBQUARD;
}
////////////////////////////////////////////////////////////////////////////////
//位图显示函数:在屏幕上某位置将缓冲的位图显示出来
//
void CHandwritingView::DrawBitmap(MYBITMAP *pBmp, int x0, int y0, CClientDC *dc)
{
int x,y;
UINT i,j;
DWORD index;
//逐象素显示位图
//
y=y0;
dc->SetROP2 (R2_COPYPEN);
if(pBmp)
for(i=0;i<biHeight;i++,y++)
for(x=x0,index=i*biWidth,j=0;j<biWidth;j++,x++)
dc->SetPixel (x,y,pBmp[index++].clrRGBA);
}
////////////////////////////////////////
//幂函数:计算2的x次幂
//
DWORD CHandwritingView::Pow2(UINT x)
{
DWORD dwProduct;
UINT i;
for(dwProduct=1,i=1;i<=x;i++)
dwProduct*=2;
return dwProduct;
}
/////////////////////////////////////////////////////
//字符笔划删除函数:将字符笔划链表中的笔划节点删除并
//释放相应资源。
//
void CHandwritingView::DeleteStrokes()
{
STROKES *pTemp;
//删除一个字符的所有笔划节点
//
while(Strokes)
{
pTemp=Strokes;
Strokes=Strokes->pStroke ;
pTemp->pStroke =NULL;
if (pTemp)
delete pTemp;
}
}
///////////////////////////////////////////////////////////
//实例按钮函数:根据给定的笔划数据,动态地展示实例
//字符的手写过程
void CHandwritingView::OnbtnSample()
{
UINT i;
STROKES *pTmp;
//示例字符“龙飞凤舞”的笔划数据
//
static _STROKE lffw[]={{34,13,39,18,3,10,1},{39,18,45,24,12,9,1},{45,16,45,27,1,6,1},{20,33,28,32,1,10,1},{29,31,48,29,10,7,1},{51,28,70,30,5,6,1},{37,31,40,52,7,6,1},{52,35,51,42,2,7,1},
{52,41,44,50,3,7,1},{9,71,15,66,2,9,1},{19,64,27,58,13,7,1},{29,56,58,54,5,5,1},{41,53,41,66,5,8,1},{41,68,26,89,7,7,1},{26,88,23,137,7,5,2},{41,65,48,76,3,4,1},
{46,73,46,132,6,7,3},{48,118,35,101,8,4,3},{34,99,31,69,3,7,3},{36,70,73,71,5,9,3},{73,68,90,64,5,7,2},{90,61,83,54,2,5,1},{83,54,75,58,3,5,1},{76,56,70,103,5,5,3},
{71,94,83,85,8,7,2},{82,86,97,85,8,7,1},{97,86,81,102,7,7,1},{82,101,82,121,6,7,2},{84,119,120,121,6,9,3},{119,119,130,110,7,9,1},{130,110,130,100,6,5,1},{131,100,124,98,5,7,1},
{124,95,113,97,5,6,1},{108,96,109,90,6,6,1},{110,88,119,80,6,8,1},{118,79,119,71,5,6,1},{119,72,113,73,2,6,1},{116,72,106,63,5,5,1},{107,61,106,53,7,5,1},{107,53,102,47,7,7,1},
{103,48,83,44,5,5,1},{82,42,112,37,10,9,1},{113,37,118,33,9,1,1},
{132,25,164,24,8,7,1},{162,22,162,49,6,5,1},{164,49,196,50,6,8,3},{198,50,198,23,6,3,3},{198,21,196,17,3,7,1},{194,17,189,18,5,4,1},{188,17,180,26,4,6,1},{180,25,186,31,4,3,1},
{188,30,201,31,3,3,1},{204,30,213,39,7,7,1},{210,36,210,53,8,9,1},{212,51,177,89,10,6,3},{176,88,176,109,4,6,2},{176,107,189,117,5,6,1},{188,113,230,114,6,5,2},{229,113,215,101,8,8,2},
{217,101,204,102,5,8,1},{205,98,189,111,8,6,2},{187,110,187,91,3,3,2},{186,89,176,85,4,4,1},{117,84,162,73,5,5,2},{162,73,142,74,6,5,1},{143,73,140,71,4,6,1},{140,69,136,55,8,8,1},
{135,54,143,51,7,8,1},{143,50,155,59,7,7,1},{153,58,153,91,7,6,2},{152,89,144,129,7,12,1},{144,122,127,143,10,7,2},{130,139,127,143,6,1,1},{236,28,237,40,2,5,1},{237,38,241,52,6,7,1},
{241,50,243,80,6,5,1},{253,35,277,37,6,7,2},{275,37,276,48,7,5,1},{276,47,277,87,6,5,1},{277,87,292,91,5,7,1},{290,89,312,91,5,6,3},{311,89,313,85,8,6,1},{312,83,312,71,6,6,2},
{312,72,295,42,5,6,2},{294,40,290,14,5,5,3},{290,12,279,14,6,5,1},{280,14,261,32,5,7,3},{261,31,260,47,6,6,2},{256,45,259,86,6,9,3},{259,83,268,96,6,10,3},{266,93,254,102,5,8,2},
{254,101,254,117,12,7,2},{253,116,266,129,6,7,1},{267,126,275,131,5,3,1},
{308,27,315,43,7,4,1},{313,39,326,22,9,5,1},{326,20,340,22,7,5,1},{339,21,345,31,5,4,1},{344,28,352,28,6,6,1},{350,26,371,24,10,5,1},{371,24,379,36,7,6,1},{377,32,389,31,4,9,1},
{387,28,401,24,9,5,1},{402,24,422,16,9,8,1},{333,43,344,69,7,6,1},{360,43,361,74,11,8,1},{382,43,380,54,5,5,1},{407,42,392,57,5,7,1},{392,56,384,78,10,5,1},{384,77,378,80,3,6,1},
{377,79,375,77,5,4,1},{325,63,406,57,10,7,1},{350,78,335,99,7,7,3},{343,90,355,108,7,7,2},{353,105,352,126,4,8,2},{351,123,336,129,9,8,2},{338,127,328,128,6,8,1},{331,127,320,121,7,8,2},
{314,120,334,118,8,7,3},{333,115,413,93,8,5,3},{414,91,414,73,4,4,2},{415,74,406,70,5,5,2},{405,67,399,95,7,10,2},{399,87,399,153,11,8,3},{377,104,377,122,8,6,2},{376,118,407,121,8,8,3},
{406,121,414,117,7,4,3},{-1,0,0,0,0,0,0}};
//根据事先录制得到的示例字符“龙飞凤舞”的数据构造其
//链表结构并显示之
//
i=0;
if(Strokes)
DeleteStrokes();
while(lffw[i].x1>-1)
{
pTmp= new _STROKES;
if(pTmp==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pTmp->Stroke.x1=lffw[i].x1 ;
pTmp->Stroke.y1=lffw[i].y1 ;
pTmp->Stroke.x2=lffw[i].x2 ;
pTmp->Stroke.y2=lffw[i].y2 ;
pTmp->Stroke.x1=lffw[i].x1 ;
pTmp->Stroke.Width1=lffw[i].Width1;
pTmp->Stroke.Width2=lffw[i].Width2;
pTmp->Stroke.Speed=lffw[i].Speed;
pTmp->pStroke =NULL;
if(pCurrentStroke)
{
pCurrentStroke->pStroke=pTmp;
pCurrentStroke=pTmp;
}
if(Strokes==NULL)
{
Strokes=pTmp;
pCurrentStroke=pTmp;
}
i++;
}
sOperated=sPlaying;
Writing(Strokes,1,5,false,1,10,10,m_pDC,false);
sOperated=sPlayed;
bmp=false;
bErase=false;
}
//////////////////////////////////////////
//屏幕重画函数:在窗口显示区改变时重新显示
//先前的内容
//
void CHandwritingView::Draw()
{
if(!bErase)
{
if(bmp)
DrawBitmap(pBuff,0,0,m_pDC);
else
Writing(Strokes,1,5,false,1,10,10,m_pDC,true);
}
}
////////////////////////////////////////////////////////
//数据按钮更新消息函数:系统自动更新数据按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnCoordinate(CCmdUI* pCmdUI)
{
pCmdUI->Enable (Strokes!=NULL);
}
////////////////////////////////////////////////////////
//录制结束按钮函数:结束本次字符的笔划录制过程。
//
void CHandwritingView::OnbtnEnd()
{
sOperated=sRecorded;
}
////////////////////////////////////////////////////////
//结束按钮更新消息函数:系统自动更新结束按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnEnd(CCmdUI* pCmdUI)
{
pCmdUI->Enable (sOperated==sRecording);
}
////////////////////////////////////////////////////////
//字符按钮更新消息函数:系统自动更新字符按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnOpenBmp(CCmdUI* pCmdUI)
{
pCmdUI->Enable ((sOperated!=sRecording)&&(sOperated!=sPlaying));
}
////////////////////////////////////////////////////////
//播放按钮更新消息函数:系统自动更新播放按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnPlay(CCmdUI* pCmdUI)
{
pCmdUI->Enable (Strokes!=NULL&&sOperated!=sPlayed&&sOperated!=sRecording);
}
////////////////////////////////////////////////////////
//录制按钮更新消息函数:系统自动更新录制按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnRecord(CCmdUI* pCmdUI)
{
pCmdUI->Enable (bmp);
}
////////////////////////////////////////////////////////
//示例按钮更新消息函数:系统自动更新示例按钮的状态。
//
void CHandwritingView::OnUpdatebtnSample(CCmdUI* pCmdUI)
{
pCmdUI->Enable ((sOperated!=sRecording)&&(sOperated!=sPlaying)) ;
}
/////////////////////////////////////////////
//显示刷新按钮函数:启动对屏幕显示内容的刷新。
//
void CHandwritingView::OnbtnRefresh()
{
bErase=true;
Invalidate(TRUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -