Click here to Skip to main content
15,891,864 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.
// InPlaceEdit.cpp: implementation of the CInPlaceEdit class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "../include/InPlaceEdit.h"
#include "../include/Worksheet.h"
#include "../include/msg.h"
#include "../include/Text.h"
namespace mycell{
	enum{ PROP_TEXT_INDENT = 2};
	//////////////////////////////////////////////////////////////////////
	// Construction/Destruction
	//////////////////////////////////////////////////////////////////////
	CInPlaceEdit::CInPlaceEdit(Worksheet* pSheet,HFONT hFont,HWND hWndParent, RECT& rect, DWORD dwStyle, UINT nID,
		int row,int col, LPCTSTR lpszCellText,LPCTSTR lpszInitText)
		:pSheet_(pSheet),m_fCancel(false),font_(hFont)
	{
		cell_.set(row,col);

		rect_ = rect;  // For bizarre CE bug.

		DWORD dwEditStyle = /*WS_BORDER|*/WS_CHILD|WS_VISIBLE| ES_AUTOHSCROLL //|ES_MULTILINE
			| dwStyle;
		//int const iTextLen=-1==row?(pSheet_->get_ColHeader().get_text(col,m_sInitText)):pSheet_->GetCellText(cell_,m_sInitText);

		if(lpszCellText){
			lstrcpy(m_sInitText,lpszCellText);
		}
		const int iTextLen=lstrlen(m_sInitText);
		if (!Create(hWndParent,rect,m_sInitText,dwEditStyle, 0,nID)) return;
		SetMargins(PROP_TEXT_INDENT, 0);   // Force EDIT margins so text doesn't jump
		SetFont(hFont);//(HFONT)::GetStockObject(DEFAULT_GUI_FONT));

		SetFocus();
		int iLen=lstrlen(lpszInitText);
		if(iLen>1 && !(VK_LBUTTON==(UINT)lpszInitText[0] || VK_SPACE==(UINT)lpszInitText[0])){
			SetWindowText(lpszInitText);
			SetSel(iLen,-1);
			SetModify();
			return;
		}else{
			iLen=iTextLen;
			SetWindowText(m_sInitText);
		}
		//AtlTrace(_T("\nlpszInitText=%s,iLen=%d"),lpszInitText,iLen);
		UINT nFirstChar=lpszInitText[0];
		switch (nFirstChar){
		case VK_LBUTTON: 
		case VK_RETURN:   SetSel(/*(int)m_sInitText.Length()*/iLen, -1); return;
		case VK_BACK:     SetSel(/*(int)m_sInitText.Length()*/iLen, -1); break;
		case VK_TAB:
		case VK_DOWN: 
		case VK_UP:   
		case VK_RIGHT:
		case VK_LEFT:  
		case VK_NEXT:  
		case VK_PRIOR: 
		case VK_HOME:
		case VK_SPACE:
		case VK_END:      SetSel(0,-1); return;
		default:          SetSel(0,-1);
		}

		// Added by KiteFly. When entering DBCS chars into cells the first char was being lost
		// SenMessage changed to PostMessage (John Lagerquist)
		if( nFirstChar < 0x80)
			PostMessage(WM_CHAR, nFirstChar);   
		//else
		//  PostMessage(WM_IME_CHAR, nFirstChar);
	}

	CInPlaceEdit::~CInPlaceEdit()
	{

	}
	void CInPlaceEdit::OnFinalMessage(HWND /*hWnd*/)
	{
		//pSheet_->SetFocus();
		delete this;
	}

	void CInPlaceEdit::EndEdit()
	{
		// EFW - BUG FIX - Clicking on a grid scroll bar in a derived class
		// that validates input can cause this to get called multiple times
		// causing assertions because the edit control goes away the first time.
		static BOOL bAlreadyEnding = FALSE;

		if(bAlreadyEnding)
			return;

		bAlreadyEnding = TRUE;
		int len = ::GetWindowTextLength(m_hWnd) + 1;
		LPTSTR str = (LPTSTR) _alloca(len * sizeof(TCHAR));
		ATLASSERT(str);
		if( ::GetWindowText(m_hWnd, str, len) == 0 ) {
			// Bah, an empty string AND an error causes the same return code!
			//if( ::GetLastError() != 0 ) return FALSE;
			if( ::GetLastError() != 0 )
				_ASSERT(FALSE);
		}

		if(IsWindowVisible())
			ShowWindow(SW_HIDE);
		//-----------
		TCHAR szCurText[MAX_CELLTEXT];
		szCurText[0]=_T('\0');
		int const iLenCurText=pSheet_->GetCellText(cell_,szCurText,EGCVD_EDIT);
		if (!iLenCurText || lstrlen(str)<=0 || 0!=lstrcmp(str,szCurText))
		{
			BOOL bHandled=FALSE;
			pSheet_->SendNotifyMessageToListener(cell_.row,cell_.col,OCN_ENDCELLEDIT,(LPARAM)str,&bHandled);
			if(!bHandled){
				TCHAR szNew[MAX_CELLTEXT];szNew[0]=_T('\0');
				int len=pSheet_->GetCellText(cell_,szNew,EGCVD_EDIT);
				const BOOL bWrapText=Text_HasReturnChar(szNew,len);
				if(bWrapText){
					StyleDesc sd=pSheet_->Style_GetCellStyle(cell_);
					sd.Align_SetWrapText(bWrapText);
					pSheet_->Style_SetCellStyle(cell_,sd);
				}
				if(pSheet_->get_AutoAppendRow() && cell_.row==pSheet_->get_RowHeader().get_rows()-1
					&& 0!=lstrcmp(szNew,szCurText))
				{
					RECT const rc=pSheet_->raw_GetCellRect(CCell(cell_.row,HEADER_COL));
					pSheet_->InvalidateRect(&rc,FALSE);
					pSheet_->put_rows(cell_.row+2);
				}
				pSheet_->SetCellText(cell_,CComVariant(str),TRUE);
			}
		}


		//HWND hWndParent=GetParent();
		//if(::IsWindow(hWndParent))
		//	::SendMessage(hWndParent,WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo );
		// Close this window (PostNcDestroy will delete this)
		//if (IsWindow())
		//	SendMessage(WM_CLOSE, 0, 0);
		bAlreadyEnding = FALSE;
	}

