Click here to Skip to main content
15,895,709 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-2006
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
#pragma once
#include <map>
#include <vector>
#include <atlstr.h>
#include "base.h"
using namespace std;
namespace mycell{
	class GridBase;
	class VaryRowHeightProcy
	{			 
		enum eBits
		{
			B_AllowRowResize=1<<0,
		};
	protected:
		VaryRowHeightProcy():defHeight_(17),bits_(B_AllowRowResize)
		{}
	public:
		void put_DefRowHeight(int hi)
		{
			defHeight_=hi;
		}
		int get_DefRowHeight()const
		{
			return defHeight_;
		}
		//template<class T>
		int get_heights(int rows)const
		{
			//int const rows=pT->get_rows();
			int heights=(rows - int(mapIrregHeights_.size()))*get_DefRowHeight();
			for(map<int,int>::const_iterator it=mapIrregHeights_.begin();it!=mapIrregHeights_.end();++it)
			{
				heights+=it->second;
			}
			return heights;
		}
		//[row1,row2)
		int get_DiffHeights(int row1,int row2)const
		{
			if(row1>=row2) return 0;
			int heights=(row2-row1)*get_DefRowHeight();
			for(map<int,int>::const_iterator it=mapIrregHeights_.begin();it!=mapIrregHeights_.end();++it)
			{
				if(it->first>=row1 && it->first<row2){
					heights-=get_DefRowHeight();
					heights+=it->second;
				}
			}
			return heights;
		}
		void put_RowHeight(int row,int hi)
		{
			if(hi==defHeight_){
				map<int,int>::iterator it=mapIrregHeights_.find(row);
				if(it!=mapIrregHeights_.end())
					mapIrregHeights_.erase(it);
			}else{
				mapIrregHeights_[row]=hi;
			}
		}
		int get_RowHeight(int row)const
		{
			map<int,int>::const_iterator it=mapIrregHeights_.find(row);
			return it==mapIrregHeights_.end()?defHeight_:it->second;
		}
		BOOL get_AllowRowResize()const
		{
			return bits_&B_AllowRowResize?TRUE:FALSE;
		}
		void put_AllowRowResize(BOOL bAllow)
		{
			bAllow?bits_|=B_AllowRowResize:bits_&=~B_AllowRowResize;	 
		}
	protected:
		void delete_row(int row)
		{
			map<int,int>::iterator it=mapIrregHeights_.find(row);
			if(it!=mapIrregHeights_.end())
				mapIrregHeights_.erase(it);
		}
		void put_rows(int rows)
		{
			for(map<int,int>::iterator it=mapIrregHeights_.begin();it!=mapIrregHeights_.end();++it)
			{
				if(it->first>=rows)
					it=mapIrregHeights_.erase(it);
			}
		}
	private:
		int	defHeight_,bits_;
		map<int,int> mapIrregHeights_;
	};
	class FixedRowHeightPolicy
	{
		int rowHeight_;
	public:		 
		FixedRowHeightPolicy():rowHeight_(17)
		{}
		int get_heights(int rows)const
		{
			return rows*rowHeight_;
		}
		//[row1,row2)
		int get_DiffHeights(int row1,int row2)const
		{
			return (row2-row1)*rowHeight_;
		}
		void put_RowHeight(int row,int hi)
		{
		}
		int get_RowHeight(int row)const
		{		   
			return rowHeight_;
		}
		int get_DefRowHeight()const
		{
			return rowHeight_;
		}
		void put_DefRowHeight(int hi)
		{
		   rowHeight_=hi;
		}
		BOOL get_AllowRowResize()const
		{
			return FALSE;
		}
		void put_AllowRowResize(BOOL)
		{
		}
	protected:
		void delete_row(int row)
		{
		}
		void put_rows(int rows)
		{
		}
	};
	template<class T,class RowHeightProcy=VaryRowHeightProcy>
	class RowHeightMgr : public RowHeightProcy
	{
	protected:
		RowHeightMgr(){}
	public:
		int get_heights()const
		{
			T const* pT=static_cast<T const*>(this);
			return RowHeightProcy::get_heights(pT->get_rows());
		}
		//[row1,row2)
		int get_DiffHeights(int row1,int row2)const
		{
			return RowHeightProcy::get_DiffHeights(row1,row2);
		}
		int get_RowHeight(int row)const
		{		   
			return RowHeightProcy::get_RowHeight(row);
		}
		int get_DefRowHeight()const
		{
			return RowHeightProcy::get_DefRowHeight();
		}
		void put_DefRowHeight(int hi)
		{
			RowHeightProcy::put_DefRowHeight(hi);
		}
	protected:
		void put_RowHeight(int row,int hi)
		{
			RowHeightProcy::put_RowHeight(row,hi);
		}
	};

