CChartLegend类用来绘制每一个波形的描述信息,它处于该控件的区域,如下图所示:

CChartLegend类的头文件。

#if !defined(AFX_CHARTLEGEND_H__CD72E5A0_8F52_472A_A611_C588F642080B__INCLUDED_)
#define AFX_CHARTLEGEND_H__CD72E5A0_8F52_472A_A611_C588F642080B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ChartObject.h"
#include "ChartCtrl.h"
#include "ChartString.h"
class CChartSerie;
class CChartLegend : public CChartObject
{
friend CChartCtrl;
public:
void SetFont(int iPointSize, const TChartString& strFaceName);
CChartLegend(CChartCtrl* pParent);
virtual ~CChartLegend();
enum DockSide
{
dsDockRight,
dsDockLeft,
dsDockTop,
dsDockBottom
};
void DockLegend(DockSide dsSide);
void UndockLegend(int iLeftPos, int iTopPos);
void SetTransparent(bool bTransparent);
void SetHorizontalMode(bool bHorizontal);
private:
void Draw(CDC* pDC);
void ClipArea(CRect& rcControl, CDC* pDC);
void UpdatePosition(CDC* pDC, const CRect& rcControl);
TChartString m_strFontName;
int m_iFontSize;
bool m_bDocked; // true if the legend is docked
DockSide m_DockSide;
// If the legend is not docked:
int m_iLeftPos;
int m_iTopPos;
bool m_bIsTransparent;
bool m_bIsHorizontal;
CSize m_BitmapSize;
};
#endif // !defined(AFX_CHARTLEGEND_H__CD72E5A0_8F52_472A_A611_C588F642080B__INCLUDED_)

CChartLegend类的源文件。

#include "stdafx.h"
#include "ChartLegend.h"
#include "ChartSerie.h"
#include "ChartCtrl.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CChartLegend::CChartLegend(CChartCtrl* pParent):CChartObject(pParent)
{
m_ObjectColor = RGB(,,);
m_iFontSize = ;
m_strFontName = _T("Times New Roman");
m_bIsVisible = false;
m_bDocked = true;
m_DockSide = dsDockRight;
m_iLeftPos = m_iTopPos = ;
m_bIsTransparent = false;
m_bIsHorizontal = false;
m_bShadow = true;
m_iShadowDepth = ;
m_BitmapSize.cx = ;
m_BitmapSize.cy = ;
}
CChartLegend::~CChartLegend()
{
}
void CChartLegend::SetFont(int iPointSize, const TChartString& strFaceName)
{
m_iFontSize = iPointSize;
m_strFontName = strFaceName;
m_pParent->RefreshCtrl();
}
void CChartLegend::SetTransparent(bool bTransparent)
{
m_bIsTransparent = bTransparent;
m_pParent->RefreshCtrl();
}
void CChartLegend::SetHorizontalMode(bool bHorizontal)
{
m_bIsHorizontal = bHorizontal;
m_pParent->RefreshCtrl();
}
void CChartLegend::DockLegend(DockSide dsSide)
{
m_bDocked = true;
m_DockSide = dsSide;
m_pParent->RefreshCtrl();
}
void CChartLegend::UndockLegend(int iLeftPos, int iTopPos)
{
m_bDocked = false;
m_iLeftPos = iLeftPos;
m_iTopPos = iTopPos;
m_pParent->RefreshCtrl();
}
void CChartLegend::ClipArea(CRect& rcControl, CDC* pDC)
{
UpdatePosition(pDC,rcControl);
if (m_ObjectRect.IsRectEmpty())
return;
if (m_bDocked)
{
switch (m_DockSide)
{
case dsDockRight:
rcControl.right = m_ObjectRect.left + ;
break;
case dsDockLeft:
rcControl.left = m_ObjectRect.right - ;
break;
case dsDockTop:
rcControl.top = m_ObjectRect.bottom + ;
break;
case dsDockBottom:
rcControl.bottom = m_ObjectRect.top - ;
break;
}
}
}
void CChartLegend::UpdatePosition(CDC* pDC, const CRect& rcControl)
{
CRect NewPosition;
NewPosition.SetRectEmpty();
if (!m_bIsVisible)
{
SetRect(NewPosition);
return;
}
CFont* pOldFont;
CFont NewFont;
NewFont.CreatePointFont(m_iFontSize,m_strFontName.c_str(),pDC);
pOldFont = pDC->SelectObject(&NewFont);
int Height = ;
int Width = ;
int MaxText = ;
CSize TextSize;
size_t SeriesCount = m_pParent->GetSeriesCount();
int Drawn = ;
for (size_t i=;i<SeriesCount;i++)
{
CChartSerie* pSerie = m_pParent->GetSerie(i);
if ( (pSerie->GetName() == _T("")) || !pSerie->IsVisible() )
continue;
Drawn++;
TextSize = pDC->GetTextExtent(pSerie->GetName().c_str());
if (!m_bIsHorizontal)
{
if (TextSize.cy>m_BitmapSize.cy)
Height += TextSize.cy + ;
else
Height += m_BitmapSize.cy + ;
if (TextSize.cx > MaxText)
MaxText = TextSize.cx;
}
else
{
Width += TextSize.cx + + m_BitmapSize.cx + ;
if (TextSize.cy > MaxText)
MaxText = TextSize.cy;
}
}
pDC->SelectObject(pOldFont);
DeleteObject(NewFont);
if (!Drawn)
{
SetRect(NewPosition);
return;
}
if (!m_bIsHorizontal)
{
Width += MaxText + m_BitmapSize.cx + ;
Height += + - ; // Top and bottom margins. -2 because space counted once too much
}
else
{
Width += + - ;
Height = + max(m_BitmapSize.cy,MaxText) + ;
} if (!m_bDocked)
{
NewPosition.top = m_iTopPos;
NewPosition.left = m_iLeftPos;
NewPosition.bottom = m_iTopPos + Height + ;
NewPosition.right = m_iLeftPos + Width;
}
else
{
switch (m_DockSide)
{
case dsDockRight:
NewPosition.top = ((rcControl.bottom-rcControl.top)/) - ((Height + )/);
NewPosition.left = rcControl.right - (Width + );
NewPosition.bottom = NewPosition.top + Height;
NewPosition.right = NewPosition.left + Width;
break;
case dsDockLeft:
NewPosition.top = ((rcControl.bottom-rcControl.top)/) - ((Height + )/);
NewPosition.left = rcControl.left + ;
NewPosition.bottom = NewPosition.top + Height;
NewPosition.right = NewPosition.left + Width;
break;
case dsDockTop:
NewPosition.top = rcControl.top + ; //((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2);
NewPosition.left = ((rcControl.right-rcControl.left)/) - (Width/); // rcControl.left + 3;
NewPosition.bottom = NewPosition.top + Height;
NewPosition.right = NewPosition.left + Width;
break;
case dsDockBottom:
NewPosition.top = rcControl.bottom - (Height + ); //((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2);
NewPosition.left = ((rcControl.right-rcControl.left)/) - (Width/); // rcControl.left + 3;
NewPosition.bottom = NewPosition.top + Height;
NewPosition.right = NewPosition.left + Width;
break;
}
}
SetRect(NewPosition);
}
void CChartLegend::Draw(CDC *pDC)
{
if (!pDC->GetSafeHdc())
return;
if (!m_bIsVisible)
return;
if (m_ObjectRect.IsRectEmpty())
return;
CPen SolidPen(PS_SOLID,,RGB(,,));
CPen* pOldPen;
CFont* pOldFont;
CFont NewFont;
NewFont.CreatePointFont(m_iFontSize,m_strFontName.c_str(),pDC);
// Draw the shadow
if (m_bShadow)
{
CRect ShadowRect = m_ObjectRect;
ShadowRect.OffsetRect(m_iShadowDepth,m_iShadowDepth);
CBrush BrushShadow;
BrushShadow.CreateSolidBrush(m_ShadowColor) ;
pDC->FillRect(ShadowRect,&BrushShadow);
}
if (!m_bIsTransparent)
{
//Fill back color
CBrush BrushBack;
BrushBack.CreateSolidBrush(m_ObjectColor) ;
pDC->FillRect(m_ObjectRect,&BrushBack);
}
pOldFont = pDC->SelectObject(&NewFont);
pOldPen = pDC->SelectObject(&SolidPen);
//Draw rectangle:
pDC->MoveTo(m_ObjectRect.left,m_ObjectRect.top);
pDC->LineTo(m_ObjectRect.right,m_ObjectRect.top);
pDC->LineTo(m_ObjectRect.right,m_ObjectRect.bottom);
pDC->LineTo(m_ObjectRect.left,m_ObjectRect.bottom);
pDC->LineTo(m_ObjectRect.left,m_ObjectRect.top);
int iPrevMode = pDC->SetBkMode(TRANSPARENT);
CRect rectBitmap(m_ObjectRect.left+,m_ObjectRect.top+,
m_ObjectRect.left++m_BitmapSize.cx,
m_ObjectRect.top++m_BitmapSize.cy);
int SeriesCount = m_pParent->GetSeriesCount();
for (int i=;i<SeriesCount;i++)
{
CChartSerie* pSerie = m_pParent->GetSerie(i);
if ( (pSerie->GetName() == _T("")) || !pSerie->IsVisible() )
continue;
int MaxHeight = ;
CSize TextSize = pDC->GetTextExtent(pSerie->GetName().c_str());
if (TextSize.cy > m_BitmapSize.cy)
{
pDC->ExtTextOut(rectBitmap.right+,rectBitmap.top,ETO_CLIPPED,NULL,pSerie->GetName().c_str(),NULL);
CRect rectTemp(rectBitmap);
int YOffset = TextSize.cy/ - rectBitmap.Height()/;
rectTemp.OffsetRect(,YOffset);
pSerie->DrawLegend(pDC,rectTemp);
MaxHeight = TextSize.cy;
}
else
{
int YOffset = rectBitmap.CenterPoint().y - TextSize.cy/;
pDC->ExtTextOut(rectBitmap.right+,YOffset,ETO_CLIPPED,NULL,pSerie->GetName().c_str(),NULL);
MaxHeight = m_BitmapSize.cy;
pSerie->DrawLegend(pDC,rectBitmap);
} if (!m_bIsHorizontal)
rectBitmap.OffsetRect(,MaxHeight+);
else
rectBitmap.OffsetRect(m_BitmapSize.cx++TextSize.cx+,);
}
pDC->SetBkMode(iPrevMode);
pDC->SelectObject(pOldFont);
DeleteObject(NewFont);
pDC->SelectObject(pOldPen);
DeleteObject(SolidPen);
}

