Click here to Skip to main content
15,896,428 members
Articles / Desktop Programming / WTL

A fast and lightweight cell control

Rate me:
Please Sign up or sign in to vote.
4.42/5 (31 votes)
11 Mar 2008CPOL1 min read 91K   4.5K   81  
A fast and lightweight cell control for displaying tabular data. The cell is a custom control derived from ATL::CWindow.
// MyCell - version 1.0
// Written by Yanxueming <yanxm2003@hotmail.com>
// Copyright (C) 2006-2008
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.

//Yanxm 2007��12��25�� 10:14:43
#include "stdafx.h"
#include "../include/Workbook.h"
#include "../include/DefaultSymbols.h"
#include "../include/EditImp.h"
namespace mycell{

	BEGIN_MSG_MAP_CPP(Workbook)
		MESSAGE_HANDLER(WM_CREATE,OnCreate)
		MESSAGE_HANDLER(WM_POSTCREATE,OnPostCreate)
		MESSAGE_HANDLER(WM_SIZE,OnSize)
		NOTIFY_CODE_HANDLER(TCN_SELCHANGE,OnTabItemChange)
		MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
	//MESSAGE_HANDLER(WM_ACTIVATEAPP,OnActivateApp)
	//ALT_MSG_MAP(1) // Scroll
	//ALT_MSG_MAP(2)
		if(pCurSheet_){
	//		MESSAGE_HANDLER(WM_GETDLGCODE,eventImpl_.OnGetDlgCode)
	//		MESSAGE_HANDLER(WM_KILLFOCUS,eventImpl_.OnKillFocus)
			MESSAGE_HANDLER(WM_VSCROLL,pCurSheet_->OnVScroll)
			MESSAGE_HANDLER(WM_HSCROLL,pCurSheet_->OnHScroll)
			MESSAGE_HANDLER(WM_MOUSEWHEEL, pCurSheet_->OnMouseWheel)
	//		MESSAGE_HANDLER(WM_KEYDOWN,eventImpl_.OnKeyEvent)
	//		MESSAGE_HANDLER(WM_CHAR,eventImpl_.OnKeyEvent)
	//		MESSAGE_HANDLER(WM_IME_COMPOSITION,eventImpl_.OnImeComposition)
	//		MESSAGE_HANDLER(WM_MOUSEMOVE, eventImpl_.OnMouseEvent)
	//		MESSAGE_HANDLER(WM_LBUTTONDBLCLK, eventImpl_.OnMouseEvent)
	//		MESSAGE_HANDLER(WM_LBUTTONDOWN, eventImpl_.OnMouseEvent)
	//		MESSAGE_HANDLER(WM_LBUTTONUP, eventImpl_.OnMouseEvent)
	//		MESSAGE_HANDLER(WM_RBUTTONDOWN, eventImpl_.OnMouseEvent)
	//		MESSAGE_HANDLER(WM_RBUTTONUP, eventImpl_.OnMouseEvent)
	//		MESSAGE_HANDLER(WM_THEMECHANGED, eventImpl_.OnThemeChanged)
	//		MESSAGE_HANDLER(WM_PAINT,eventImpl_.OnPaint)
		}
        //if (uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP )
        //    CHAIN_MSG_MAP_MEMBER(wndTabHScroll_);

	ALT_MSG_MAP(1)//Scroll bar
	END_MSG_MAP()

	TCHAR Workbook::tooltipText_[MAX_CELLTEXT];

	Workbook::Workbook():hWndListener_(NULL),wndSheet_(cellTypeFactory_)
		,bits_(B_SHOWHSCROLLBAR|B_SHOWVSCROLLBAR)
		//,bShowHScrollBar_(TRUE),bShowVScrollBar_(TRUE)
		,selectionMode_(ESM_SINGLESELECTION)
	{
		Worksheet::tooltipCell_.set(-100,-100);
		pCurSheet_=Worksheet_AddNewSheet();
		pCurSheet_->SetName(_T("Sheet1"));
		//render_.Init(pCurSheet_);
		InitTypeFactory();
	}

