绘制成绩分布图docxWord格式.docx
《绘制成绩分布图docxWord格式.docx》由会员分享,可在线阅读,更多相关《绘制成绩分布图docxWord格式.docx(17页珍藏版)》请在冰豆网上搜索。
在玩游戏的过程中看到的不是画面,而是各种数据在有规律的运动,计算,时刻进行着各种循环和假设判断,我玩的已不是游戏,而是方程式……这段话深刻的反映出了游戏的设计过程。
同样也折射出了程序设计的原理。
在绘图这方面以前只设计过简单的直线曲线自由线画图,而对于这样的数据自动绘图没有涉及到,在设计出来前就曾想过做一个图像处理程序,不过在看过程序的复杂性以及时间短暂的原因,没有着手哪方面的准备,在这之后课题为绘图设计正好可以弥补这方面的空缺。
设计时由于没有任何的基础,所以搜索了很多资料,最终锁定了一个比较简单的模板,将模板打出来是很简单的事情,但是真正有趣的是后面的调试完善工作,其中各种环节都是围绕绘制矩形和绘制扇形而来,大量的工作就是将数据导入数组并将其处理分组得到其人数以后将其转化为矩形以及为立体而设计的平行四边形的坐标,扇形的坐标。
其他的一些完善代码大部分都是辅助的,不过在设计过程中也是十分有趣的。
在设计过程中遇到了很多问题,从最简单的矩形图数据分析到后来的文件操作以及画刷颜色的随机选取,模拟按键消息,各种错误的报错提醒等等问题都一一排除,通过查阅大量资料来进行各种完善。
因为学过其他的编程软件,所以在编程的过程中,也在比较两者的区别,各自的特点以及缺点,不同和相同之处。
C++的各类分的比较详细,在创建变量时也是通过对话框创建,结构性比较好,适合于团队协作;
而另一个编程软件(delphi)则在类于类之间比较模糊,所有的工作都在Form上操作,不过这样操作起来比较方便,整合的控件也相当多,直接摆放即可,适合个人应用。
不管哪种软件都是为编程而服务的,其目的是一样的,只是在操作上不同而已,通过两个软件的比较是自己更好的掌握了其类的概念,控件的用途,在函数以及属性的设计上都有了更深的理解。
语言都是想通的,在学过一门语言以后其他的便可以读懂了。
最开始学习的是C++,而后又接触了delphi,在刚开始学习delphi的过程中基本上都可以读懂其中的代码,而后再学习VisualC++便轻松多了。
在刚开始讲课的时候几乎不知道怎么去分析处理,因为有了前者使用的习惯,所以在后者使用时总会想当然的以为该那样,其实两者在程序使用中有很大的不同,即使到了考试时也不是很明白该怎么去使用它。
直到现在设计这个小程序时才系统的将这个软件大致的掌握了其使用方法。
在变量声明以及转换显示,属性的动态修改等等都有了一个新的认识。
那么剩下的在编程方面的思想以及windowsAPI接口函数的使用都是相通的。
只不过实现的过程不一样而已。
在设计过程中遇到了很多错误,软件自身带有的DEBUG功能有一定的好处,但是这个功能不怎么会用,而在查阅资料的时候记得看到过用MessageBox来调试程序的用法,如果出错了,那么就用MessageBox来看看到底程序执行到了什么步骤,出现对话框,则说明之前的都执行过了,如果没出现,则程序没执行到这里就已经产生了错误。
MessageBox还可以显示所处理的数据或者字符串的变化。
用起来相当简单。
这个小技巧是自己在调试过程中效率提高了不少,在源代码中,这些MessageBox并没有删除,只是注释掉了,在以后分析的时候这也是相当有帮助的。
五、出现的错误及改正方法
1.刚开始是将浏览和导入的函数集成到一个按钮“浏览”里面,但是在调试中发现如果单击浏览而不选中文件的话,会出现错误二终止。
通过分析其主要原因是因为函数理念有导入数据的代码,单击后会一并执行,如果没有选中文件那么就无法导入数据产生错误。
解决方法:
将浏览和导入功能分装到两个按钮里面,并在导入数据的时候检测是否有文件导入。
如果没有则报错提醒。
2.在绘制直方图或圆饼图时如果没有数据则会出现错误而自动终止程序,原因是数组当中没有数据而无法绘图。
定义全局变量,在导入后全局变量变为1,绘制时检测全局变量是否为1,是则绘制,否则报错提醒。
3.在录入过程中难免会录入错误,所以查看录入和重新录入就显得很重要了。
而在录入的过程中会出现录入人数大于所规定的人数的,这样在数组存放数据时就会产生错误。
增加重新录入和查看录入成绩的功能,为了方便起见,每行显示五个成绩,而且在录入时对录入人数做了一个判断,如果大于所输人数,则提示成绩录入完毕。
4.在做圆饼图时发现如果某一分数段的人数为0的话,就会产生这样的结果
这种结果并不是我们想要的。
图中可以看到本来没有的分数段70-80覆盖掉了原有的<
60和60-70的分数段。
在绘制过程中对绘制扇形一部分做了检测,发现如果所绘制分数段如果为零则不绘制这段扇形。
这样结果便正常了。
5.由于绘图部分并不是在OnPaint函数里所写的,而是直接在按钮里添加的,所以在程序重新得到焦点重绘的过程中会产生这样的错误:
一部分被挡住的图形丢失了。
虽说可以重新点击绘图重绘,不过这样的事情最好不要发生。
在程序重绘的过程中在OnPaint事件里添加如下代码:
if(DrawMode==1)
{
PostMessage(WM_COMMAND,IDC_BUTTON1,BN_CLICKED);
}
elseif(DrawMode==2)
PostMessage(WM_COMMAND,IDC_BUTTON2,BN_CLICKED);
这是模拟单机事件的代码,在重绘过程中自动模拟单机事件。
DrawMode是定义的一个绘图模式,若单机绘制直方图,DrawMode=1;
单机绘制圆饼图,DrawMode=2。
在重绘过程中自动模拟但是过程。
省去了使用者再次点击的过程。
六、设计中的关键源程序
1、绘制直方图代码:
voidCMy09228DulichaoDlg:
:
OnButton1()
{
if(True==0)
{
MessageBox("
未导入数据!
"
"
错误!
);
}
else
CClientDC*pDC=newCClientDC(this);
constintx0=280,y0=35,x1=780,y1=395;
//定义绘制的矩形区域
//CFileDialogofn(TRUE,NULL,"
*.txt"
OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST,"
Textfiles(*.txt)\0*.txt\0"
//ofn.DoModal();
//FILE*fp=fopen(ofn.GetPathName(),"
rt"
intN,*a;
inti,x,y;
CStrings;
//for(fscanf(fp,"
%d,"
&
N),a=newint[N],i=0;
i<
N;
++i)
//{fscanf(fp,"
a[i]);
//}
//fclose(fp);
N=Num;
a=newint[N];
//inta[N];
for(i=0;
a[i]=Score[i];
//CStringstr1;
//str1.Format("
%d"
a[i]);
//MessageBox(str1,"
//将全局变量Score[i]里的数据传递给局部变量a[i]
}
//MessageBox()"
;
intSc[5];
Sc[0]=0;
Sc[1]=0;
Sc[2]=0;
Sc[3]=0;
Sc[4]=0;
i++)
if(a[i]<
60)
Sc[0]++;
else
if(a[i]<
70)//统计各个分段中的人数
Sc[1]++;
if(a[i]<
80)
{
Sc[2]++;
}
else
if(a[i]<
90)
{
Sc[3]++;
}
else
Sc[4]++;
intMax=0;
5;
if(Sc[i]>
Max)//确定五个分段中最大的个数
Max=Sc[i];
//MessageBox("
adfasdf"
sss"
//调试所用
constintdx=(x1-x0)/5,M=30,dy=(y1-y0)/10,h=dx/4,dh=(y1-y0)/Max;
CPointv[4];
CBrushbr;
CPenpen,*p_pen;
#defineRrand()%56+200
BYTEr,g,b;
br.CreateSolidBrush(RGB(126,126,126));
pDC->
SelectObject(&
br);
//srand((unsigned)time(NULL));
CRectrc;
GetClientRect(&
rc);
pDC->
Rectangle(x0-40,0,rc.right,rc.bottom);
//画出绘制区域
br.DeleteObject();
MoveTo(x0,y1);
LineTo(x=x1+80,y1);
MoveTo(x,y1);
LineTo(x-12,y1-3);
LineTo(x-12,y1+3);
//画出x轴
LineTo(x0,0);
MoveTo(x0,0);
LineTo(x0-3,12);
LineTo(x0+3,12);
//画出y轴
pen.DeleteObject();
//pDC->
SetROP2(R2_MASKPEN);
//pen.CreatePen(PS_DOT,1,RGB(70,70,70));
//p_pen=pDC->
pen);
MoveTo(x1+55,0);
LineTo(x1+55,y1);
pen.CreatePen(PS_SOLID,2,RGB(0,0,0));
p_pen=pDC->
for(i=0,x=x0;
++i,x+=dx)
br.CreateSolidBrush(RGB(r=R,g=R,b=R));
Rectangle(x,y1-dh*Sc[i],x+dx,y1);
//画出矩形区域
v[0].x=x+dx;
v[0].y=y1-dh*Sc[i];
v[1].x=v[0].x+h;
v[1].y=v[0].y-h;
v[2].x=v[1].x-dx;
v[2].y=v[1].y;
v[3].x=v[2].x-h;
v[3].y=v[2].y+h;
//画出顶部平行四边形区域
Polygon(v,4);
SelectStockObject(WHITE_BRUSH);
if(i==4||Sc[i]>
Sc[i+1])
br.CreateSolidBrush(RGB(r*0.7,g*0.7,b*0.7));
pDC->
v[2].x=v[1].x;
v[2].y=v[1].y+dh*Sc[i];
v[3].x=x+dx;
v[3].y=y1;
//画出侧边四边形区域
br.DeleteObject();
SelectObject(p_pen);
pen.CreatePen(PS_DOT,1,RGB(70,70,70));
for(y=y1,i=0;
y>
=y0;
++i,y-=dh)
if(y!
=y0&
&
y!
=y1)
MoveTo(x0,y);
LineTo(x1+h+30,y);
///沿y轴标注
s.Format("
%3d"
i);
TextOut(250,y-8,s);
CStringren;
ren="
人"
s.Format("
%s"
ren);
TextOut(260,10,s);
CStringStr[5];
Str[0]="
<
60分"
Str[1]="
60-70分"
Str[2]="
70-80分"
Str[3]="
80-90分"
//x轴标注
Str[4]="
>
90分"
Str[i]);
TextOut(x0+i*dx+(dx-s.GetLength()*8)/2,y1+4,s);
//沿x轴标注
%d人"
Sc[i]);
TextOut(x0+i*dx+(dx-s.GetLength()*8)/2+6,y1-20-dh*Sc[i],s);
//顶层标注人数
CStringfen;
fen="
分数"
fen);
TextOut(x0+i*dx+(dx-s.GetLength()*8)/2+30,y1+4,s);
deletepDC;
//删除指针
if(a!
=NULL)deletea;
//Num=1;
//将最大数清零
DrawMode=1;
True=1;
2.绘制饼形图源代码
if(True==0)
CClientDC*pDC=newCClientDC(this);
#defineSums[n-1]
constintr=170,p=20;
constintx0=r+20,y0=r+20,x1=x0-r,y1=y0-r,x2=x0+r,y2=y0+r;
intn=5,*data=newint[n],*s=newint[n];
staticintpromin=0;
///////////////////////////////*
//CStrings;
//将全局变量Score[i]里的数据传递给局部变量a[i]
///////////////////////////////////////////////
data[0]=Sc[0];
data[1]=Sc[1];
//将分数段传给data数组
data[2]=Sc[2];
data[3]=Sc[3];
data[4]=Sc[4];
intx3,y3,x4,y4;
doubletheta3,theta4,thetam,tx,ty;
//#defineR156+rand()%100
//BYTEr1,g,b;
CBrushbr,*p_br;
CRectrc;
TEXTMETRICtxMetric;
GetTextMetrics(&
txMetric);
//br.CreateSolidBrush(RGB(r1=R,g=R,b=R));
//pDC->
CStringstr;
br.CreateSolidBrush(RGB(126,126,126));
Rectangle(240,0,rc.right,rc.bottom);
//绘图区域
for(s[0]=data[0],i=1;
n;
++i)
s[i]=s[i-1]+data[i];
//求总和
srand((unsigned)time(NULL));
CStringStr1[5];
Str1[0]="
Str1[1]="
Str1[2]="
Str1[3]="
Str1[4]="
for(theta3=0.0,x3=x0+r/*x0=r+20*/,y3=y0/*y0=r+20*/,i=0;
theta4=_2PI*s[i]/Sum;
//角度值
x4=x0+r*cos(theta4);
//三角值
y4=y0+r*sin(theta4);
thetam=(theta3+theta4)*0.5;
//三角平均值
if(i!
=promin)
tx=ty=0;
tx=p*cos(thetam)*(_2PI-theta4+theta3)/_2PI;
ty=p*sin(thetam)*(_2PI-theta4+theta3)/_2PI;
if(data[i]!
=0)
//#defineRrand()%56+200
br.CreateSolidBrush(RGB(255+i*50,300+i*80,50+i*60));
p_br=pDC->
Pie(x1+tx+250,y1+ty,x2+tx+250,y2+ty/*边缘矩阵*/,x4+tx+250,y4+ty/*起始点*/,x3+tx+250,y3+ty/*终止点*/);
//第一个是边缘矩阵,第二个是起始点,第三个是终止点
str.Format("
data[i]);
//各个分段数据
TextOut(x0+tx-txMetric.tmAveCharWidth*str.GetLength()*0.5+r*0.7*cos(thetam)+250,y0+ty-(txMetric.tmExternalLeading+txMetric.tmHeight)*0.5+r*0.7*sin(thetam),str,str.GetLength());
//显示分段数据
Rectangle(700,150+i*40,720,170+i*40);
str.Format("
Str1[i]);
TextOut(740,150+i*40,str);
theta3=theta4;
x3=x4;
y3=y4