📄 clplot.cpp
字号:
if(printerDC!=NULL)
printerDC->SelectObject(oFont);
else
dc.SelectObject(oFont);
}
//*******************************************************************************************************/
//* Function: clPlot::OnPaint
//*
//* Description: This function will create a memory image, call Draw to draw the plot on it, and when
//* copy the image into memory.
//*
//* This is fast and provides flicker free plot update.
//*
//* Author: Jan Vidar Berger
//*******************************************************************************************************/
void clPlot::OnPaint()
{
CPaintDC dc(this); // device context for painting
CMemDC pdc(&dc); // non flickering painting
Draw(&pdc);
// Do not call for painting messages
}
BOOL clPlot::OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}
//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::Draw(CDC * dc)
{
CFont *oFont;
CFont newfont;
newfont.CreateFontIndirect(&m_zoomFont);//以前是将字体指针直接
//选进设备环境,在打印预览时常导致字体资源丢失错误。故此处改为
//直接创建字体,字体大小与m_font相同,只不过是重新创建了一次而已。
oFont = dc->SelectObject(&newfont);
DrawBasic(dc); //画整个图区的边框和背景
DrawGrid(dc); //画网格
DrawPlot(dc); //画主曲线
if(m_bDrawLegend)
DrawLegend(dc);//画图例
dc->SelectObject(oFont);
}
//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::Print(CDC * dc)
{
Draw(dc);// 在打印机上打印
}
//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::DrawBasic(CDC * dc)
{
CBrush brushctlBkColor(m_ctlBkColor);
CRect lrect;
lrect=m_ctlRect;
lrect.left-=5;lrect.top-=5;
//实际过程中不知为何总出现左上边缘不能清除问题,只好将m_ctlRect向左上扩展
dc->FillRect(lrect,&brushctlBkColor);//清整个图区(包括刻度标示,margin区等)
CBrush brushPlotBkColor(m_plotBkColor);
dc->FillRect(m_plotRect,&brushPlotBkColor);//清整个图区(包括刻度标示,margin区等)
if(dc->IsPrinting())
dc->Rectangle(m_plotRect);//打印时不用3D线,以使打印清楚
else
{
CRect lr=m_plotRect;
lr.InflateRect(1,1);
dc->DrawEdge(lr,EDGE_BUMP, BF_RECT);//(在屏幕上)画3D边框
}
if(m_bDrawLegend)
DrawLegendShadow(dc);//画图例阴影
}
//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::DrawPlot(CDC * dc)//画曲线
{
for(int s=0;s<MAXSERIES;s++)
{
if(m_series[s].m_bIAmInUse)
{
DrawSerie(dc, s);//依次画各条曲线
}
}
}
//*******************************************************************************************************/
//*******************************************************************************************************/
//已调试通过,只是曲线采样间隔超过X轴最大时间时不显示 2000.9.21
void clPlot::DrawSerie(CDC *dc,int serie) //画曲线的核心程序
//serie:曲线索引号(从0开始)
{
BOOL bMore=TRUE;
BOOL bDraw;
CPoint point;
int counter;//本图中实际要画的点数
// lets get some serie parameters now and save the time of indexing during the loop
//实际值从m_series[serie].m_pvalues[m_lbegin]到m_series[serie].m_pvalues[m_lend]画第serie条曲线
long pointer = m_series[serie].m_lbegin;
long end = m_series[serie].m_lend;
long valueNos = m_series[serie].m_lNoValues;//第serie曲线采样的总点数
BOOL bRightAxis = m_series[serie].m_bRightAxisAlign;//右Y轴
CPen pen(m_series[serie].m_iLineStyle, 3, m_series[serie].m_color);//画曲线的笔
CPen *old;
//画实时曲线
old= dc->SelectObject(&pen);
int pLineArrayStart=1;
int thelastpoint=0;//记录在可视区最后一个点在数组中的位置
_value * mvalues=m_series[serie].m_pvalues;//
while(bMore)
{
bDraw=FALSE;
bMore=FALSE;
counter=0;
counter=1;//预留pLineArray[0]为实测数据与左轴的交点
//while(pointer != end && !bDraw)
while(pointer != end )
{
//Scaling. We do scaling inline to save some time
long valuetime = mvalues[pointer].ValueTime;
//X轴坐标(像素为单位)
point.x = (int)(m_plotRect.left+ ((valuetime-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
if(!bRightAxis) //左Y轴
point.y = (int)(m_plotRect.bottom - ((mvalues[pointer].dValue-m_leftaxis.minrange)/m_leftaxis.m_dValuePrPixel));
//像素
else
point.y = (int)(m_plotRect.bottom - ((mvalues[pointer].dValue-m_rightaxis.minrange)/m_rightaxis.m_dValuePrPixel));
//TRACE("counter=%d point.x=%d point.y=%d \n",counter,point.x,point.y);
if(point.x >= m_plotRect.left && point.x <= m_plotRect.right)
{//采样点落在当前图可视区域
if(counter==1)//在可视区域画的第一个点
{
//到采样起点间的采样点数
int dist=(pointer-m_series[serie].m_lbegin+clPlot::m_lMaxDataPrSerie)%( clPlot::m_lMaxDataPrSerie)+1;
if(dist>=2)//当前至少为采样数组第2个点后面的点
{//计算与左Y轴的交点坐标
int lastpointer=(pointer-1+clPlot::m_lMaxDataPrSerie)%( clPlot::m_lMaxDataPrSerie);//pointer最大不超过clPlot::m_lMaxDataPrSerie
long lasttime=mvalues[lastpointer].ValueTime;
CPoint lastpoint;
//计算前一个采样点的坐标值
lastpoint.x = (int)(m_plotRect.left+ ((lasttime-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
if(bRightAxis) //右Y轴
lastpoint.y = (int)(m_plotRect.bottom - ((mvalues[lastpointer].dValue-m_rightaxis.minrange)/m_rightaxis.m_dValuePrPixel));
else
lastpoint.y = (int)(m_plotRect.bottom - ((mvalues[lastpointer].dValue-m_leftaxis.minrange)/m_leftaxis.m_dValuePrPixel));
//与左轴交点的坐标
pLineArray[0].x =m_plotRect.left;
if(point.x!=lastpoint.x)
{
pLineArray[0].y = (lastpoint.y*(point.x-m_plotRect.left)+point.y*(m_plotRect.left-lastpoint.x))/(point.x-lastpoint.x);
pLineArrayStart=0;
}
else
point.x=lastpoint.x;
}//if(pointer>=1)
}//if(counter==1) end
pLineArray[counter].x = point.x;
pLineArray[counter].y = point.y;
thelastpoint=pointer; //记录在可视区最后一个点在数组中的位置
counter++;//counter:本图中实际要画的点数
}
pointer++;//指向第serie曲线采样值的存储数组
pointer=pointer%( clPlot::m_lMaxDataPrSerie);//pointer最大不超过clPlot::m_lMaxDataPrSerie
if(pointer > valueNos) // wrap list index ?
pointer=0;
}//while(pointer != end end
if(counter-pLineArrayStart>0)
{
dc->Polyline(pLineArray+pLineArrayStart, counter-pLineArrayStart);
}
}//while(bMore) end
dc->SelectObject(old);
}
//*******************************************************************************************************/
//*
//*******************************************************************************************************/
void clPlot::DrawGrid(CDC * dc)
{
DrawXAxisGrid(dc); //画X轴网格
DrawYAxisGrid(dc);//画Y轴网格并标Y轴坐标
}
//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::DrawXAxisGrid(CDC * dc)//画X轴网格并标X轴坐标
{
long yGrid = m_timeaxis.m_mintime;
long delta =(m_timeaxis.m_maxtime-m_timeaxis.m_mintime)/m_iXBigGrids;//X轴分为m_iXBigGrid个大网格(模认为6)
long d10 = delta / 5;//每大格间又分为5小格
long diff = ((long)yGrid)%((long)delta);
CPen *old, pen(PS_DASHDOTDOT, 0, m_gridColor);//竖向的主分割线
CPen stick(PS_DASH,0,RGB(0,0,0));//坐标轴下的短线
CPen mline(PS_SOLID,0,RGB(192,192,192));//浅灰(竖向的辅分割线)
int i;
TRACE("画坐标x轴开始\n");
m_lMaxDataPrSerie;
i=(m_series[0].m_lNoValues-1)%( clPlot::m_lMaxDataPrSerie);
if(i>=0)
{
_value &vv=m_series[0].m_pvalues[i];
TRACE("Nos=%d array[%d]=%f valtime=%d \n ",m_series[0].m_lNoValues,i,vv.dValue,vv.ValueTime);
}
if(m_timeaxis.m_mintime!=0)
{
TRACE(" mintime= %d maxtime=%d \n",m_timeaxis.m_mintime,m_timeaxis.m_maxtime);
}
for( long sx = m_timeaxis.m_mintime; sx < m_timeaxis.m_maxtime; sx+=d10)
{
int off=3;
off=8;
if((long)sx%(long)delta == 0)
off=10;
if(sx > m_timeaxis.m_mintime)
{
int x = (int)(m_plotRect.left + ((sx-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
old = dc->SelectObject(&stick);
TRACE("刻度线:moveto( %d, %d ) lineto(%d,%d)\n",x,m_plotRect.bottom,x+off,m_plotRect.bottom);
dc->MoveTo(CPoint(x,m_plotRect.bottom));
dc->SelectObject(old);
if(m_bXThinGrid)//竖向的细线
{
old = dc->SelectObject(&mline);
TRACE("xthingrid: moveto(%d,%d) lineto(%d,%d) \n",x,m_plotRect.bottom-1,x,m_plotRect.top+1);
dc->MoveTo(CPoint(x,m_plotRect.bottom-1));
dc->LineTo(CPoint(x,m_plotRect.top+1));//竖向的细线
dc->SelectObject(old);
}
}
}
old = dc->SelectObject(&pen);
COLORREF oldbkcolor=dc->SetBkColor(m_ctlBkColor);//刻度字符的背景色
COLORREF oldtxtcolor=dc->SetTextColor(m_txtColor);//刻度字符的颜色
int ykedu=m_plotRect.bottom+5;//刻度所在Y坐标
for(yGrid=m_timeaxis.m_mintime,i=0;i<=m_iXBigGrids;i++)
{
int x = (int)(m_plotRect.left + ((yGrid-m_timeaxis.m_mintime)/m_timeaxis.m_dMilliSecondsPrPixel));
if(m_bXThickGrid)//竖向的粗线
{
if(x>m_plotRect.left && x<m_plotRect.right&&i!=m_iXBigGrids)
{
TRACE("竖向粗线:moveto( %d, %d ) lineto(%d,%d)\n",x,m_plotRect.bottom-1,x,m_plotRect.top+1);
dc->MoveTo(CPoint(x,m_plotRect.bottom-1));
dc->LineTo(CPoint(x,m_plotRect.top+1));//竖向粗线
}
}
//标X轴刻度值--时间(s)
char b[100];
double ft=(double)yGrid/1000.0;//时间:s
sprintf(b, "%.2f", ft);
CSize size=dc->GetTextExtent(CString("A"));
CString lstr(b);
size=dc->GetTextExtent(lstr);
int y=m_clientRect.bottom+(int)(size.cy*1.5)+5;
int len=size.cx;
y=m_plotRect.bottom;
TRACE("刻度 rect( %d, %d %d,%d,%s)\n",x-len/2, ykedu,x+len/2,ykedu+size.cy,b);
TRY
{
if(!dc->TextOut(x-len/2, ykedu,lstr))
AfxThrowResourceException();
}
CATCH(CResourceException,e)
{
CString msgStr("resource error");
AfxMessageBox((const char*)msgStr);
}
AND_CATCH_ALL(e)
{
CString msgStr("other error");
AfxMessageBox((const char*)msgStr);
}
END_CATCH_ALL
yGrid += delta;
}
//标X轴名称及单位
CSize size=dc->GetTextExtent(m_timeaxis.m_szTitle);
int center=(m_plotRect.left+m_plotRect.right)/2;
TRACE("x轴名称 rect( %d, %d %d,%d)\n",center-size.cx/2,m_ctlRect.bottom-size.cy-2,center+size.cx/2,m_ctlRect.bottom-2);
int y=(m_ctlRect.bottom+ykedu+size.cy)/2-size.cy/2;
if(y+size.cy>m_ctlRect.bottom)
y=m_ctlRect.bottom-size.cy-2;
CRect lrect(center-size.cx/2,m_ctlRect.bottom-size.cy-2,center+size.cx/2,m_ctlRect.bottom-2);
lrect.NormalizeRect();
CString lcstr(m_timeaxis.m_szTitle);
if(m_bDispXTitle)//是否显示x轴名称
dc->TextOut(center-size.cx/2,y,lcstr);//center display
TRACE("x轴名称结束 \n");
dc->SetTextColor(oldtxtcolor);////恢复为字符的原背景色
dc->SetBkColor(oldbkcolor);////恢复为字符的原背景色
dc->SelectObject(old);
TRACE("画坐标x轴结束 \n");
}
//*******************************************************************************************************/
//*******************************************************************************************************/
void clPlot::DrawYAxisGrid(CDC * dc)//画Y轴网格并标Y轴坐标
{
int smallgrids=5;//大栅格间可以有smallgrids个小栅格
double delta;//大栅格间对应的实际值
//调整m_leftaxis.minrange为10的倍数
m_leftaxis.minrange=(double) ( (long)(m_dLeftYSetMinRange/10.0) ) *10.0;
double yGrid = m_leftaxis.minrange;
double di=4.0;//大栅格间对应的刻度时di的倍数 (根据Y轴间代表的实际值调整)
if(m_dLeftYSetMaxRange-m_leftaxis.minrange>500.0)
di=50.0;
else
if(m_dLeftYSetMaxRange-m_leftaxis.minrange<80.0)
di=2.0;
delta=(((long)(m_leftaxis.maxrange-m_leftaxis.minrange+di*m_iYBigGrids-1.0))/(((long)di)*m_iYBigGrids))*((long)di);
m_leftaxis.maxrange=m_leftaxis.minrange+delta*m_iYBigGrids;
m_leftaxis.m_dValuePrPixel = ((double)(m_leftaxis.maxrange- m_leftaxis.minrange) / (double)m_plotRect.Height());
double d10 = delta / 5.0;//小栅格间对应的实际值
// todo: delta switch
long diff = ((long)yGrid)%((long)delta);
//yGrid = yGrid - diff;
diff=0;
CPen *oldpen, pen(PS_DASHDOTDOT, 1, m_gridColor);//横向的主分割线
CPen stick(PS_SOLID,0,RGB(0,0,0));//坐标轴外的短线
CPen mline(PS_SOLID,0,RGB(192,192,192));//横向的辅分割线
//画Grid(栅格)细线
double sy;
int ii;
//for( long sy = (long)((long)(m_leftaxis.minrange) - diff); sy <= m_leftaxis.maxrange; sy+=(long)d10)
//for(sy =m_leftaxis.minrange; sy <= m_leftaxis.maxrange; sy+=d10)
int off=5;//短线的长度
for(ii=0;ii<=m_iYBigGrids*smallgrids;ii++)
{
sy=m_leftaxis.minrange+d10*ii;//d10短线间代表的实际值
off=5;//短线的长度
//if((long)sy%(long)delta == 0)
if((ii%smallgrids)==0)
{
off=15;
}
if(sy >= m_leftaxis.minrange)
{
double yy=(sy-m_leftaxis.minrange)/m_leftaxis.m_dValuePrPixel;
int y=m_plotRect.bottom -(int)yy;
oldpen = dc->SelectObject(&stick);
dc->MoveTo(CPoint(m_plotRect.left,y));
//画短线
dc->LineTo(CPoint(m_plotRect.left-off,y)); //左Y轴栅格坐标外的短线(细线)
if(m_bUseRightYAxis)
{
dc->MoveTo(CPoint(m_plotRect.right,y));
dc->LineTo(CPoint(m_plotRect.right+off,y));//右Y轴栅格坐标外的短线(细线)
}
dc->SelectObject(oldpen);
if(m_bYThinGrid)//横向的细线
{
oldpen = dc->SelectObject(&mline);
dc->MoveTo(CPoint(m_plotRect.left+1,y));
dc->LineTo(CPoint(m_plotRect.right-1,y)); //横向的细线
dc->SelectObject(oldpen);
}
}
}//画Grid(栅格)细线结束
oldpen = dc->SelectObject(&pen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -