TeeChart控件是功能强大,可以绘制各种图像,因此在MFC中具有较多的应用。关于使用TeeChart绘制二维图像,现在网上可以搜到很多的教程;对于三维绘图,网上也有一些教程,但是对新手来说,由于某些地方不甚详细,总是会出现一些意料不到的问题。这里计划绘制一个三维螺旋线,详细地指出每一步应该怎么去操作。
在此之前,应该保证计算机上注册过TeeChart的ActiveX控件,同时也有TeeChart的程序集(包含着TeeChart所需要的各种类)。如果只使用TeeChart activeX控件但没有程序集,就会遇到诸如“找不到函数ADDXYZ()”之类的错误。
首先先新建一个基于对话框的MFC程序,命名为Chart,对话框的标题就叫做“三维绘图”好了。建立好之后如下图所示。
随后删除掉不需要的static控件,然后再对话框上右键单击,选择“插入ActiveX控件”,在对话框中选择TeeChart Pro ActiveX Control,如下图所示。
这个控件就是用来绘图的TeeChart控件了。随后调整控件的大小和位置,调好之后双击控件,在弹出的对话框中选择chart->series,单击右边的Add按钮(以上的操作实际上是为这个teechart控件添加一个图像)。在图像类型中选择point3D,也就是三维曲线,如下图。在下图中我们也能看到,TeeChart所提供的图像类型非常多,二维的曲线图、饼图、误差棒图等,三维的曲线、曲面图一应俱全,基本上包含了我们所需要用到的一切功能。
把TeeChart程序集(里面包含各种.h文件与.cpp文件)放在项目目录下。我之前就是因为没有使用这个程序集,所以没有办法绘制三维曲线。
在解决方案中右击Chart,添加项->现有项,在项目中添加需要的文件。本次三维绘图需要用到的包括tchart,series,point3dseries对应的.h文件及.cpp文件,里面分别定义了CTChart,CSeries,CPoint3DSeries三个类。一般来说,TeeChart对应的关联变量需要定义成CTChart类型,而TeeChart上面的图像作为CSeries类型处理,CPoint3DSeries是三维曲线绘图需要用的类型。另外多说一句,在程序集中我们可以看到有各式各样的文件,里面具有相应的类(比如涉及到坐标轴的Axes类,涉及图属性的Aspect类,可以按照需要去引入、使用。我们这里只做一个简单的实例,所以不用那么多。我们导入的文件如下图所示。
这一步算是和很多TeeChart二维绘图教程不一样的地方,而很多介绍三维绘图的相关文章中也没有提及(之前一直没有办法成功绘制三维图,就是卡在这里)。当然,我不知道我的操作算不算是官子,但是至少是可以实现的。
在这里,首先要在ChartDlg.h这个对话框类头文件中手动添加一个TeeChart的关联变量,类型为CTChart类型,也就是
private:
CTChart m_Chart;//TEECHART对应的控件
同时别忘了添加CTChart类的头文件引用(在tchart.h这个文件中)
#include"TeeChart\tchart.h"
最终得到的对话框类头文件应该是这样的(其他语句都是自己生成的,没有做修改)
// ChartDlg.h : 头文件
//
#pragma once
#include"TeeChart\tchart.h"
// CChartDlg 对话框
class CChartDlg : public CDialogEx
{
// 构造
public:
CChartDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_CHART_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
//控件
private:
CTChart m_Chart;//TEECHART对应的控件
};
随后创建m_Chart和TeeChart控件的数据绑定。在对话框类的实现文件中找到DoDataExchange函数,添加语句
DDX_Control(pDX, IDC_TCHART1, m_Chart);//控件的绑定
这里IDC_TCHART1是我们所用的TeeChart控件的ID。
我们尝试绘制如下曲线:
$$\left\{\begin{matrix} x=\cos \left( 2 \pi t/100 \right) \\ y= \sin \left( 2 \pi t/100 \right) \\ z= t/10 \end{matrix}\right.$$
该曲线表示以t为参数的螺旋线。在OnInitDialog()函数中添加如下程序段:
const double pi = 3.14;//定义pi
for (int i = 0; i<300; i++)
m_Chart.Series(0).GetAsPoint3D().AddXYZ(cos(2*pi*i/100), sin(2*pi*i/100), i/10, NULL, RGB(0, 0, 255));//前三个是点坐标,最后一个参数时点的颜色
其他的地方不需要做修改。不过同时记得添加相应的头文件
#include "TeeChart\tchart.h"
#include"TeeChart\series.h"
#include"TeeChart\point3dseries.h"
对话框类实现文件为:
// ChartDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "Chart.h"
#include "ChartDlg.h"
#include "afxdialogex.h"
#include "TeeChart\tchart.h"
#include"TeeChart\series.h"
#include"TeeChart\point3dseries.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CChartDlg 对话框
CChartDlg::CChartDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_CHART_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CChartDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TCHART1, m_Chart);//控件的绑定
}
BEGIN_MESSAGE_MAP(CChartDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()
// CChartDlg 消息处理程序
BOOL CChartDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
const double pi = 3.14;//定义pi
for (int i = 0; i<300; i++)
m_Chart.Series(0).GetAsPoint3D().AddXYZ(cos(2*pi*i/100), sin(2*pi*i/100), i/10, NULL, RGB(0, 0, 255));//前三个是点坐标,最后一个参数时点的颜色
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CChartDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CChartDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CChartDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
运行后,可以得到如图所示的螺旋线
这样一个三维曲线图像就绘制完成了。接下来可以对图进行设置(坐标轴、标题、图例、标记点的类型等),使得绘图效果看起来更加漂亮一些。设置的方法有两种,一种是静态的,你可以在控件上直接双击,然后进行操作;另一种是动态的,就需要你添加上TeeChart程序集里面相应的类,然后用后台代码去修改。比如说我加一个标题,去掉图例,再稍微做一些小修小补,就可以得到下图所示的最终结果。
以上就是我对TeeChart三维曲线绘图的一些粗浅的理解。欢迎大家一起交流讨论。