深入浅出CChart 每日一课——快乐高四第八课 懵懂的童年,返璞归真之Duilib窗口多区域绘图

这一课是要在Duilib窗口上实现多区域绘图。前面高四第三课里面,已经介绍了CChart在Duilib里面的用法,其基本过程是在Duilib里面创建一个带句柄的窗口,然后把CChartWnd粘在上面。

在计划写本课之前,本以为在Duilib里面多区域绘图是易如反掌的事,因为每个创建的窗口都是独立的,但把CChartWnd粘上后,多个窗口之间还是有点问题。没办法,只好祭出了屠龙刀,解决了这个问题,不过代码就稍微要多一点了。

(笨笨注:上述描述已经过时,新版本CChart完美实现了窗口多次粘贴CChartWnd,因此用高四第三课的方法完全可以实现Duilib窗口多区域绘图,的确是易如反掌。)

基本过程还是和前面高四第三课一样的,但由于不使用CChartWnd了,在创建带句柄的窗口时,需要自己实现这些窗口的窗口函数,并注册窗口类。

下面直接给出源代码(只有一个cpp文件)和窗口布局XML文件,有关细节请参考高四第三课。

首先给出最终效果图。

深入浅出CChart 每日一课——快乐高四第八课 懵懂的童年,返璞归真之Duilib窗口多区域绘图_第1张图片

 

从图可见,我们画了两个图,一个是折线图,一个是饼图。

窗口布局XML文件如下。

 



  
  
    
    
    
      
      
      
      
        
        

可以看到,与前面高四第三课的区别仅仅在于客户区部分,这里我们有两个标签Wnd1和Wnd2,也就是我们的两个绘图窗口。这两个标签需要在代码里面实现。

代码文件LessonA08.cpp全文如下。

#pragma once
#include "DuiLib\UIlib.h"
using namespace DuiLib;

#ifdef _DEBUG
#   ifdef _UNICODE
#       pragma comment(lib, "DuiLib\\DuiLib_ud.lib")
#   else
#       pragma comment(lib, "DuiLib\\DuiLib_d.lib")
#   endif
#else
#   ifdef _UNICODE
#       pragma comment(lib, "DuiLib\\DuiLib_u.lib")
#   else
#       pragma comment(lib, "DuiLib\\DuiLib.lib")
#   endif
#endif

#include "Chart.h"
#if defined(_UNICODE) || defined(UNICODE)
#	pragma comment(lib,"CChartu.lib")
#else
#	pragma comment(lib,"CChart.lib")
#endif
using namespace NsCChart;


class CWndUI: public CControlUI
{
public:
    CWndUI(): m_hWnd(NULL){}
 
    virtual void SetInternVisible(bool bVisible = true)
    {
        __super::SetInternVisible(bVisible);
        ::ShowWindow(m_hWnd, bVisible);
    }
 
    virtual void SetPos(RECT rc)
    {
        __super::SetPos(rc);
        ::SetWindowPos(m_hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOACTIVATE);
    }
 
    BOOL Attach(HWND hWndNew)
    {
        if (! ::IsWindow(hWndNew))
        {
            return FALSE;
        }
 
        m_hWnd = hWndNew;
        return TRUE;
    }
 
    HWND Detach()
    {
        HWND hWnd = m_hWnd;
        m_hWnd = NULL;
        return hWnd;
    }

protected:
    HWND m_hWnd;
};