ClipArea函数的作用是将ChartLegend与波形绘制区域分离开,其中rcControl表示的是绘制波形的区域,m_ObjectRect表示的是绘制ChartLegend的区域。UpdatePosition函数用来在当前绘制区域里面计算ChartLegend所处的位置并记录下该位置。Draw函数用来绘制ChartLegend控件,调用CChartSeries类的DrawLegend用来绘制ChartLegend里面的波形图像信息。

ChartCtrl源码剖析之——CChartLegend类的更多相关文章

  1. ChartCtrl源码剖析之——CChartObject类

    首先,做一些简单的铺垫,目前针对ChartCtrl源码的剖析只针对V.15版本.名义上说是剖析,倒不如说是记录下自己针对该控件的理解,非常感谢Cedric Moonen大神,一切的功劳与掌声都该赠予给 ...

  2. ChartCtrl源码剖析之——CChartScrollBar类

    CChartScrollBar类用来针对每个轴的数据进行滚动,将那些不在当前区域内的数据通过滚动展示出来. CChartScrollBar类的头文件. #pragma once class CChar ...

  3. ChartCtrl源码剖析之——CChartAxis类

    CChartAxis类用来绘制波形控件的坐标轴,这个源码相对较复杂,当初阅读的时候耗费了不少精力来理解源码中的一些实现细节. CChartAxis类的头文件. #if !defined(AFX_CHA ...

  4. ChartCtrl源码剖析之——CChartTitle类

    CChartTitle类顾名思义,该类用来绘制波形控件的标题,它处于该控件的区域,如下图所示: CChartTitle类的头文件. #if !defined(AFX_CHARTTITLE_H__499 ...

  5. ChartCtrl源码剖析之——CChartAxisLabel类

    CChartAxisLabel类用来绘制轴标签,上.下.左.右都可以根据实际需要设置对应的轴标签.它处于该控件的区域,如下图所示: CChartAxisLabel类的头文件. #if !defined ...

  6. ChartCtrl源码剖析之——CChartGrid类

    CChartGrid类用来绘制波形区域中的表格,当绘制波形时波形就显示在这些表格上面.它处于该控件的区域,如下图所示: CChartGrid类的头文件. #if !defined(AFX_CHARTG ...

  7. PART(Persistent Adaptive Radix Tree)的Java实现源码剖析

    论文地址 Adaptive Radix Tree: https://db.in.tum.de/~leis/papers/ART.pdf Persistent Adaptive Radix Tree: ...

  8. 老李推荐:第6章3节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-命令翻译类

    老李推荐:第6章3节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-命令翻译类   每个来自网络的字串命令都需要进行解析执行,只是有些是在解析的过程中直接执行 ...

  9. WorldWind源码剖析系列:影像存储类ImageStore、Nlt影像存储类NltImageStore和WMS影像存储类WmsImageStore

    影像存储类ImageStore 影像存储类ImageStore提供了计算本地影像路径和远程影像影像URL访问的各种接口,是WmsImageStore类和NltImageStore类的基类.当划分完层次 ...

