
画坐标是很简单的,分别画两条直线代表x轴和Y轴(需要的话可以加上箭头美观一些),刻度线可以当成是短的线段,画一条条短直线来代表就是了。
你说的画函数的图像,不知道是固定的一个函数还是要能给一个函数公式就能画出这个函数的图像。如果是固定的函数,比如你图里面的函数,函数公式你有了,剩下的还是画线,这个函数分成三段直线,计算出每段直线的起点坐标和终点坐标,分别画线即可。
画线,画点,画箭头用到的都是gdi函数,PolyLine画线,其余的函数你可以自查一下msdn,都有例子。
1 画像素点
画像素点就是设置像素点的颜色,从前面3)(2)已知道这可由CDC的成员函数SetPixel来做,该函数的原型为:
COLORREF SetPixel( int x, int y, COLORREF crColor ); 或
COLORREF SetPixel( POINT point, COLORREF crColor );
其中,x与y分别为像素点的横坐标与纵坐标,crColor为像素的颜色值。例如
pDC->SetPixel(i, j, RGB(r, g, b));
2.画线状图
在Windows中,线状图必须用笔来画(笔的创建与使用见前面的3)(3)),下面是CDC类中可以绘制线状图的常用成员函数:
当前位置:设置当前位置为(x, y)或point:(返回值为原当前位置的坐标)
CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point);
画线:使用DC中的笔从当前位置画线到点(x, y)或point:(若成功返回非0值):
BOOL LineTo( int x, int y ); 或BOOL LineTo( POINT point );
画折线:使用DC中的笔,依次将点数组lpPoints中的nCount(≥2)个点连接起来,形成一条折线:
BOOL Polyline( LPPOINT lpPoints, int nCount );
画多边形:似画折线,但还会将最后的点与第一个点相连形成多边形,并用DC中的刷填充其内部区域:
BOOL Polygon( LPPOINT lpPoints, int nCount );
画矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2,y2)或范围为lpRect的矩形的边线,并用DC中的刷填充其内部区域:
BOOL Rectangle( int x1, int y1, int x2, int y2 ); 或
BOOL Rectangle( LPCRECT lpRect );
有时需要根据用户给定的两个任意点来重新构造左上角和右下角的点,例如:
rect = CRect(min(p0x, pointx), min(p0y, pointy), max(p0x,pointx), max(p0y, pointy));
画圆角矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2,y2)或范围为lpRect的矩形的边线,并用宽x3或pointx高y3或pointy矩形的内接椭圆倒角,再用DC中的刷填充其内部区域:
BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3);
BOOL RoundRect( LPCRECT lpRect, POINT point );
例如:
int d = min(rectWidth(), rectHeight()) / 4;
pDC-> RoundRect(rect, CPoint(d, d));
画(椭)圆:使用DC中的笔在左上角为(x1, y1)、右下角为(x2,y2)或范围为lpRect的矩形中画内接(椭)圆的边线,并用DC中的刷填充其内部区域:
BOOL Ellipse( int x1, int y1, int x2, int y2 );
BOOL Ellipse( LPCRECT lpRect );
注意,CDC中没有画圆的专用函数。在这里,圆是作为椭圆的(宽高相等)特例来画的。
画弧:(x1, y1)与(x2, y2)或lpRect的含义同画(椭)圆,(x3, y3)或ptStart为弧的起点,(x4,y4)或ptEnd为弧的终点:(逆时针方向旋转)
BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, intx4, int y4 );
BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4,int y4);
BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
画圆弧:(其中(x, y)为圆心、nRadius为半径、fStartAngle为起始角、fSweepAngle为弧段跨角)
BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, floatfSweepAngle);
画弓弦:参数的含义同上,只是用一根弦连接弧的起点和终点,形成一个弓形,并用DC中的刷填充其内部区域:
BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, intx4, int y4 );
BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
3.画填充图
在Windows中,面状图必须用刷来填充(刷的创建与使用见前面的3)(4))。上面(2)中的Polygon、Rectangle、Ellipse和Chord等画闭合线状图的函数,只要DC中的刷不是空刷,都可以用来画对应的面状图(边线用当前笔画,内部用当前刷填充)。下面介绍的是CDC类中只能绘制面状图的其他常用成员函数:
画填充矩形:用指定的刷pBrush画一个以lpRect为区域的填充矩形,无边线,填充区域包括矩形的左边界和上边界,但不包括矩形的右边界和下边界:
void FillRect( LPCRECT lpRect, CBrush pBrush );
画单色填充矩形:似FillRect,但只能填充单色,不能填充条纹和图案:
void FillSolidRect( LPCRECT lpRect, COLORREF clr );
void FillSolidRect( int x, int y, int cx, int cy, COLORREF clr);
画饼图(扇形):参数含义同Arc,但将起点和终点都与外接矩形的中心相连接,形成一个扇形区域,用DC中的刷填充整个扇形区域,无另外的边线:
BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, intx4, int y4 );
BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
画拖动的矩形:先擦除线宽为sizeLast、填充刷为pBrushLast的原矩形lpRectLast,然后再以线宽为size、填充刷为pBrush画新矩形lpRectLast。矩形的边框用灰色的点虚线画,缺省的填充刷为空刷:
void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECTlpRectLast,
SIZE sizeLast, CBrush pBrush = NULL, CBrush pBrushLast = NULL);
如:pDC->DrawDragRect(rect, size, rect0, size);
填充区域:
用当前刷从点(x, y)开始向四周填充到颜色为crColor的边界:
BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0
用当前刷从点(x, y)开始向四周填充:
BOOL ExtFloodFill(int x, int y, COLORREF crColor,
UINT nFillType); // 成功返回非0
nFillType =FLOODFILLBORDER:填充到颜色为crColor的边界(同FloodFill);(用于填充内部颜色不同但边界颜色相同的区域)
nFillType =FLOODFILLSURFACE:填充所有颜色为crColor的点,直到碰到非crColor颜色的点为止。(点(x,y)的颜色也必须为crColor),(用于填充内部颜色相同但边界颜色可以不同的区域)。例如:
pDC->ExtFloodFill(pointx, pointy,pDC-> GetPixel_r(point), FLOODFILLSURFACE);
4.清屏
Windows没有提供专门的清屏函数,可以调用CWnd的下面两个函数调用来完成该功能:
void Invalidate(BOOL bErase = TRUE);
void UpdateWindow( );
或调用CWnd的函数
BOOL RedrawWindow(
LPCRECT lpRectUpdate =NULL,
CRgn prgnUpdate =NULL,
UINT flags = RDW_INVALIDATE |RDW_UPDATENOW | RDW_ERASE
);
来完成。
例如(菜单项ID_CLEAR的事件处理函数):
CDrawView::OnClear() { // 调用OnDraw来清屏
//Invalidate();
//UpdateWindow( );
RedrawWindow( );
}
也可以用画填充背景色矩形的方法来清屏,如:
RECT rect;
GetClientRect_r(&rect);
pDC->FillSolidRect(&rect, RGB(255,255, 255));
1、可以在内存中建立一张缓存,然后在这个上画你需要的图,然后输出到窗体,这样你可以直接保存成了。
2、画在bitmap上
bitmap有save方法
创建graphics的时候用:GraphicsFromImage()
对的
控制点是不会经过的
第一条曲线以第二点和第三点为控制点,将第一点和第四点连接而绘成的。其后每条曲线都需要三个点:以前一条曲线的终点为起点,其后两点为控制点,第三个点则作为终点。
也就是说 你的曲线只会经过
1,4,7,11,15,19。。。这样的点
其余为控制点,而且int nCount的值须是终点数 不然会返回FALSE
MFC中没其他函数可代替他
C++ GUI 绘图控件目录
MFC(VC)
VS2010 使用TeeChart绘图控件 - 之一 - 控件和类的导入
VS2010 使用TeeChart绘图控件 - 之二 - 绘制图形(折线图,柱状图)
TeeChart绘图控件 - 之三 - 提高绘图的效率
MFC下好用的高速绘图控件-(Hight-Speed Charting)
绘制动态曲线
Qt
qt超强精美绘图控件 - QCustomPlot一览
qt超强绘图控件qwt - 安装及配置
对于任何绘图控件,都可以实现动态绘图,其原则是:控件只负责绘图,若想曲线动,就让数据动,就像看**一样,**是由一帧一帧的静态组合起来的,在一定速度上刷新,静态就能动起来;和**的原理一样,绘图控件能显示静态的曲线,想要它动起来,就让它频在一定时间刷新就可以了。
这就是动态绘图的实现原理。
实现动态曲线需要以下两个准备:
计时器Timer
数组左移
基于Timer的绘图
任何界面库都会有Timer这个实现,在MFC中时OnTimer消息,在Qt中是QTimer类,那种原理基本都一样,下面将以MFC(VC)为例进行说明。
Timer是消息级别最低的消息,它会保证其它级别高的消息优先执行,因此,就算数据大量刷新,也不会影响主线程的其它消息。
MFC生成OnTimer消息,消息响应函数如下:
[cpp] view plaincopyvoid CTeeChartDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码或调用默认值
CDialogEx::OnTimer(nIDEvent);
}
绘图的实现就在这个消息响应函数里
如果让定时器设定为1秒触发,每一秒把旧数据去除,绘制新数据,就能看到不停变换的波形;对于趋势图,假如每秒有一个新数据,那么就在定长数组中,把数组所有数据整体左移,同时数组末端加入新数据。代码如下:
[cpp] view plaincopy///
/// \brief 左移数组
/// \param ptr 数组指针
/// \param data 新数值
///
void LeftMoveArray(double ptr,size_t length,double data)
{
for (size_t i=1;i<length;++i)
{
ptr[i-1] = ptr[i];
}
ptr[length-1] = data;
}
此函数把整个数组左移,然后新数据放置在数组最末端(右端)。
这样,数组就实现“向左运动”,把左移后的数组绘制,就能在绘图控件上发现其变化。
下面开始实现动态绘图(这里演示TeeChart的方法,附件里有HightSpeed-Chart CChartCtrl的方法):
[cpp] view plaincopyvoid CTeeChartDlg::OnBnClickedButtonRuning()
{
KillTimer(0);
ZeroMemory(&m_TeeChartArray,sizeof(double)m_c_arrayLength);
for (size_t i=0;i<m_c_arrayLength;++i)
{
m_X[i] = i;
}
m_count = m_c_arrayLength;
CSeries chart_T = (CSeries)m_ChartSeries(0);
chart_TClear();
m_pLineSerie->ClearSerie();
SetTimer(0,1000,NULL);
}
函数中几个成员变量的定义是:
[cpp] view plaincopydouble m_TeeChartArray[2096];
double m_X[2096];
unsigned int m_count;
const size_t m_c_arrayLength = 2096;
m_TeeChartArray是需要绘制的数组的Y值,m_X是对应的x值,m_count是计数器,每绘制一次,个数加1,主要用于x轴
在timer中的实现如下:
void CTeeChartDlg::OnTimer(UINT_PTR nIDEvent){
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(0 == nIDEvent)
{
++m_count;
drawMoving();
}
CDialogEx::OnTimer(nIDEvent);
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)