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

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

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

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

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

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

首先给出最终效果图。

 

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

窗口布局XML文件如下。

 

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4">
  <!-- 窗口的初始尺寸(宽800,高600)、窗口的最小尺寸(宽600,高400)、标题栏拖拽区域(高32)、可拖拽边框大小(这里添加sizebox后就可以拖拽边框调整大小了) -->
  <VerticalLayout bkcolor="#FFF0F0F0" bkcolor2="#FFAAAAA0">
    <!-- 整个窗口的背景色 -->
    <!-- 标题栏区 -->
    <HorizontalLayout height="32" bkcolor="#FFE6E6DC" bkcolor2="#FFAAAAA0">
      <!-- 标题栏背景色 bkcolor、bkcolor2、bkcolor3分别是渐变色的三个值-->
      <VerticalLayout />
      <!-- 占空位,占据左边所有的空位-->
      <VerticalLayout width="77">
        <!-- 右边三个控件所占的宽度-->
        <Button name="minbtn"   tooltip="最小化" float="true" pos="0,5,22,24"  width="23" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' " pushedimage=" file='SysBtn\MinFocus.bmp' "/>
        <Button name="maxbtn"   tooltip="最大化" float="true" pos="22,5,44,24" width="23" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' " pushedimage=" file='SysBtn\MaxFocus.bmp' " />
        <Button name="restorebtn" visible="false" tooltip="还原" float="true" pos="22,5,44,24" width="23" normalimage=" file='SysBtn\StoreNormal.bmp' " hotimage=" file='SysBtn\StoreFocus.bmp' " pushedimage=" file='SysBtn\StoreFocus.bmp' " />
        <Button name="closebtn" tooltip="关闭"   float="true" pos="44,5,74,24" width="28" normalimage=" file='SysBtn\CloseNormal.bmp' " hotimage=" file='SysBtn\CloseFocus.bmp' " pushedimage=" file='SysBtn\CloseFocus.bmp' "/>
      </VerticalLayout>
    </HorizontalLayout>

    <!-- 客户区 -->
    <HorizontalLayout>
      <!--我们的CChart窗口-->
      <Wnd1 float="true" pos="10,10,0,0" width="350" height="350" />
      <Wnd2 float="true" pos="380,10,0,0" width="350" height="350" />
    </HorizontalLayout>
  </VerticalLayout>
</Window>

可以看到,与前面高四第三课的区别仅仅在于客户区部分,这里我们有两个标签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配置不同,有点冲突。

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值