随机推荐

  1. ubuntu使用git时,终端不显示git分支。

    1:问题描述: 在Windows环境下习惯使用git bash操作git分支,最近学习linux环境,发现linux环境终端不显示git分支,相关现象如下:      期望效果是: 我的linux环境 ...

  2. Hibernate 批处理(batch inserts, updates and deletes)

    总结:hibernate在进行批量处理不给力的主要原因就是Session中存在缓存,而hibernate的机制就是通过session中的一级缓存去同步数据库,所以当进行批量处理时,缓存中保存的数据量很 ...

  3. 使用WaveOut API播放WAV音频文件(解决卡顿)

    虽然waveout已经过时,但是其api简单,有些时候也还是需要用到. 其实还是自己上msdn查阅相应api最靠谱,waveout也有提供暂停.设置音量等接口的,这里给个链接,需要的可以自己查找: h ...

  4. sequence(bzoj 1367)

    Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15 ...

  5. hdu 4046 Panda [线段树]

    Panda Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  6. transient 关键字

    java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持.换句话来说就是,用transient关键字标记的成员变量不参与序列化过程.   作用 Jav ...

  7. poj3532求生成树中最大权与最小权只差最小的生成树+hoj1598俩个点之间的最大权与最小权只差最小的路经。

    该题是最小生成树问题变通活用,表示自己开始没有想到该算法:先将所有边按权重排序,然后枚举最小边,求最小生成树(一个简单图的最小生成树的最大权是所有生成树中最大权最小的,这个容易理解,所以每次取最小边, ...

  8. SQL SERVER 2012 第四章 连接 JOIN の OUTER JOIN,完全连接FULL JOIN,交叉连接CROSS JOIN

    SELECT <SELECT LIST> FROM <the table you want to be the "LEFT" table> <LEFT ...

  9. mybatis批量更新两种方式:1.修改值全部一样 2.修改每条记录值不一样

    Mybatis批量更新数据 mybatis批量更新两种方式:1.修改值全部一样 2.修改每条记录值不一样 mybatis批量更新两种方式:1.修改值全部一样 2.修改每条记录值不一样 mybatis批 ...

  10. 多平台密码绕过及提权工具Kon-Boot的使用与防范

    在单用户的机器上密码可能没那么重要,但是一旦有多个用户可以使用这台机器,密码就显得十分必要了(比如有儿童账户的电脑).所以说为你的电脑增设一条防线的最常用,最简单的方法就是用密码将你的电脑保护起来,但 ...