VC++6.0语言中的矢量图形技术
一、 自动生成程序框架
1. 新建工作区
打开VC++6.0->菜单“文件”->“新建”:
2. 选择位置(目录)E:/vc_test,输入工程名称Mdocs,选择类型:MFC AppWizard(exe)
3. 按“确定”后进入下一步,选择文档类型:多文档,语言:中文
4. 设定数据库,数据库类型,文件
5. 设定服务器,Automation, ActiveX
6. 设定界面参数
7. 按“完成”后,系统会为你创建所有的应用程序框架
8. 注:不同的系统所生成的程序框架的详细程度不同
二、 正文文字输入
1. 添加键盘输入成员函数
2. 添加字符数组变量
3. 将字符加入到数组中
4. 窗口中显示文本
1-2-3-4实例:
//以下函数输入文本:
void CMDocsView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
int x = (rect.Width() - 0) / 1;
int y = (rect.Height() - 0) / 1;
double charwidth=9; //设定字符宽度(假设)
static int i=0,j=0; //设定静态变量为数组的下标,每次调用后仍保持其值
if ((nChar==13) || j>x/charwidth-1) //输入回车,或者,到达右边缘
m_inputstring[i][j]=nChar; //字符到数组
}
m_inputstring[i][j]=nChar; //正常位置记录输入
CClientDC dc(this); //窗口指针
dc.TextOut( 0,i*16,&m_inputstring[i][0],j+1); //输出
CView::OnChar(nChar, nRepCnt, nFlags);
}
5. 刷新时重写所有文本
/////////////////////////////////////////////////////////////////////////////
// CMDocsView drawing 图形刷新:
void CMDocsView::OnDraw(CDC* pDC)
{
CMDocsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//以下输出数组中的文本:
int i=0,j=0,n=0; //循环变量
CClientDC dc(this); //输出窗口,this当前活动窗口
for (i=0;i<=1024;i++) //循环
{
if (m_inputstring[i][0]<13) //每行的第一个字符=13回车符
if (m_inputstring[i][n]<=13) //循环求出回车符前的字符长度
dc.TextOut( 0,i*16,&m_inputstring[i][0],j); //输出字符串
//dc.TextOut (int x,int y,CString &str,Length)
}
//文本输出结束
}
三、 绘制图形
(1) ResourceView->Menu->IDR_MDOCSTYPE ->菜单虚线框按右键->属性:
B) ID:为该菜单指定一个名称,对应于一个整型值,唯一性,程序自动指定
C) 提示栏输入菜单的功能简要说明
2. 给菜单添加函数
(1) 菜单“查看”->“建立类向导”->
(2)
(3) 选择该菜单项的类Class Name:CMainFrame
(4) 选择对象识别号Object IDs:AFX_ID_DRAW_LINE,先前在菜单项中所定义的
(5) 在消息栏中选择消息传递函数Messages:COMMAND
(6) 点击右上角的“Add Function”按钮,便完成了函数添加工作
(7) 点击右上角的“Edit Code”按钮,在函数中添加内容:只能自己动手。例:
添加下列代码可绘出一条直线:
void CMDocsView::OnIdDrawLine()
{
// TODO: Add your command handler code here
CClientDC dc(this);
POINT Point;
Point.x=100;
Point.y=200;
dc.LineTo(Point);
}
注意:C的大小写是敏感的,别忘了分号结束每一条语句,括号、引号等要成对的打入,
3. 添加成员变量,标示那个菜单项被点击
(1) 在ClassView中选择菜单所在的类CMainFrame,右键,Add Member Variable…
(3) 在窗口的创建中初始化变量
C语言中申请变量后不加初始化,则其值是不确定的!其他语言?请举例
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
draw_menu_control=0; //添加该语句
return 0;
}
(4) 自己定义该变量对应于菜单项的规则
draw_menu_control=0; //没有选择
draw_menu_control=1; //绘制直线
draw_menu_control=2; //绘制圆
draw_menu_control=3; //绘制圆弧
draw_menu_control=4; //绘制长方形
draw_menu_control=5; //绘制多边形
。。。。。。
(5) 在菜单函数中加入上述定义:
void CMDocsView::OnIdDrawLine()
{
// TODO: Add your command handler code here
draw_menu_control=1; //绘制直线
mouse12=0; //鼠标器按键次数初始化
}
4. 在View类中添加成员函数OnLButtonUp(UINT nFlags, CPoint point)
参看上面的“2. 给菜单添加函数”
5. 记录图形的起始点和终止点
(1) 添加成员变量,记录点坐标,参看前面的说明,可以在File View项中的??View.h中找到其定义:
// Implementation
public:
int y0;
int x0;
int x1,y1;
(2) 添加成员变量,标记鼠标左键是第一次还是第二次按下
??View.h:
// Implementation
public:
int mouse12; //=1第一次,=2第二次,=3第三次,。。。。。。
(3) 在函数OnLButtonUp(UINT nFlags, CPoint point)中添加绘图代码:
第一次按键:记录坐标值:
第二次按键:绘图:
void CMDocsView::OnLButtonUp(UINT nFlags, CPoint point)
{
if (mouse12= = 0)
mouse12=1;
if (draw_menu_control = = 1 || draw_menu_control = = 2 || draw_menu_control = = 3) //绘制直线或圆
{
if (draw_menu_control==1 && mouse12==1) //第一次
{ x0=point.x;
y0=point.y;
mouse12=2;
mouse_move_count=0; //鼠标器移动次数初始化
}
else //第二次
{
if (draw_menu_control==1 && mouse12==2) //选择了绘制直线菜单
{
dc.MoveTo (x0,y0); //移到第一点
dc.LineTo (point); //画到第二点
mouse12=0; //鼠标器第一次按键
draw_menu_control=0; //菜单选择复位
}
}
}
else
{…}
}
6. 画笔
CClientDC dc(this);
CPen penBlue; // Construct it, then initialize
if( penBlue.CreatePen( PS_DOT, 1, RGB(0,0,255) ) ) //如果画笔创建成功
// CreatePen(线型、线宽、颜色RGB(RED,GREEN,BLUE))
{
// Select it into the device context
// Save the old pen at the same time
CPen* pOldPen = dc.SelectObject( &penBlue ); //选择新的画笔,返回老的画笔
// Draw with the pen
dc.MoveTo (x0,y0);
dc.LineTo (p);
// Restore the old pen to the device context
dc.SelectObject( pOldPen ); //恢复老的画笔
}
else
{
// Alert the user that resources are low //出错处理
}
//PS_SOLID Creates a solid pen.
//PS_DASH Creates a dashed pen. Valid only when the pen width is 1 or less, in device units. //
//PS_DOT Creates a dotted pen. Valid only when the pen width is 1 or less, in device units.
//PS_DASHDOT Creates a pen with alternating dashes and dots.
//PS_DASHDOTDOT Creates a pen with alternating dashes and double dots.
//。。。。。。
7. 实现橡皮筋技术
(1) 在View类中添加成员函数OnMouseMove(UINT nFlags, CPoint point)
(2) 绘制一个新的图形
(3) 反色绘制上一个图形
(4) 不能删掉其它的已经存在的图形
实例:
// 随着鼠标器的移动,函数会返回一系列的坐标点point
//(1)在View类中添加成员函数OnMouseMove(UINT nFlags, CPoint point):
void CMDocsView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CPen penBlue; // Construct it, then initialize
if( penBlue.CreatePen( PS_DOT, 1, RGB(0,0,255) ) ) //蓝色画笔,用于画橡皮筋线
{
// Select it into the device context
// Save the old pen at the same time
CPen* pOldPen = dc.SelectObject( &penBlue );
// Draw with the pen
if (draw_menu_control= =1 && mouse12= =2) //如果绘制直线,且,有了第一次按键:
CPen penGND; //P1
if (penGND.CreatePen( PS_SOLID, 3, RGB(255,255,255) )) //背景色 P2
//白色画笔,与底色相同,用于删除上一根橡皮筋线
{ CPen* pOldPen1 = dc.SelectObject( &penGND ); //选择画笔P3
//设定反色画笔的4句P1-P4, 可以用下列绘图方式设定来代替:
//dc.SetROP2(R2_NOT); //设定画笔与屏幕的Pixel的inverse运算
POINT p;
if (mouse_move_count= =0)
{ x1=x0;
y1=y0;
}
p.x=x1;p.y=y1;
dc.MoveTo (x0,y0);
dc.LineTo (p); //删除上次的直线
dc.SelectObject( pOldPen1 ); //恢复画笔P4
}
dc.MoveTo (x0,y0);
dc.LineTo (point);
x1=point.x;
y1=point.y; //记录当前点的坐标,为下次删除准备
}
mouse_move_count=mouse_move_count+1; //鼠标器移动次数增加
// Restore the old pen to the device context
dc.SelectObject( pOldPen );
}
else
{
// Alert the user that resources are low
}
CView::OnMouseMove(nFlags, point);
}
8. 避免新绘制的实体覆盖老的实体
void CMDocsView::OnLButtonUp(UINT nFlags, CPoint point)
dc.SetROP2(R2_XOR); //画笔PEN与屏幕SCREEN的PIXEL取或运算
}
9. 在图形绘制过程中避免鼠标器干别的事情
//在安下第一次鼠标按键进入绘图时,调用鼠标器捕捉:
10. 记录实体参数
(1) 申请坐标数组
typedef struct
{
int x;
int y;
} PlineVertexStruct;
PlineVertexStruct PlineVertex[500][50]; //实体数:500;顶点数:50
(2) 实体属性参数
int ObjectLineWidth[500]; //实体线宽
int ObjectLineType[500]; //实体线型
int ObjectColor[500]; //实体颜色
int ObjectType[500]; //实体类型
int ObjectCount; //实体数量
(3) 变量的初始化
BOOL CMDocsView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
//以下初始化用户变量:
LineColor=RGB(0,255,0); //初始化颜色
LineType=PS_SOLID; //初始化线型
LineWidth=1; //初始化线宽
ObjectCount=-1; //初始化实体数量
for (int i=0;i<500;i++) //初始化实体坐标点
for (int j=0;j<50;j++)
{
PlineVertex[i][j].x=0;
PlineVertex[i][j].y=0;
}
return CView::PreCreateWindow(cs);
}
(4) 在记录所绘图形的坐标和实体属性
//鼠标器左键抬起
void CMDocsView::OnLButtonUp(UINT nFlags, CPoint point)
{
if (mouse12==1) //第一次
{if (draw_menu_control==1 ||draw_menu_control==2 ||draw_menu_control==3)
{ x0=point.x;
y0=point.y;
ObjectCount++; //增加实体数量
ObjectColor[ObjectCount]=LineColor; //记录该实体的颜色
ObjectLineWidth[ObjectCount]=LineWidth; //记录该实体的线宽
ObjectLineType[ObjectCount]=LineType; //记录该实体的线型
ObjectType[ObjectCount]=draw_menu_control; //记录该实体的线型
PlineVertex[ObjectCount][0].x=point.x ; //记录该实体的顶点坐标
PlineVertex[ObjectCount][0].y=point.y ;
mouse12=2;//记录该实体的颜色
mouse_move_count=0; //鼠标器移动次数初始化
SetCapture(); //捕捉鼠标
}
}
else //第二次
{
//绘制直线:
if (draw_menu_control==1 ||draw_menu_control==2 && mouse12>=2) //选择了绘制直线菜单
{
dc.MoveTo (x0,y0); //移到第一点
dc.LineTo (point); //画到第二点
x0=point.x; //如果绘制PLINE,该终点作为下一段线的起点
y0=point.y;
PlineVertex[ObjectCount][mouse12-1].x=point.x ;
PlineVertex[ObjectCount][mouse12-1].y=point.y ;
mouse12++; //鼠标器第i次按键
if (draw_menu_control==1) draw_menu_control=0; //菜单选择复位
}
if (draw_menu_control==3 && mouse12==2) //选择了绘制圆菜单
{
dc.MoveTo (x0,y0); //移到第一点
dc.Ellipse(x0-CircleR,y0-CircleR,x0+CircleR,y0+CircleR); //画到第二点
PlineVertex[ObjectCount][mouse12-1].x=CircleR ;
mouse12=0; //鼠标器第一次按键
draw_menu_control=0; //菜单选择复位
}
ReleaseCapture(); //释放鼠标
} //else end of 第二次按键
}
11. 在View类中的OnDraw(CDC* pDC)实现重画
/////////////////////////////////////////////////////////////////////////////
// CMDocsView drawing 图形刷新:
void CMDocsView::OnDraw(CDC* pDC)
//为了使用CMDocsDoc中申请的变量 :step1/3: MdocsView.cpp中: #include "MDocsDoc.h"
CMDocsDoc* pDoc = GetDocument();
//step 2/3: 定义文档类的指针,然后初始化该指针
ASSERT_VALID(pDoc);
//此两个语句APPWizard已经帮你创建好了。
// TODO: add draw code for native data here
//CMDocsDoc* doc;
//为了使用CMDocsDoc中申请的变量
//doc=GetDocument();
//也可以分开来写
CClientDC dc(this);
//输出窗口,this当前活动窗口
dc.SetROP2(R2_MASKPEN);
//设定画笔与屏幕的Pixel的或运算
if (pDoc->m_inputstring[i][n]<=13) //循环求出回车符前的字符长度 // step 3/3: 红色部分:使用MDocsDoc.h中定义的变量时,变量前加类指针名->
dc.TextOut( 0,i*16,&pDoc->m_inputstring[i][0],j); //输出字符串
//dc.TextOut (int x,int y,CString &str,Length)
if (pDoc->m_inputstring[i+1][0]<13) //每行的第一个字符=13回车符
for (i=0;i<=pDoc->ObjectMaxQt;i++)
CPen penRED; // Construct it, then initialize
if( penRED.CreatePen( pDoc->ObjectLineType[i], pDoc->ObjectLineWidth[i], pDoc->ObjectColor[i] ) ) //使用当前色LineColor
// Select it into the device context
// Save the old pen at the same time
CPen* pOldPen = dc.SelectObject( &penRED );
dc.MoveTo (pDoc->PlineVertex[i][0].x,pDoc->PlineVertex[i][0].y);
if (pDoc->ObjectType[i]==1 || pDoc->ObjectType[i]==2) //直线类
for (j=0;j<=pDoc->ObjectVertexQt[i];j++)
dc.LineTo (pDoc->PlineVertex[i][j].x,pDoc->PlineVertex[i][j].y);
if (pDoc->PlineVertex[i][j+1].x==0 && pDoc->PlineVertex[i][j+1].y==0 && pDoc->PlineVertex[i][j+2].x==0 && pDoc->PlineVertex[i][j+2].x==0)
if (pDoc->ObjectType[i]==3) //圆
dc.Ellipse (pDoc->PlineVertex[i][0].x-pDoc->PlineVertex[i][1].x,pDoc->PlineVertex[i][0].y-pDoc->PlineVertex[i][1].x,pDoc->PlineVertex[i][0].x+pDoc->PlineVertex[i][1].x,pDoc->PlineVertex[i][0].y+pDoc->PlineVertex[i][1].x);
if (pDoc->PlineVertex[i+1][0].x==0 && pDoc->PlineVertex[i+1][0].y==0 && pDoc->PlineVertex[i+1][1].x==0 && pDoc->PlineVertex[i+1][1].x==0)
dc.SelectObject( pOldPen );
} //end of if CreatePen()
//在CMDocsDoc类中使用void CMDocsDoc::Serialize(CArchive& ar)进行输入输出,参数(CArchive& ar)指向外存文件,
/////////////////////////////////////////////////////////////////////////////
// CMDocsDoc serialization
void CMDocsDoc::Serialize(CArchive& ar)
if (ar.IsStoring()) //写文件开始
// TODO: add storing code here
if (m_inputstring[0][0]>13) //无文本时不输出:ASCII13是回车符。
ar.WriteString("T,"); //流输出:行头:T-文本,L-直线,C-圆
if (m_inputstring[i][n+1]<=13) //循环求出回车符前的字符长度
ar.WriteString(m_inputstring[i]) ; //输出字符串
if (m_inputstring[i+1][0]<=13) //每行的第一个字符=13回车符
for (i=0;i<=ObjectMaxQt;i++)
if (ObjectType[i]==1 || ObjectType[i]==2) //直线类:L,线型,线宽,颜色,起始点,顶点,。。。
itoa(ObjectLineType[i],ItoS,10);
itoa(ObjectLineWidth[i],ItoS,10);
itoa(ObjectColor[i],ItoS,10);
for (j=0;j<=ObjectVertexQt[i];j++)
itoa(PlineVertex[i][j].x,ItoS,10);
itoa(PlineVertex[i][j].y,ItoS,10);
if (PlineVertex[i][j+1].x==0 && PlineVertex[i][j+1].y==0 && PlineVertex[i][j+2].x==0 && PlineVertex[i][j+2].x==0)
if (ObjectType[i]==3) //圆:C,线型,线宽,颜色,中心点,半径
itoa(ObjectLineType[i],ItoS,10);
itoa(ObjectLineWidth[i],ItoS,10);
itoa(ObjectColor[i],ItoS,10);
itoa(PlineVertex[i][0].x,ItoS,10);
itoa(PlineVertex[i][0].y,ItoS,10);
itoa(PlineVertex[i][1].x,ItoS,10);
ar.WriteString("/0"); ///0字符串结束,
ar.WriteString("/n"); ///0字符串结束,
if (PlineVertex[i+1][0].x==0 && PlineVertex[i+1][0].y==0 && PlineVertex[i+1][1].x==0 && PlineVertex[i+1][1].x==0)
// TODO: add loading code here
ff.open ("ppp.txt",ios::out);
if (ar.ReadString(readCString)) //ar.ReadString()返回true,如果成功
if (readCString[0]=='T') //文字处理
readCString=readCString.Right (readCString.GetLength()-2);
_tcscpy(m_inputstring[i],readCString);
//_tcscpy(char*,CString)将CString转换成char*,反向运算CString=_T(char*)
if (readCString[0]=='L' || readCString[0]=='P') //直线处理
readCString=readCString.Right (readCString.GetLength()-2);
ff<<readCString.GetLength()<<"//";
pos=strcspn(readCString,strtemp); //strcspn("fsabcd","bc"),返回3
ff<<"pos="<<pos<<" k="<<k<<" j="<<j;
if (pos <readCString.GetLength()) //如果有","
PlineVertex[j][m].x=atoi(readCString.Left (pos));
readCString=readCString.Right (readCString.GetLength()-pos-1);
pos1=strcspn(readCString,strtemp);
if (pos1<readCString.GetLength()) //后面还有点坐标
PlineVertex[j][m].y=atoi(readCString.Left (pos1));
readCString=readCString.Right (readCString.GetLength()-pos1-1);
PlineVertex[j][m].y=atoi(readCString);
if (k==0) ObjectLineType[j]=atoi(readCString.Left (pos));
if (k==1) ObjectLineWidth[j]=atoi(readCString.Left (pos));
if (k==2) ObjectColor[j]=atoi(readCString.Left (pos));
readCString=readCString.Right (readCString.GetLength()-pos-1);
} //end of if (int pos=strcspn(readCString,strtemp)<readCString.GetLength())
//_tcscpy(char*,CString)将CString转换成char*,反向运算CString=_T(char*)
ObjectMaxQt=j;ff<<"j="<<j<<" m="<<ObjectVertexQt[j];
else //如果读不成功,结束serialization函数,也可以添加告警代码
} //end of while(true)读循环
} //end of void CMDocsDoc::Serialize(CArchive& ar)
四、 图形的画面操作
(1) 在函数void CMDocsView::OnLButtonDown(UINT nFlags, CPoint point)中记录起始点坐标point0
(2) 在函数void CMDocsView::OnLButtonUp(UINT nFlags, CPoint point)中:
Ø 记录终止点坐标point1
Ø 将所有的坐标点平移point1-point0;
Ø 发出重画消息,调用重画函数ON_Draw()
(1) 在函数void CMDocsView::OnLButtonDown(UINT nFlags, CPoint point)中记录选择窗口起始点坐标point0
(2) 在函数void CMDocsView::OnLButtonUp(UINT nFlags, CPoint point)中:
Ø 记录选择窗口终止点坐标point1
Ø 计算选择窗口与视图窗口的平移量和比例
Ø 将所有的坐标点平移,并放大比例;
Ø 发出重画消息,调用重画函数ON_Draw()
Ø 计算出所有图形实体的矩形区域
Ø 计算该矩形区域与视图窗口的平移量和比例
Ø 将所有的坐标点平移,并放大比例;
Ø 发出重画消息,调用重画函数ON_Draw()
设定一个数组,记录图形画面操作的每一步参数
五、 编辑图形
1.编辑菜单
2.鼠标器的位置是否落在图形实体上
3.编辑对话框
4.实体改变的程序体
六、 管理图形
1. 图形实体的层
3. 图形实体的线型
4. 图形实体的附加信息
5. 图形实体外部信息库链接
七、 格式转换
1. 图形交换格式DXF