www.pudn.com > TableTest.rar > XTable.cpp
// XTable.cpp : implementation file
//
#include "stdafx.h"
#include "TableTest.h"
#include "XTable.h"
#include "MemDc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTable
#define XTABLE_CLASSNAME _T("XTableCtrl")
CXTable::CXTable(int rows, int cols)
{
// RegisterWindowClass ();
defaultCell.table = this;
defaultHeight = 20;
defaultWidth = 80;
cells = NULL;
rowHeight = NULL;
colWidth = NULL;
this->rows = 0;
this->cols = 0;
SetRows (rows);
SetCols (cols);
focusRow = 0;;
focusCol = 0;
}
CXTable::~CXTable()
{
delete [] cells;
delete [] rowHeight;
delete [] colWidth;
}
BEGIN_MESSAGE_MAP(CXTable, CWnd)
//{{AFX_MSG_MAP(CXTable)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CXTable message handlers
void CXTable::OnPaint()
{
// CPaintDC dc(this); // device context for painting
CPaintDC dc(this); // device context for painting
CMemDC MemDC(&dc);
OnDraw(&MemDC);
// TODO: Add your message handler code here
// Do not call CWnd::OnPaint() for painting messages
}
BOOL CXTable::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
{
// TODO: Add your specialized code here and/or call the base class
// ASSERT(pParentWnd->GetSafeHwnd());
//
// if (!CWnd::Create(XTABLE_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
// return FALSE;
//
// return TRUE;
BOOL result ;
static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW) ;
result = CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE,
className, NULL, dwStyle,
rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID) ;
return result ;
// return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
int CXTable::SetRows(int newRows)
{
if (rows < 0 || rows > MAX_ROWS) return -1;
if (rows == newRows) return 0;
int cellsSize = cols * rows;
CXCell* newCells = cells;
int* newRowHeight = new int [newRows];
if ( rows < newRows)
{
if (cellsSize < newRows * cols)
{
cellsSize *= 2;
if (cellsSize < newRows * cols)
cellsSize = newRows * cols;
newCells = new CXCell [cellsSize];
//复制旧数据
for (int i = 0; i < rows; i++)
{
for(int j = 0; j < cols ; j++)
{
newCells [i * cols +j] = cells [i * cols +j];
}
newRowHeight [i] = rowHeight [i];
}
}
//初始化新数据
for (int i = rows; i < newRows; i++)
{
for (int j = 0; j < cols; j++)
{
newCells [i * cols + j] = defaultCell;
newCells [i * cols + j].SetSpan (1, 1);
}
newRowHeight [i] = defaultHeight;
}
delete [] rowHeight;
rowHeight = newRowHeight;
}
else
{
if (cellsSize > newRows * cols * 2)
{
cellsSize = newRows * cols;
newCells = new CXCell [cellsSize];
}
//复制数据
for (int i = 0; i < newRows; i ++)
{
for (int j = 0; j < cols; j++)
newCells [i * cols + j] = cells[i * cols +j];
}
}
if (newCells != cells)
{
delete [] cells;
cells = newCells;
}
rows = newRows;
return 0;
}
int CXTable::GetRows()
{
return rows;
}
int CXTable::SetCols(int newCols)
{
if (newCols < 0 || newCols > MAX_COLS) return -1;
if (this->cols == newCols) return 0;
int cellsSize = cols * rows;
CXCell* newCells = cells;
int* newColWidth = new int [newCols];
if ( cols < newCols)
{
if (cellsSize < newCols * rows)
{
cellsSize *= 2;
if (cellsSize < newCols * rows)
cellsSize = newCols * rows;
newCells = new CXCell [cellsSize];
//复制旧数据
for (int i = 0; i < rows; i++)
{
for(int j = 0; j < cols ; j++)
{
newCells [i * newCols +j] = cells [i * cols +j];
newColWidth[j] = colWidth [j];
}
}
}
//初始化新数据
for (int i = 0; i < rows; i++)
{
for (int j = cols; j < newCols; j++)
{
newCells [i * newCols + j] = defaultCell;
newCells [i * newCols + j].SetSpan (1, 1);
newColWidth[j] = defaultWidth;
}
}
delete [] colWidth;
colWidth = newColWidth;
}
else
{
if (cellsSize > newCols * rows * 2)
{
cellsSize = newCols * rows;
newCells = new CXCell [cellsSize];
}
//复制数据
for (int i = 0; i < rows; i ++)
{
for (int j = 0; j < newCols; j++)
newCells [i * newCols + j] = cells[i * cols +j];
}
}
if (newCells != cells)
{
delete [] cells;
cells = newCells;
}
cols = newCols;
return 0;
}
int CXTable::GetCols()
{
return cols;
}
int CXTable::JoinCells (int startRow, int startCol, int endRow, int endCol)
{
if (startRow < 0 || startRow >= rows) return -1;
if (endRow < 0 || startRow >= rows) return -1;
if (startCol < 0 || startCol >= cols) return -1;
if (endCol < 0 || endCol >= cols) return -1;
if (startRow > endRow || startCol > endCol) return -1;
for (int i = startRow; i <= endRow; i++)
{
for (int j = startCol; j <=endCol; j++)
{
cells [i * cols + j].SetSpan(0,0);
}
}
cells [startRow * cols + startCol].SetSpan(endRow - startRow+1, endCol - startCol+1);
return 0;
}
int CXTable::UnjoinCells (int row, int col)
{
if (row < 0 || row >= this->rows) return -1;
if (col < 0 || col >= this->cols) return -1;
if (cells [row * cols + col].rowSpan <= 1 && cells [row * cols + col].colSpan <= 1 ) return -1;
for (int i = row; i <= row + cells [row * cols + col].rowSpan; i++)
{
for (int j = col; j <= cells [row * cols + col].colSpan; j++)
{
cells[i*cols+j] = defaultCell;
cells [i * cols + j].SetSpan(1,1);
}
}
return 0;
}
int CXTable::SetRowHeight(int row, int height)
{
rowHeight [row] = height;
return 0;
}
int CXTable::GetRowHeight(int row)
{
return rowHeight [row];
}
int CXTable::SetColWidth(int col, int width)
{
colWidth [col] = width;
return 0;
}
int CXTable::GetColWidth(int col)
{
return colWidth [col];
}
int CXTable::GetRowsHeight(int startRow, int endRow)
{
if (startRow < 0 || startRow >= rows) return -1;
if (endRow < 0 || endRow >= rows) return -1;
if (startRow > endRow) return -1;
int height = 0;
for (int i = startRow; i <= endRow; i++)
{
height += rowHeight[i];
}
return height;
}
int CXTable::GetColsWidth(int startCol, int endCol)
{
if (startCol < 0 || startCol >= cols) return -1;
if (endCol < 0 || endCol >= cols) return -1;
if (startCol > endCol) return -1;
int width = 0;
for (int i = startCol; i <= endCol; i++)
{
width += colWidth[i];
}
return width;
}
int CXTable::SetCells(int row, int col, CXCell& cell)
{
cells[row * cols + col] = cell;
return 0;
}
CXCell* CXTable::GetCells(int row, int col)
{
return &cells [row * cols + col];
}
int CXTable::SetText(int row, int col, CString str)
{
CXCell* cell = GetCells (row, col);
if (!cell) return -1;
return cell->SetText (str);
}
CString CXTable::GetText(int row, int col)
{
return cells[row * cols + col].GetText();
}
int CXTable::SetTextColor(int row, int col, COLORREF color)
{
cells[row * cols + col].SetTextColor(color);
return 0;
}
COLORREF CXTable::GetTextColor(int row, int col)
{
return cells[row * cols + col].GetTextColor();
}
int CXTable::SetTextFont(int row, int col, CFont& font)
{
cells[row * cols + col].SetTextFont(&font);
return 0;
}
CFont* CXTable::GetTextFont(int row, int col)
{
return cells[row * cols + col].GetTextFont();
}
int CXTable::SetTextFontSize(int row, int col, int size)
{
cells[row * cols + col].SetTextFontSize(size);
return 0;
}
int CXTable::GetTextFontSize(int row, int col)
{
return cells[row * cols + col].GetTextFontSize();
}
int CXTable::SetOverlap (int row, int col, bool enable)
{
CXCell* cell = GetCells (row, col);
if (!cell) return -1;
return cell->SetOverlap (enable);
}
bool CXTable::GetOverlap (int row, int col)
{
CXCell* cell = GetCells (row, col);
if (!cell) return false;
return cell->GetOverlap ();
}
int CXTable::SetAlignment (int row, int col, int align)
{
CXCell* cell = GetCells (row, col);
if (!cell) return -1;
return cell->SetAlignment (align);
}
int CXTable::GetAlignment (int row, int col)
{
CXCell* cell = GetCells (row, col);
if (!cell) return -1;
return cell->GetAlignment ();
}
int CXTable::SetWordbreak (int row, int col, bool wordbreak)
{
CXCell* cell = GetCells (row, col);
if (!cell) return -1;
return cell->SetWordbreak (wordbreak);
}
bool CXTable::GetWordbreak (int row, int col)
{
CXCell* cell = GetCells (row, col);
if (!cell) return false;
return cell->GetWordbreak ();
}
int CXTable::SetBackColor(int row, int col, COLORREF color)
{
cells[row * cols + col].SetBackColor(color);
return 0;
}
COLORREF CXTable::GetBackColor(int row, int col)
{
return cells[row * cols + col].GetBackColor();
}
int CXTable::SetBackMode(int row, int col, int mode)
{
cells[row * cols + col].SetBackMode(mode);
return 0;
}
int CXTable::GetBackMode(int row, int col)
{
return cells[row * cols + col].GetBackMode();
}
RECT CXTable::GetRect(int row, int col)
{
RECT rect;
int rowSpan = GetCells(row, col)->rowSpan;
int colSpan = GetCells(row, col)->colSpan;
rect.top = GetRowsHeight(0, row-1);
rect.left = GetColsWidth(0, col-1);
rect.bottom = rect.top + GetRowsHeight (row, row + rowSpan-1);
rect.right = rect.left + GetColsWidth (col, col + colSpan-1);
return rect;
}
bool CXTable::HitTest (CPoint point, int& row, int& col)
{
for (int i= 0; i < rows; i++)
{
for(int j=0; j < rows; j++)
{
RECT rect = GetRect (i,j);
if (rect.top <= point.y && rect.bottom > point.y && rect.left <= point.x && rect.right > point.x)
{
row = i;
col = j;
return true;
}
}
}
return false;
}
void CXTable::OnDraw(CDC* pDC)
{
static bool lock = false;
if (lock) return;
// if (!::IsWindow(m_hWnd)) return;
lock = true;
Draw (pDC);
lock = false;
}
int CXTable::Draw(CDC* pDC)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
CXCell& cell = cells[i*cols+j];
if (cell.colSpan !=0 && cell.rowSpan != 0)
{
RECT rect = GetRect(i,j);
if (cell.GetOverlap())
{
RECT textRect = GetRect(i,j);
cell.CalcTextRect(pDC, &textRect);
if (textRect.right > rect.right)
{
for (j = j+1; j < cols; j ++)
{
if (cells[i*cols+j].text != "")
break;
rect.right += colWidth [j];
if (rect.right > textRect.right)
break;
}
j --;
}
}
cell.Draw(pDC,rect);
}
}
}
if (focusRow < rows && focusCol < cols) //**
{
RECT rect = GetRect (focusRow, focusCol);
GetCells (focusRow, focusCol)->DrawHitBorder(pDC, rect, RGB(255, 0, 20));
}
return 0;
}
// CXTable message handlers
//void CXTable::OnPaint()
//{
//}
/*
BOOL CXTable::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CXTable::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CPoint point;
RECT rect = GetRect(focusRow,focusCol);
point.x = rect.left;
point.y = rect.top;
switch (nChar)
{
case VK_DOWN:
point.y =rect.bottom + 1;
break;
case VK_UP:
point.y =point.y -2;
break;
case VK_LEFT:
point.x = point.x - 2;
break;
case VK_RIGHT:
point.x =rect.right + 1;
break;
default:
return ;
}
HitTest (point,focusRow,focusCol);
Invalidate();
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CXTable::OnLButtonDown(UINT nFlags, CPoint point)
{
HitTest (point,focusRow,focusCol);
SetFocus ();
Invalidate();
CWnd::OnLButtonDown(nFlags, point);
}
*/
BOOL CXTable::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();
if (!(::GetClassInfo(hInst, XTABLE_CLASSNAME, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = XTABLE_CLASSNAME;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
int CXTable::Test()
{
defaultHeight = 20;
defaultWidth = 80;
int i = 0;
int j = 0;
int row_Height = 0;
int col_Width = 0;
CFont titleFont;
CFont normalFont;
titleFont.CreateFont(16, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH, FF_DONTCARE, "TitleFont");
normalFont.CreateFont(12, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH, FF_DONTCARE, "TitleFont");
row_Height = (m_rect.bottom-m_rect.top)/10;
col_Width = (m_rect.right - m_rect.left)/5;
SetRows (10);
SetCols (5);
for (i = 0; i < 10; i ++)
{
SetBackColor (i, 0, RGB(0xC8, 0x96, 0x96));
SetRowHeight (i, row_Height);
SetTextFont(i, 0, titleFont);
}
for (i = 0; i < 5; i++)
{
SetBackColor (0, i, RGB(0xC8, 0x96, 0x96));
SetColWidth(i, col_Width);
SetTextFont(0, i, titleFont);
}
SetText (0,0, "Hello World!");
for (i=1; i<10; i++) {
for (j=1; j<5; j++) {
SetTextFont(i, j, normalFont);
SetText(i, j, "yeah");
}
}
// CFont *pOldFont = GetTextFont(0, 0);
/*
SetRowHeight (0, 10);
SetRowHeight (2, 10);
SetRowHeight (7, 10);
SetRowHeight (9, 10);
SetRowHeight (13, 10);
SetRowHeight (15, 10);
SetRowHeight (19, 10);
SetRowHeight (21, 10);
SetRowHeight (24, 10);
SetRowHeight (28, 10);
SetRowHeight (31, 10);
SetRowHeight (34, 10);
for (i = 0; i < 9; i ++)
SetBackColor (0, i, RGB(0xC8, 0x96, 0x96));
SetColWidth (0, 10);
JoinCells (1,1,1,8);
SetBackColor (1,1, RGB(0x64,0x96,0xC8));
SetText (1,1, "Default edit control respects cell's celltype, font size and type");
JoinCells (3,1,3,2);
SetText (3,1, "Using default font");
SetText (3,3, "Enter text");
JoinCells (3,5,5,6);
SetText (3,5, "This cell contains multiline text, which provides multiline edit.");
SetWordbreak (3,5,true);
JoinCells (3,7,5,8);
SetText (3,7, "This cell contains multiline text, which provides multiline edit.");
SetWordbreak (3,7,true);
SetText (4,1, "You can even edit a long (cell overlapping) string.");
SetOverlap(4,1,true);
SetText (4,3, "Test");
JoinCells (5,1,6,2);
SetText (5,1, "Enter your name here.");
JoinCells (5,3,5,4);
SetText (5,3, "Enter your text here ...");
JoinCells (8,1,8,8);
SetBackColor (8,1, RGB(0x64,0x96,0xC8));
SetText (8,1, "Default edit controls also allow us to customize user's editing experience by:");
JoinCells (10,1,10,2);
SetBackColor (10,1, RGB(0xDC,0xC8,0xB4));
SetText (10,1, "Converting input to upper case:");
SetText (10,3, "TYPE HERE ...");
JoinCells (10,5,10,6);
SetBackColor (10,5, RGB(0xDC,0xC8,0xB4));
SetText (10,5, "Converting input to lower case:");
SetText (10,7, "type here ...");
JoinCells (11,1,11,2);
SetBackColor (11,1, RGB(0xDC,0xC8,0xB4));
SetText (11,1, "Allowing password input:");
SetText (11,3, "*********");
SetText (11,5, "Entered password was:*********");
SetOverlap(11,5,true);
JoinCells (12,1,12,2);
SetBackColor (12,1, RGB(0xDC,0xC8,0xB4));
SetText (12,1, "Allowing aligned input:");
SetText (12,3, "Left aligned");
SetText (12,5, "Centered");
SetAlignment (12,5,DT_CENTER);
SetText (12,7, "Right aligned");
SetAlignment (12,7,DT_RIGHT);
JoinCells (14,1,14,8);
SetBackColor (14,1, RGB(0x64,0x96,0xC8));
SetText (14,1, "Ultimate Grid allow us to process user's input with various notifications.");
JoinCells (16,1,16,5);
SetBackColor (16,1, RGB(0xDC,0xC8,0xB4));
SetText (16,1, "We can verify data it is entered, for example to limit number of char to 4:");
SetText (16,6, "");
JoinCells (17,1,17,5);
SetBackColor (17,1, RGB(0xDC,0xC8,0xB4));
SetText (17,1, "or that the numeric value entered is under 500 (number < 500):");
SetText (17,6, "");
JoinCells (18,1,18,5);
SetBackColor (18,1, RGB(0xDC,0xC8,0xB4));
SetText (18,1, "We can also test user's input after it is completed, or force user's input:");
SetText (18,6, "");
JoinCells (20,1,20,8);
SetBackColor (20,1, RGB(0x64,0x96,0xC8));
SetText (20,1, "The Ultimate Grid also allows us to use other edit controls when needed:");
JoinCells (22,1,23,5);
SetBackColor (22,1, RGB(0xDC,0xC8,0xB4));
SetText (22,1, "Just by setting a mask on a cell, the grid will change edit controls to use a mask edit. By default Ultimate Grid creates an instance of CUGMEdit to use as mask edit control.");
SetWordbreak (22,1,true);
JoinCells (22,6,22,7);
SetText (22,6, "