	Workbook::~Workbook()
	{
		for(vector<Worksheet*>::iterator it=vecWorksheet_.begin();it!=vecWorksheet_.end();++it)
		{
			delete *it;
		}
	}
	void Workbook::Clear()
	{
		pCurSheet_=NULL;
		for(vector<Worksheet*>::iterator it=vecWorksheet_.begin();it!=vecWorksheet_.end();++it){
			(*it)->clear();
			(*it)->m_hWnd=NULL;
		}
		styleStore_.Clear();
	}
	void Workbook::InitTypeFactory()
	{
		using namespace mycell;
		using namespace symbol;
		//const BOOL bNoHeaderSymbol=!cellTypeFactory_.GetSymbol(ECT_ROWHEADER);
		//const BOOL bNoColorSymbol=!cellTypeFactory_.GetSymbol(ECT_COLOR);
		//const BOOL bNoCheckSymbol=!cellTypeFactory_.GetSymbol(ECT_CHECKBOX);
		{
			CComPtr<ICellSymbol> pSymbol;
			CComObject<TextSymbol>* ps;
			CComObject<TextSymbol>::CreateInstance(&ps);
			ps->QueryInterface(IID_IUnknown,(void**)&pSymbol);

			CComPtr<ICellSymbol> pFillSymbol;
			CComObject<SimpleFillSymbol>* pfs;
			CComObject<SimpleFillSymbol>::CreateInstance(&pfs);
			pfs->QueryInterface(IID_IUnknown,(void**)&pFillSymbol);

			for(size_t i=0;i<cellTypeFactory_.size();++i){
				const ECellType ct=(ECellType)i;
				if(!cellTypeFactory_.GetSymbol(ct))
					cellTypeFactory_.SetSymbol(ct,pSymbol);
				if(!cellTypeFactory_.GetFillSymbol(ct))
					cellTypeFactory_.SetFillSymbol(ct,pFillSymbol);
			}
		}

		//if(bNoCheckSymbol)
		{
			CComPtr<ICellSymbol> pSymbol;
			CComObject<ThemeCheckBoxSymbol>* ps;
			CComObject<ThemeCheckBoxSymbol>::CreateInstance(&ps);
			//ps->OpenThemeData(wndSheet_.m_hWnd);
			ps->QueryInterface(IID_IUnknown,(void**)&pSymbol);
			cellTypeFactory_.SetSymbol(ECT_CHECKBOX,pSymbol);
		}
		//if(bNoHeaderSymbol)
		{
			CComPtr<ICellSymbol> pSymbol;
			CComObject<HeaderSymbol>* ps;
			CComObject<HeaderSymbol>::CreateInstance(&ps);
			ps->QueryInterface(IID_IUnknown,(void**)&pSymbol);
			cellTypeFactory_.SetSymbol(ECT_ROWHEADER,pSymbol);
			cellTypeFactory_.SetSymbol(ECT_COLHEADER,pSymbol);
			cellTypeFactory_.SetSymbol(ECT_HEADERCORNER,pSymbol);
		}
		//if(bNoColorSymbol)
		{
			CComPtr<ICellSymbol> pSymbol;
			CComObject<ColorSymbol>* ps;
			CComObject<ColorSymbol>::CreateInstance(&ps);
			ps->QueryInterface(IID_IUnknown,(void**)&pSymbol);
			cellTypeFactory_.SetSymbol(ECT_COLOR,pSymbol);
		}

		CComPtr<ICellEditor> pEditor;
		{
			CComObject<editor::TextEditor>* pEdit;
			CComObject<editor::TextEditor>::CreateInstance(&pEdit);
			pEdit->Init(this);
			pEdit->QueryInterface(IID_IUnknown,(void**)&pEditor);
			ECellType ect[]={
				ECT_TEXT,
				ECT_UINT,
				ECT_INT,
				ECT_DOUBLE,
				ECT_UDOUBLE,
				ECT_DEGREE
			};
			for(size_t i=0;i<sizeof(ect)/sizeof(ect[0]);++i){
				if(!cellTypeFactory_.GetEditor(ect[i]))
					cellTypeFactory_.SetEditor(ect[i],pEditor);
			}
		}

		{
			pEditor.Release();
			CComObject<editor::CheckBoxEditor>* pEdit;
			CComObject<editor::CheckBoxEditor>::CreateInstance(&pEdit);
			pEdit->Init(this);
			pEdit->QueryInterface(IID_IUnknown,(void**)&pEditor);
			cellTypeFactory_.SetEditor(ECT_CHECKBOX,pEditor);
		}
	}
	int Workbook::Worksheet_FindPosByName(LPCTSTR lpszSheetName)const
	{
		CString strSheetName(lpszSheetName);
		strSheetName.MakeLower();
		for(vector<Worksheet*>::const_iterator it=vecWorksheet_.begin();it!=vecWorksheet_.end();++it)
		{
			CString name=(*it)->GetName();
			name.MakeLower();
			if(strSheetName==name)
				return int(it-vecWorksheet_.begin());
		}
		return -1;
	}
	Worksheet* Workbook::Worksheet_FindByName(LPCTSTR lpszSheetName)const
	{
		CString strSheetName(lpszSheetName);
		strSheetName.MakeLower();
		for(vector<Worksheet*>::const_iterator it=vecWorksheet_.begin();it!=vecWorksheet_.end();++it)
		{
			CString name=(*it)->GetName();
			name.MakeLower();
			if(strSheetName==name)
				return (*it);
		}
		return NULL;
	}
	Worksheet* Workbook::Worksheet_AddNewSheet()
	{
		Worksheet* pSheet=new Worksheet(this);
		if(m_hWnd){
			TCHAR buf[32];
			wndTabHScroll_.GetFlatTabCtrl()->InsertItem((int)vecWorksheet_.size(),GetNewSheetName(buf));
			pSheet->SetName(buf);
			pSheet->Scroll_SetScrollBars(wndTabHScroll_.m_wndScroll/*wndHScroll_*/,wndVScroll_);
		}
		vecWorksheet_.push_back(pSheet);
		return pSheet;
	}

