相关代码如下:
// 先在类中定义三个变量bool m_painting; // 是否正在绘制
CPoint m_pointOri; // 中心点
float m_radius; // 半径Cdemo98View::Cdemo98View()
{
m_painting = false;
m_radius = 0;
}
void Cdemo98View::OnDraw(CDC pDC)
{
Cdemo98Doc pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
pDC->Ellipse(m_pointOrix - m_radius, m_pointOriy - m_radius, m_pointOrix + m_radius, m_pointOriy + m_radius);
}
void Cdemo98View::OnLButtonDown(UINT nFlags, CPoint point)
{
m_pointOri = point;
m_radius = 0;
m_painting = true;
}
void Cdemo98View::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_painting) {
// 计算当前点距离中心点距离也就是半径
m_radius = sqrt(pow(float(pointx - m_pointOrix), 2) + pow(float(pointy - m_pointOriy), 2));
Invalidate();
}
}
void Cdemo98View::OnLButtonUp(UINT nFlags, CPoint point)
{
// 计算当前点距离中心点距离也就是半径
m_radius = sqrt(pow(float(pointx - m_pointOrix), 2) + pow(float(pointy - m_pointOriy), 2));
m_painting = false;
Invalidate();
}
运行结果:
以下方法可在MFC和控制台中都可以实现:
1HDC hdc = GetDC(HWND hWnd); 获得设备上下文的客户区一个指定的窗口或整个屏幕
eg:如果是在窗口类中可以:
HDC hdc = GetDC(this->m_hWnd);
2在窗口区画点。
SetPixel(
hdc,
x, // 横坐标
y , // 纵坐标
RGB(100,100,100)); //点的颜色。
3 画线
MoveToEx(
HDC hdc,
int X, // 横坐标
int Y, // 纵坐标
LPPOINT lpPoint //保存先前的点的位置,在这里你可以直接写NULL
)
LineTo(
HDC hdc, // device context handle
int nXEnd, // x-coordinate of line's ending point
int nYEnd // y-coordinate of line's ending point
);
4画圆
函数:
Ellipse(
HDC hdc, // handle to device context
int nLeftRect, // x-coord of bounding rectangle's upper-left corner
int nTopRect, // y-coord of bounding rectangle's upper-left corner
int nRightRect, // x-coord of bounding rectangle's lower-right corner
int nBottomRect // y-coord of bounding rectangle's lower-right corner
);
eg :Ellipse(hdc,0,0,100,100);
所谓的动态画线,画矩形,画椭圆的本质就是在于消隐问题的解决以及对Windows消息循环机制的理解,消隐问题:因为MFC中有一个函数SetROP2,通过将该函数的参数设置为R2—NOT(当前绘制的像素值设为屏幕像素值的反色,这里面的“屏幕”二字是指你所绘制的图形所占据的那一部分屏幕区域,即直线所占的屏幕区域就是直线所在的那一段线的区域),利用这一点通过在同一区域重复画两次便可以将该区域的形状消隐。
而Windows消息循环机制更好的体现于MouseMove消息响应中,因为要实现动态画线、画矩形这就体现在鼠标在绘图区的移动上,鼠标在绘图区移动时,产生动态的效果,也就是说在mouse 移动的过程中始终在画线、画矩形,这就要求在MouseMove消息响应中有画线、画矩形的相应函数的调用,但正是因为mouse移动的过程中画了很多的线、矩形,所以我们就要在mouse移动的过程中将之前画出的线、矩形消隐掉,才能保证实现了自己所要实现的功能——动态画线、画矩形,但又没有产生多余的线和矩形。
消隐的问题和动态画图的问题关键在于MouseMove消息响应中的函数调用的顺序:
1首先将上次所画的图形消隐掉
2画出临时的图形
3消息循环的机制:循环执行上述代码(这是Windows循环的机制,不需要自己代码实现)
在最后的LButtonUp消息响应中,需要将上面的MouseMove消息响应中循环的最后一次中最后所画的临时图形消隐掉,之后根据LButtonUp消息响应中point参数画出最终的图形。综上可知:MouseMove中的代码和LButtonUp中消隐临时图形的代码所要实现的功能就是动态这一过程,而图形的最终绘制还在与LButtonUp消息响应及其point参数。
代码如下:
[cpp] view plaincopy
private:
[cpp] view plaincopy
//
HCURSOR m_HCross;
UINT m_drawType;
CPoint m_OldPoint;
CPoint m_startPoint;
BOOL m_startRect;
[cpp] view plaincopy
CGISView::CGISView()
{
// TODO: add construction code here
//
m_startRect=FALSE;
m_startPoint=0;
m_OldPoint=0;
m_drawType=0;
//初始化m_HCross为十字光标
m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
}
[cpp] view plaincopy
void CGISView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_startRect=TRUE; //鼠标左键单击,设置可以开始绘制矩形框
m_startPoint=point; //记录起始点
m_OldPoint=point;//设置老点也为起始点
//设置光标为十字光标
::SetCursor(m_HCross);
CView::OnLButtonDown(nFlags, point);
}
[cpp] view plaincopy
void CGISView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this); //获取设备句柄
dcSetROP2(R2_NOT);//此为关键
dcSetROP2(R2_NOT);//所绘制的图形并没有消失,所以可以验证下面的连续两次颜色取反不是在一次相应中完成
//SetRop2 Specifies the new drawing mode(MSDN)
//R2_NOT Pixel is the inverse of the screen color(MSDN)
//即:该函数用来定义绘制的颜色,而该参数则将颜色设置为原屏幕颜色的反色
//这样,如果连续绘制两次的话,就可以恢复原来屏幕的颜色了(如下)
//但是,这里的连续两次绘制却不是在一次消息响应中完成的
//而是在第一次拖动响应的绘制可以显示(也就是看到的),第二次拖动绘制实现擦出(也就看不到了)
dcSelectStockObject(NULL_BRUSH);//不使用画刷
if(TRUE==m_startRect) //根据是否有单击判断是否可以画矩形
{
switch(m_drawType)
{
case 1://Rectangle
::SetCursor(m_HCross);
dcRectangle(CRect(m_startPoint,m_OldPoint));
dcRectangle(CRect(m_startPoint,point));
m_OldPoint=point;
break;
case 2: //Line
::SetCursor(m_HCross);
//擦去上一次绘制的临时线
dcMoveTo(m_startPoint);
dcLineTo(m_OldPoint);
//绘制这一次的临时线
dcMoveTo(m_startPoint);
dcLineTo(point);
//将临时线的终点复制给m_OldPoint,
//使其在消息循环的过程中将该值传递到
//擦去上一次画线的过程中,以便擦去上一次所画的线
m_OldPoint=point;
break;
case 3: //Circle
::SetCursor(m_HCross);
//擦去上一次绘制的临时圆
//设定该圆的y坐标,因为要保证两点的x之差等于y之差
m_OldPointy=m_OldPointx-m_startPointx+m_startPointy;
dcEllipse(CRect(m_startPoint,m_OldPoint));
//绘制临时圆
pointy=pointx-m_startPointx+m_startPointy;
dcEllipse(CRect(m_startPoint,point));
m_OldPoint=point;
break;
case 4: //Ellipse
::SetCursor(m_HCross);
dcEllipse(CRect(m_startPoint,m_OldPoint));
dcEllipse(CRect(m_startPoint,point));
m_OldPoint=point;
break;
case 5: //Dot
break;
}
[cpp] view plaincopy
}
[cpp] view plaincopy
}
[cpp] view plaincopy
void CGISView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_startRect=FALSE;//重置绘制矩形框标志
::ClipCursor(NULL);//解锁光标,即将光标恢复为默认光标
//消隐最后的一个矩形
CClientDC dc(this);//获取设备句柄
// dcSetROP2(R2_NOT); //在MouseMove消息响应中使用过该函数了,所以在这里再一次使用会使得其恢复为屏幕的颜色
dcSelectStockObject(NULL_BRUSH); //设置画刷为空画刷
switch(m_drawType)
{
case 1: //Retangle
//利用当前画刷绘制矩形,内部由当前空画刷(NULL_BRUSH)填充。
//擦去MouseMove消息响应中的临时矩形
dcRectangle(CRect(m_startPoint,m_OldPoint));
//绘制固定矩形
dcRectangle(CRect(m_startPoint,point));
//m_drawType=0; //该行的可以使得每画一次都要选择所画的形状
break;
case 2: //Line
//擦去MouseMove消息响应中绘制的最后一次临时线
dcMoveTo(m_startPoint);
dcLineTo(m_OldPoint);
//绘制固定线
dcMoveTo(m_startPoint);
dcLineTo(point);
break;
case 3: //Circle
dcEllipse(CRect(m_startPoint,m_OldPoint));
dcEllipse(CRect(m_startPoint,point));
break;
case 4: //Ellipse
dcEllipse(CRect(m_startPoint,m_OldPoint));
dcEllipse(CRect(m_startPoint,point));
break;
case 5: //Dot
dcSetPixel(point,RGB(0,0,0));
break;
}
CView::OnLButtonUp(nFlags, point);
}
[cpp] view plaincopy
void CGISView::OnRectangle()
{
// TODO: Add your command handler code here
m_drawType=1;//设置所画的为矩形
}
void CGISView::OnLine()
{
// TODO: Add your command handler code here
m_drawType=2;
}
void CGISView::OnEllipse()
{
// TODO: Add your command handler code here
m_drawType=4;
}
void CGISView::OnDot()
{
// TODO: Add your command handler code here
m_drawType=5;
}
void CGISView::OnCircle()
{
// TODO: Add your command handler code here
m_drawType=3;
}
以上为自己根据实际编程练习和对博文的学习所领悟到的,如果有哪里理解的不对,还望大家指正,谢谢哈!(代码没有问题,可以正常运行。)
注:代码的排版,我多次修改,并确保整齐,但是一旦我发表后,代码的排版就会发生改变,有几行代码就会变得不规则。
MFC里面画点是dcpixel(point)
//这里的point是你设置ClickButtonDown或者ClickButtonUp里面返回的CPoint类型的值,如果是画线的话,调用moveto()函数到直线的起点,然后lineto函数到终点
;如果你要画圆的话用Ellipse()函数,ellipse(CRect());
CRect是一个类型的变量,你需要用两个点来构造一个CRect
CRect rc ;
CStatic pPic = (CStatic)GetDlgItem(IDC_STATIC_Pic);
pPic->GetClientRect(&rc);//获得控件客户区大小
CDC pDC = pPic->GetDC();//获取绘图DC
int cx=rcright;
int cy=rcbottom;
pDC->SetMapMode(MM_ANISOTROPIC);//X=Y
pDC->SetWindowExt(cx,cy); //设置窗口坐标系的大小
pDC->SetViewportExt(cx,cy);//定义输出视口,X向右,Y向上 |_
pDC->SetViewportOrg(m_movePointx,m_movePointy);//设置坐标原点 左下为圆点 注:我的这个坐标好像是我移动时候的标记点,你把这个设为你自己的固定点就行。
CPen pen(PS_SOLID, 1, RGB(255,0,255));
pDC->SelectObject(pen);
pDC->SelectStockObject(NULL_BRUSH);
pDC->Ellipse(&rect); // 这个就是画圆了 其实是椭圆 只要把参数设置为正方形 就是圆了
CPen penSide(PS_SOLID, 1, RGB(255,0,0));
pDC->SelectObject(penSide);
pDC->Ellipse(&rctSide);
//删除画笔
penDeleteObject();
penSideDeleteObject();
ReleaseDC(pDC);
可以调用API的AngleArc()函数,或者CDC::AngleArc()函数
以API的AngleArc为例:
//函数原型
BOOL AngleArc(
HDC hdc, // handle to device context
int X, // x-coordinate of circle's center
int Y, // y-coordinate of circle's center
DWORD dwRadius, // circle's radius
FLOAT eStartAngle, // arc's start angle
FLOAT eSweepAngle // arc's sweep angle
);
//具体使用:如圆心(20,20),半径15,从pi/到pi/2。
AngleArc(hdc,20,20,15,pi,-pi/2);//eSweepAngle是相对起始角度计算的角度值
可以用CRgn,创建一个环形区域,然后dcFillRgn进行填充
画圆程序源代码:
import javaawt;
import javaawtevent;
public class DrawOval extends JFramwe{
public DrawOval()
{
super(画圆);
setBounds(0,0,100,100);
setVisible(true);
}
public void paint(Graphics g)
{
gsetColor(Colorred);//画红圆
gdrawOval(0,0,100,100);//在50,50处画一个半径为50的圆
}
public static void main(String[] args)
{
DrawOval do=new DrawOval();
}
}
以上就是关于MFC动态画圆全部的内容,包括:MFC动态画圆、VC6.0下如何实现圆弧插补、MFC编程ellipse()怎么画圆等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)