LRESULT CALLBACK ChartProc1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	static CChart chart;

	switch (message) 
	{
	case WM_CREATE:
		chart.SetType(kTypeXY);
		chart.AddPoint2D(1, 1);
		chart.AddPoint2D(2, 2);
		chart.AddPoint2D(3, 2);
		chart.AddPoint2D(4, 1);
		break;
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_LBUTTONDBLCLK:
	case WM_MOUSEMOVE:
	case WM_CONTEXTMENU:
	case WM_ERASEBKGND:
		chart.Interactive(hWnd, message, wParam, lParam);
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		chart.OnDraw(hWnd);
		EndPaint(hWnd, &ps);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

LRESULT CALLBACK ChartProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	static CChart chart;

	switch (message) 
	{
	case WM_CREATE:
		chart.SetType(kTypePie);
		chart.AddPie(2, _T("刘岩"));
		chart.AddPie(2, _T("瞿颖"));
		chart.AddPie(4, _T("周迅"));
		chart.AddPie(8, _T("王菲"));
		break;
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_LBUTTONDBLCLK:
	case WM_MOUSEMOVE:
	case WM_CONTEXTMENU:
	case WM_ERASEBKGND:
		chart.Interactive(hWnd, message, wParam, lParam);
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		chart.OnDraw(hWnd);
		EndPaint(hWnd, &ps);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

ATOM MyRegisterWnd(TCHAR *szClass, WNDPROC proc)
{	
	WNDCLASS wcls;
	// check to see if class already registered
	if (GetClassInfo(GetModuleHandle(NULL), szClass, &wcls))
	{
		return 1;// name already registered - ok if it was us
	}
	// Use standard "button" control as a template.
	GetClassInfo(NULL, _T("button"), &wcls);
	// set new values
	wcls.style |= CS_DBLCLKS; // Make it to receive double clicks
	wcls.lpfnWndProc = proc;
	wcls.hInstance = GetModuleHandle(NULL);
	wcls.lpszClassName = szClass;
	
	return RegisterClass(&wcls);
}

class CDuiFrameWnd : public WindowImplBase
{
public:
    virtual LPCTSTR    GetWindowClassName() const   {   return _T("DUIMainFrame");  }
    virtual CDuiString GetSkinFile()                {   return _T("duilib.xml");  }
    virtual CDuiString GetSkinFolder()              {   return _T("");  }

	virtual CControlUI* CreateControl(LPCTSTR pstrClassName)
    {
        if (_tcsicmp(pstrClassName, _T("Wnd1")) == 0)
        {
            CWndUI  *pUI  = new CWndUI;            
            HWND    hWnd  = CreateWindow(_T("mychart1"), _T("win32"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 0, 0, 0, m_PaintManager.GetPaintWindow(), NULL, NULL, NULL);
            pUI->Attach(hWnd);  
 
            return pUI;
        }
		else if (_tcsicmp(pstrClassName, _T("Wnd2")) == 0)
        {
            CWndUI  *pUI  = new CWndUI;            
            HWND    hWnd  = CreateWindow(_T("mychart2"), _T("win32"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 0, 0, 0, 0, m_PaintManager.GetPaintWindow(), NULL, NULL, NULL);
            pUI->Attach(hWnd);  
 
            return pUI;
        }
        //return NULL;
		return WindowImplBase::CreateControl(pstrClassName);
    }
};

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    CPaintManagerUI::SetInstance(hInstance);

	MyRegisterWnd(_T("mychart1"), ChartProc1);
	MyRegisterWnd(_T("mychart2"), ChartProc2);

    CDuiFrameWnd duiFrame;
    duiFrame.Create(NULL, _T("DUIWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
    duiFrame.CenterWindow();
    duiFrame.ShowModal();
    return 0;
}

 

基本结构和LessonA03.cpp是一样的,下面是不同点。

 

首先,这里我们编写了两个窗口函数ChartProc1和ChartProc2,分别对于图中的折线图和饼图,这实际就是笨笨CChartWnd的一个简化版。

其次,我们在WinMain函数里面注册了了两个窗口类,一个窗口类的类名为mychart1,窗口函数为ChartProc1,另一个窗口类的类名为mychart2,窗口函数为ChartProc2。为了简化注册,编写了一个MyRegisterWnd函数。

最后,在CreateControl函数里面,对标签Wnd1创建mychart1的窗口,对标签Wnd2创建mychart2的窗口。

本课就结束了。大家注意,请在笨笨的网站下载VS2010编译的版本,VC6的版本在unicode问题上可能和duilib配置不同,有点冲突。

 

你可能感兴趣的:(业余C++爱好者,数据可视化,波形图,曲线图,CChart曲线绘制库)