	void Workbook::Worksheet_DeleteSheet(size_t idx)
	{
		_ASSERT(idx<vecWorksheet_.size());
		Worksheet* pSheet=vecWorksheet_[idx];
		if(pCurSheet_==pSheet){
			if(idx<vecWorksheet_.size()-1)
				pCurSheet_=vecWorksheet_[++idx];
			else if(idx>0)
				pCurSheet_=vecWorksheet_[--idx];
			else
				pCurSheet_=NULL;
		}
		delete pSheet;
		wndTabHScroll_.GetFlatTabCtrl()->DeleteItem((int)idx);
		vecWorksheet_.erase(vecWorksheet_.begin()+idx);
	}
	Worksheet* Workbook::Worksheet_SetActiveSheet(size_t idx)
	{
		_ASSERT(idx<vecWorksheet_.size());
		if(pCurSheet_)
			pCurSheet_->m_hWnd=NULL;
		pCurSheet_=vecWorksheet_[idx];
		wndSheet_.SetWorksheet(pCurSheet_);
		wndTabHScroll_.GetFlatTabCtrl()->SetCurSel((int)idx);
		return pCurSheet_;
	}


	BOOL Workbook::SubclassWindow(HWND hWnd)
	{
		BOOL bRet=baseWnd::SubclassWindow(hWnd);
		CreateChildren();
//#pragma warning( disable : 4312 )
//		cf_.standardCursor=(HCURSOR)SetClassLong(hWnd,GCL_HCURSOR,NULL);
//		if(!cf_.standardCursor){
//			cf_.standardCursor=LoadCursor(NULL,IDC_ARROW);
//		}
//#pragma warning( default : 4312 )
//		//pCurSheet_->m_hWnd=wndSheet_.m_hWnd;
//		CreateTT();
		return bRet;
	}
	// Sends a message to the listener in the form of a WM_NOTIFY message with
	// a NM_SHEETVIEW structure attached
	HRESULT Workbook::SendNotifyMessageToListener(int nRow, int nCol, int nNotifyCode,LPARAM lParam,BOOL* pbHandled) const
	{
		if(!m_hWnd)
			return S_FALSE;
		HWND hWndListener=get_listener();
		if(!hWndListener)
			hWndListener=GetParent();
		NM_SHEETVIEW nmgv;
		nmgv.hr				= S_OK;
		nmgv.bHandled	=FALSE;
		if (hWndListener && ::IsWindow(hWndListener) && IsWindow()){
			nmgv.row			= nRow;
			nmgv.col			= nCol;
			nmgv.lParam		= lParam;	
			nmgv.hdr.hwndFrom	= m_hWnd;
			nmgv.hdr.idFrom	= GetDlgCtrlID();
			nmgv.hdr.code	= nNotifyCode;
			::SendMessage(hWndListener,WM_NOTIFY,nmgv.hdr.idFrom, (LPARAM)&nmgv);
		}
		if(pbHandled)
			*pbHandled=nmgv.bHandled;
		return nmgv.hr;
	}
	void Workbook::CreateChildren()
	{
		//wndHScroll_.Create(this, 1, m_hWnd, CWindow::rcDefault, NULL, WS_CHILD /*| WS_VISIBLE*/);
		//wndHScroll_.SetFont((HFONT)::SendMessage(GetParent(), WM_GETFONT, 0, 0));
		wndVScroll_.Create(this, 1, m_hWnd, CWindow::rcDefault, NULL, WS_CHILD /*| WS_VISIBLE*/ |SBS_VERT);
        wndTabHScroll_.Create(m_hWnd);//*this, CWindow::rcDefault/*rcPos*/, NULL, WS_CHILD|WS_CLIPCHILDREN | WS_VISIBLE);
		wndTabHScroll_.SetFont((HFONT)::SendMessage(GetParent(), WM_GETFONT, 0, 0));
        //wndTabHScroll_.GetFlatTabCtrl()->InsertItem(0, _T("Build"));
        //wndTabHScroll_.GetFlatTabCtrl()->InsertItem(1, _T("Debug"));
        //wndTabHScroll_.GetFlatTabCtrl()->InsertItem(2, _T("Find in File 1"));

		wndVScroll_.SetFont((HFONT)::SendMessage(GetParent(), WM_GETFONT, 0, 0));
		wndBottomRightCorner_.Create(m_hWnd, CWindow::rcDefault, NULL, WS_CHILD|WS_VISIBLE|WS_DISABLED|SBS_SIZEBOX/*|SBS_SIZEBOXBOTTOMRIGHTALIGN*/);

		//for(vector<Worksheet*>::iterator it=vecWorksheet_.begin();it!=vecWorksheet_.end();++it){
		for(size_t i=0;i<vecWorksheet_.size();++i){
			Worksheet* pSheet=vecWorksheet_[i];
			const LPCTSTR lpstr=pSheet->GetName();
			wndTabHScroll_.GetFlatTabCtrl()->InsertItem((int)i,lpstr);
			pSheet->Scroll_SetScrollBars(wndTabHScroll_.m_wndScroll,wndVScroll_);
		}

		wndSheet_.Create(m_hWnd,CWindow::rcDefault,NULL,WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
		wndSheet_.SetWorksheet(pCurSheet_);
		PostMessage(WM_POSTCREATE);

		cellTypeFactory_.OnThemeChanged(wndSheet_.m_hWnd);
	}
	void Workbook::UpdateControlLayout(WORD cx, WORD cy, bool bMouseMove/* = false*/)
	{
		if(cx<=0 || cy<=0) return;
		const BOOL bShowHScrollBar=IsShowHScrollBar();
		const int cyHScroll=bShowHScrollBar?::GetSystemMetrics(SM_CYHSCROLL):0;
		const int cxVScroll=IsShowVScrollBar()?::GetSystemMetrics(SM_CXVSCROLL):0;
		const int cxSheet=cx-cxVScroll;
		const int cySheet=cy-cyHScroll;
		//int const xHScroll=0;
		int const yHScroll=cy-cyHScroll;
		int const xVScroll=cx-cxVScroll;
		HDWP hdwp=::BeginDeferWindowPos(4);
		::DeferWindowPos(hdwp,wndTabHScroll_,NULL,0,yHScroll,cx-cxVScroll,cyHScroll,SWP_NOZORDER|SWP_SHOWWINDOW);
		::DeferWindowPos(hdwp,wndVScroll_,NULL,xVScroll,0,cxVScroll,yHScroll,SWP_NOZORDER|SWP_SHOWWINDOW);
		::DeferWindowPos(hdwp,wndBottomRightCorner_,NULL,xVScroll,yHScroll,cxVScroll,cyHScroll,SWP_NOZORDER|SWP_SHOWWINDOW);
		::DeferWindowPos(hdwp,wndSheet_.m_hWnd,NULL,0,0,cxSheet,cySheet,SWP_NOZORDER|SWP_NOMOVE|SWP_SHOWWINDOW);
		::EndDeferWindowPos(hdwp);
	}
	LRESULT Workbook::OnCreate(UINT,WPARAM,LPARAM lParam,BOOL& bHandled)
	{
		CreateChildren();
		return 0;
	}
	LRESULT Workbook::OnPostCreate(UINT,WPARAM,LPARAM lParam,BOOL& bHandled)
	{
		for(size_t i=0;i<vecWorksheet_.size();++i){
			if(pCurSheet_==vecWorksheet_[i]){
				wndTabHScroll_.GetFlatTabCtrl()->SetCurSel(int(i));
				break;
			}
		}
		return 0;
	}
	void Workbook::OnActivateApp(BOOL bActivated)//UINT,WPARAM,LPARAM lParam,BOOL&)
	{
		if(pCurSheet_ && bActivated){
			RECT rcCli;
			pCurSheet_->GetClientRect(&rcCli);
			pCurSheet_->RecalcCellAxisInfo(rcCli,CCAI_CALC_ALL);
		}
	}
	LRESULT Workbook::OnSize(UINT,WPARAM,LPARAM lParam,BOOL&)
	{
		if(pCurSheet_){
			const WORD cx=LOWORD(lParam);
			const WORD cy=HIWORD(lParam);
			if(!cx || !cy) return 0;
			UpdateControlLayout(cx,cy);
		}
		return 0;
	}
	LRESULT Workbook::OnTabItemChange(int,LPNMHDR pNMHDR, BOOL& bHandled)
	{
		if(pNMHDR->hwndFrom==wndTabHScroll_.m_hWnd && IsDrawingEnabled()){
			const int nChoice = wndTabHScroll_.GetFlatTabCtrl()->GetCurSel();
			Worksheet_SetActiveSheet(nChoice);
		}else
			bHandled=FALSE;
		return 0;
	}
	LPTSTR Workbook::GetNewSheetName(TCHAR buf[32])
	{
		CString str;
		for(int i=1;;++i){
			str.Format(_T("Sheet%d"),i);
			if(!Worksheet_FindByName(str)){
				lstrcpy(buf,str);
				break;
			}
		}
		return buf;
	}
}//namespace mycell

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
China China
My name is Yanxueming,i live in Chengdu China.Graduated from UESTC in 1999.

Comments and Discussions