	LRESULT CInPlaceEdit::OnKillFocus(UINT nMsg, WPARAM wParam, 
		LPARAM lParam, BOOL& bHandled)
	{
		LRESULT lRet=DefWindowProc();
		//EndEdit();
		m_fCancel |= (GetModify() == FALSE);
		if(!m_fCancel){
			EndEdit();
		}
		if (IsWindow())
			SendMessage(WM_CLOSE,0,0);
		return lRet;
	}
	LRESULT CInPlaceEdit::OnChar(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandled)//UINT nChar, UINT nRepCnt, UINT nFlags)
	{
		UINT nChar=(UINT)wParam;
		UINT nRepCnt=LOWORD(lParam);
		if (nChar == VK_TAB || nChar == VK_RETURN)
		{
			HWND const hWndParent=GetParent();
			m_nLastChar = nChar;
			::SetFocus(hWndParent);    // This will destroy this window
			::SendMessage(hWndParent,WM_KEYDOWN/*uMsg*/,wParam,lParam);
			return 0;
		}
		if (nChar == VK_ESCAPE) 
		{
			USES_CONVERSION;
			SetWindowText(m_sInitText);    // restore previous text
			m_nLastChar = nChar;
			::SetFocus(GetParent());
			return 0;
		}
		bHandled=FALSE;
		if(wParam < 0x20) return 0;//always allow control chars

		const StyleDesc& styleDesc=pSheet_->Style_GetCellStyle(cell_);
		
		//ECellType const tc=pSheet_->GetCellType(cell_.row,cell_.col,styleDesc);
		//ColHeader& ch=pSheet_->get_ColHeader();
		
		const ECellType cellType=pSheet_->GetCellStore(cell_,ECSM_CELLTYPE_VALID).GetCellType();//styleDesc.CellType_GetType();//==ECT_NONE?ch.get_DefColType():styleDesc.cellType;//pSheet_->GetCellType(row,col,styleDesc);//styleDesc.cellType;
		switch(cellType)
		{
		case ECT_UINT:
			{
				if(!(IsCharAlphaNumeric((TCHAR)wParam) && !IsCharAlpha((TCHAR)wParam))){
					bHandled=TRUE;
					::MessageBeep((UINT)-1);
				}
			}break;
		case ECT_INT:
			{
				if(!(wParam=='-'||IsCharAlphaNumeric((TCHAR)wParam) && !IsCharAlpha((TCHAR)wParam))){
					bHandled=TRUE;
					::MessageBeep((UINT)-1);
				}
			}
			break;
		case ECT_UDOUBLE:
			{
				if(!(wParam>='0'&&wParam<='9'||wParam==VK_BACK||wParam=='.')){
					bHandled=TRUE;
					::MessageBeep((UINT)-1);
				}
			}
			break;
		case ECT_DOUBLE:
			{
				if(!(wParam>='0'&&wParam<='9'||wParam=='-'||wParam==VK_BACK||wParam=='.')){
					bHandled=TRUE;
					::MessageBeep((UINT)-1);
				}
			}
			break;
		default:
			break;
		}
		LRESULT lRet=0;
		return lRet;
	}

	LRESULT CInPlaceEdit::OnGetDlgCode(UINT,WPARAM,LPARAM,BOOL&)
	{
		return DLGC_WANTALLKEYS;
	}
	LRESULT CInPlaceEdit::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		UINT nChar=(UINT)wParam;
		UINT nRepCnt=LOWORD(lParam);
		switch(nChar)
		{
		case VK_ESCAPE:
			m_fCancel = true;
			// FALL THROUGH...

			//case VK_LEFT:
			//	int lLow, lHigh;
			//	GetSel(lLow, lHigh);
			//	if( lLow != lHigh || lLow != 0 ) break;
			//case VK_RIGHT:
			//	GetSel(lLow, lHigh);
			//	if( lLow != lHigh || lLow != GetWindowTextLength() ) break;
			//case VK_PRIOR:
			//case VK_NEXT:
			//case VK_DOWN:
			//case VK_UP:
		case VK_RETURN:
			if(IsCTRLpressed())
				break;
		case VK_TAB:
			//(m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0)*/)
			{
				m_nLastChar = nChar;
				//::SetFocus(GetParent());
				//::SendMessage(GetParent(),uMsg,wParam,lParam);
				return 0;
			}
		}
		return DefWindowProc(uMsg,wParam,lParam);
	}
}//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