	class RowHeader;
	typedef RowHeightMgr<RowHeader> VaryRowHeightMgr;
	typedef RowHeightMgr<RowHeader,FixedRowHeightPolicy> FixedRowHeightMgr;
//#ifdef MYCELL_USE_VARYROWHEADER
	typedef VaryRowHeightMgr RowHeightMgrT;
//#else
//	typedef FixedRowHeightMgr RowHeightMgrT;
//#endif
	struct RowHeaderEvents
	{
		virtual void OnVisibleRowChanged(int oldTopRow,int oldBottomRow,int newTopRow,int newBottomRow)=0;
	};
	class RowHeader : public RowHeightMgrT
	{
		typedef RowHeightMgrT baseClass;
		friend class GridBase;
	public:
		RowHeader():rows_(100),width_(30),topRow_(0),bottomRow_(-1),pEvents_(NULL)
		{
		}
		void SetListener(RowHeaderEvents* p)
		{
			pEvents_=p;
		}
		int get_rows()const
		{
			return rows_;
		}
		//return validate toprow;
		int put_TopRow(int row,LPCRECT lprcContent);
		//return new toprow;
		int put_BottomRow(int row,LPCRECT lprcContent,BOOL bFullVisible=FALSE);
		int get_TopRow()const
		{
			return topRow_;
		}
		int calc_TopRow(int height);
		int get_BottomRow()const
		{
			//_ASSERT(-1!=bottomRow_);
			return bottomRow_;
		}
		void put_width(int wi)
		{
			width_=wi;
		}
		int get_MinWidth()const
		{
			return 30;
		}
		int get_width()const
		{
			return width_;
		}
		int get_text(int row,LPTSTR buf)
		{
			wsprintf(buf,_T("%d"),row+1);
			for(int i=0;i!=MAX_CELLTEXT && buf[i];++i)
				;
			return i;
		}
	private:
		void put_rows(int rows)
		{
			_ASSERT(rows>=0);
			rows_=rows;
			//if(bottomRow_>=rows)
			//	bottomRow_=rows-1;
			//if(topRow_>bottomRow_)
			//	topRow_=bottomRow_;
			baseClass::put_rows(rows);
		}
		void delete_row(int row,LPCRECT lprcContent)
		{
			baseClass::delete_row(row);
			--rows_;
			if(row>=topRow_&& row<=bottomRow_){
				validate_TopRow(lprcContent);
				validate_BottomRow(lprcContent);
			}
		}
		BOOL IsTopRowValidate(LPCRECT lprcContent);
		void validate_TopRow(LPCRECT lprcContent);
		void validate_BottomRow(LPCRECT lprcContent);
	private:
		int	rows_;
		int	width_;
		int topRow_,bottomRow_;
		RowHeaderEvents* pEvents_;
	};
	//struct ColumnInfo
	//{
	//	CString label;
	//	CellTypeConstants cellType;
	//};
	struct ColHeaderEvents
	{
		virtual void OnVisibleColChanged(int oldLeftCol,int oldRightCol,int newLeftCol,int newRightCol)=0;
	};
	class ColHeader
	{
		friend class GridBase;
		ColHeader(ColHeader const& rhs);
		ColHeader& operator=(ColHeader const& rhs);
	public:		 
		explicit ColHeader():cols_(200),defWidth_(80),height_(20),leftCol_(0),rightCol_(-1)
			,defColType_(cellDefault),pEvents_(NULL)
		{
			vecLabel_.resize(cols_);
			//vecColInfo_.resize(cols_);
		}
		void put_DefColType(CellTypeConstants cellType)
		{
			defColType_=cellType;
		}
		CellTypeConstants get_DefColType()const
		{
			return defColType_;
		}
		void SetListener(ColHeaderEvents* p)
		{
			pEvents_=p;
		}
		int get_cols()const
		{
			return cols_;
		}
		//return new leftcol
		int put_LeftCol(int col,LPCRECT lprcContent);
		//return new leftcol
		int put_RightCol(int col,LPCRECT lprcContent,BOOL bFullVisible=FALSE);
		int get_LeftCol()const
		{
			return leftCol_;
		}
		int get_RightCol()const
		{
			//_ASSERT(-1!=rightCol_);
			return rightCol_;
		}
		void put_DefColWidth(int wi)
		{
			defWidth_=wi;
		}
		int get_DefColWidth()const
		{
			return defWidth_;
		}
		//[col1,col2)
		int get_DiffWidths(int col1,int col2);
		int get_widths()const
		{
			int widths=(cols_-int(mapIrregWidths_.size()))*get_DefColWidth();
			for(map<int,int>::const_iterator it=mapIrregWidths_.begin();it!=mapIrregWidths_.end();++it)
				widths+=it->second;
			return widths;
		}
		int get_ColWidth(int col)const
		{
			map<int,int>::const_iterator it=mapIrregWidths_.find(col);
			return it==mapIrregWidths_.end()?defWidth_:it->second;
		}
		void put_height(int hi)
		{
			height_=hi;
		}
		int get_height()const
		{
			return height_;
		}
		int get_text(int col,LPTSTR buf)
		{
			_ASSERT(col>=0);
			_ASSERT(col<get_cols());
			lstrcpy(buf,vecLabel_[col]);
			//lstrcpy(buf,vecColInfo_[col].label);
			/*
			++col;
			if(col<27){					//A~Z
				buf[0]=(col+0x40);
				buf[1]=0;
			}else if(col<703){				//AA~ZZ
				buf[1]=(col-1)%26+'A';//0x41;
				buf[0]=(col-1)/26-1+'A';//0x40;
				buf[2]=0;
			}
			*/
			for(int i=0;i!=MAX_CELLTEXT && buf[i];++i)
				;
			return i;
		}
		int calc_LeftCol(int width);
		void put_ColLabel(int col,LPCTSTR label)
		{
			_ASSERT(col<cols_);
			_ASSERT(col>=0);
			vecLabel_[col]=label;
			//vecColInfo_[col].label=label;
		}
		CString const& getref_ColLabel(int col)
		{
			_ASSERT(col<cols_);
			_ASSERT(col>=0);
			return vecLabel_[col];
			//return vecColInfo_[col].label;
		}
		CellTypeConstants get_ColType(int col)const
		{
			map<int,CellTypeConstants>::const_iterator it=mapColType_.find(col);
			return it==mapColType_.end()?defColType_:it->second;
		}
		void put_ColType(int col,CellTypeConstants type)
		{
			if(defColType_!=type)
				mapColType_[col]=type;
		}
		//CellTypeConstants get_CellType(int col)
		//{
		//	return cellEdit;
		//}
	private:
		void put_cols(int cols)
		{
			cols_=cols;
			vecLabel_.resize(cols_);
			for(map<int,int>::iterator it=mapIrregWidths_.begin();it!=mapIrregWidths_.end();++it)
			{
				if(it->first>=cols){
					it=mapIrregWidths_.erase(it);
				}
			}
			//vecColInfo_.resize(cols_);
		}
		void put_ColWidth(int col,int wi/*,LPCRECT lprcClient*/)
		{
			if(wi==defWidth_){
				map<int,int>::iterator it=mapIrregWidths_.find(col);
				if(it!=mapIrregWidths_.end())
					mapIrregWidths_.erase(it);
			}else{
				mapIrregWidths_[col]=wi;
			}
			//put_LeftCol(get_LeftCol(),lprcClient);
		}
		void validate_LeftCol(LPCRECT lprcClient);
		void validate_RightCol(LPCRECT lprcClient);
	private:
		int	cols_;
		int	defWidth_,height_;
		int leftCol_,rightCol_;
		CellTypeConstants defColType_;
		map<int,int> mapIrregWidths_;
		map<int,CellTypeConstants> mapColType_;
		vector<CString> vecLabel_;
		ColHeaderEvents* pEvents_;
	};
}//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