📄 nrdbgrid.cpp
字号:
//////////////////////////////////////////////////////
//
// NRDB Pro - Spatial database and mapping application
//
// Copyright (c) 1989-2004 Richard D. Alexander
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// NRDB Pro is part of the Natural Resources Database Project
//
// Homepage: http://www.nrdb.co.uk/
// Users' Forum: http://nrdb.mypalawan.info/
//
#include "stdafx.h"
#include <math.h>
#include "nrdb.h"
#include "NRDBGrid.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
void inline swap(long& a, long& b)
{
long c = a;
a = b;
b = c;
}
COLORREF inline InverseColor(COLORREF cr)
{
return RGB(255-GetRValue(cr), 255-GetGValue(cr), 255 - GetBValue(cr));
};
/////////////////////////////////////////////////////////////////////////////
// CNRDBGrid
CNRDBGrid::CNRDBGrid()
{
m_nActiveRow = 1;
m_nActiveCol = 1;
m_nFocusRow = 1;
m_nFocusCol = 1;
m_nFirstVisibleRow = 1;
m_nFirstVisibleCol = 1;
m_nVisibleColumns = 0;
m_nVisibleRows = 0;
m_celltopleft.Row = -2;
m_celltopleft.Col = -2;
m_cellbottomright.Col = -2;
m_cellbottomright.Row = -2;
m_nRows = 0;
m_nCols = 0;
m_dColWidth = 1;
m_hFont = NULL;
m_bShift = FALSE;
m_bCtrl = FALSE;
m_bLButton = FALSE;
m_nUndoRow = 0;
m_nUndoCol = 0;
m_hDragCursor = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_DRAGHORZ));
//m_hDefaultCursor = ::GetCursor();
m_nDragCol = 0;
m_bDragCursor = FALSE;
m_bEditMode = FALSE;
}
CNRDBGrid::~CNRDBGrid()
{
if (m_hDragCursor != NULL) DestroyCursor(m_hDragCursor);
}
BEGIN_MESSAGE_MAP(CNRDBGrid, CButton)
//{{AFX_MSG_MAP(CNRDBGrid)
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_CHAR()
ON_WM_KILLFOCUS()
ON_WM_SETFOCUS()
ON_WM_KEYUP()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
ON_WM_SETCURSOR()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETEDITMODE, OnSetEditMode)
ON_MESSAGE(WM_COPY, OnCopy)
ON_MESSAGE(WM_CUT, OnCut)
ON_MESSAGE(WM_PASTE, OnPaste)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNRDBGrid message handlers
CGridRow::CGridRow(CGridRow& rSrc)
{
*this = rSrc;
}
CGridRow& CGridRow::operator=(CGridRow& rSrc )
{
RemoveAll();
Copy(rSrc);
return *this;
}
/////////////////////////////////////////////////////////////////////////////
BOOL CNRDBGrid::ClearDataRange(SS_COORD Col, SS_COORD Row,
SS_COORD Col2, SS_COORD Row2)
{
for (int i = Col; i <= Col2; i++)
{
for (int j = Row; j <= Row2; j++)
{
SetValue(i, j, "");
SetInteger(i, j, 0);
SetIndex(i, j, -1);
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
// Resize the grid to reflect the number of columns
//
void CNRDBGrid::SetMaxCols(SS_COORD MaxCols)
{
m_nCols = MaxCols+1;
for (int iRow = 0; iRow < m_nRows; iRow++)
{
int nSize = m_aGrid[iRow].GetSize();
m_aGrid[iRow].SetSize(m_nCols);
};
m_aColumns.SetSize(m_nCols);
}
///////////////////////////////////////////////////////////////////////////////
//
// Resize the grid to reflect the number of rows
//
void CNRDBGrid::SetMaxRows(SS_COORD MaxRows)
{
m_nRows = MaxRows+1;
m_aGrid.SetSize(m_nRows);
// Update the column size for the new columns
SetMaxCols(m_nCols-1);
};
///////////////////////////////////////////////////////////////////////////////
BOOL CNRDBGrid::DelRow(SS_COORD Row)
{
if (m_nRows > 2)
{
m_aGrid.RemoveAt(Row);
SetMaxRows(GetMaxRows()-1);
// Create a blank row
if (m_nRows == 1)
{
InsRow(1);
}
};
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CNRDBGrid::InsRow(SS_COORD nRow)
{
CGridRow row;
m_aGrid.InsertAt(nRow, row);
SetMaxRows(GetMaxRows()+1);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
// Set value, update number of columns if necessary
//
BOOL CNRDBGrid::SetValue(SS_COORD Col, SS_COORD Row, LPCTSTR lpData)
{
if (Row >= m_nRows) SetMaxRows(Row);
if (Col >= m_nCols) SetMaxCols(Col);
m_aGrid[Row][Col].m_sText = lpData;
m_aGrid[Row][Col].m_sText.TrimRight();
Invalidate(FALSE);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CNRDBGrid::SetColWidth(SS_COORD Col, double Width)
{
if (Col == -1)
{
for (int i = 0; i < m_nCols; i++)
{
m_aColumns[i].m_dWidth = Width;
}
// Set default column width
m_dColWidth = Width;
} else
{
m_aColumns[Col].m_dWidth = Width;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
double CNRDBGrid::GetColWidth(SS_COORD Col)
{
// If no column width set then use default
double dWidth = m_aColumns[Col].m_dWidth;
// Comparing with -1 should be ok because no arithmetic performed
if (Col == 0) return 4;
else if (dWidth == -1) return m_dColWidth;
else return dWidth;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CNRDBGrid::SetColor(SS_COORD Col, SS_COORD Row, COLORREF Background,
COLORREF Foreground)
{
//
Invalidate(FALSE);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
COLORREF CNRDBGrid::GetCellColor(SS_COORD Col, SS_COORD Row)
{
if (Col == 0 || Row == 0) return RGB(192, 192, 192);
long n;
if (GetInteger(Col, Row, &n) && n == 0) return RGB(255,255,255);
else return RGB(0,0,250);
}
///////////////////////////////////////////////////////////////////////////////
void CNRDBGrid::PreSubclassWindow()
{
CButton::PreSubclassWindow();
}
///////////////////////////////////////////////////////////////////////////////
void CNRDBGrid::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CString s;
// Determine characer width
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CSize sz = pDC->GetTextExtent("A");
CRect rectC;
CRect rect;
GetClientRect(&rectC);
pDC->SetBkMode(TRANSPARENT);
// Initialise
m_aRectCols.RemoveAll();
m_aRectRows.RemoveAll();
// Use the font
CFont* pFont = CFont::FromHandle(m_hFont);
CFont* pFontOld = pDC->SelectObject(pFont);
// Draw the grid
int y = 0;
int x = 0;
int xMax = 0;
for (int iRow = 0; iRow < m_nRows; iRow++)
{
x = 0;
double dHeight;
GetRowHeight(iRow, &dHeight);
int nHeight = (int)(sz.cy * dHeight * 1.3);
// Allow for scolling
if (iRow != 0 && iRow < m_nFirstVisibleRow) iRow = m_nFirstVisibleRow;
if (y > rectC.bottom) break;
for (int iCol = 0; iCol < m_nCols; iCol++)
{
// Allow for scrolling
if (iCol != 0 && iCol < m_nFirstVisibleCol) iCol = m_nFirstVisibleCol;
// Don't draw if not visible
if (x > rectC.right) break;
if (m_aColumns[iCol].m_bVisible)
{
// Determine column width
int nWidth = (int)(sz.cx * GetColWidth(iCol) * 1.2);
// Draw rectangle
rect.left = x;
rect.right = x + nWidth;
rect.top = y;
rect.bottom = y + nHeight;
COLORREF cr = GetCellColor(iCol, iRow);
COLORREF crT = RGB(0,0,0);
// Check if selected
if ((m_celltopleft.Row <= iRow && iRow <= m_cellbottomright.Row ||
m_celltopleft.Row == -1) &&
(m_celltopleft.Col <= iCol && iCol <= m_cellbottomright.Col ||
m_celltopleft.Col == -1) && !(iRow == m_nActiveRow &&
iCol == m_nActiveCol))
{
// Inverse colour
cr = InverseColor(cr);
crT = InverseColor(crT);
}
pDC->FillSolidRect(rect.left,rect.top, rect.Width(), rect.Height(), cr);
if (iCol == 0 || iRow == 0)
{
pDC->Draw3dRect(rect.left, rect.top, rect.Width()+1, rect.Height()+1,
0,0);
pDC->Draw3dRect(rect.left+1, rect.top+1, rect.Width()-1, rect.Height()-1,
RGB(255,255,255), RGB(128,128,128));
} else
{
pDC->Draw3dRect(rect.left, rect.top, rect.Width()+1, rect.Height()+1,
RGB(192,192,192), RGB(192,192,192));
}
// If cell is active then indicate this
if (iCol == m_nActiveCol && iRow == m_nActiveRow && iCol > 0 && iRow > 0)
{
cr = InverseColor(cr);
pDC->Draw3dRect(rect.left+1, rect.top+1, rect.Width()-2, rect.Height()-2,
cr, cr);
}
// Draw the text - for numbers do not display
if (iRow == 0 || m_aColumns[iCol].m_celltype.m_nType == Edit ||
m_aColumns[iCol].m_celltype.m_nType == Combo)
{
s = GetValue(iCol, iRow);
int nFlags = DT_LEFT|DT_NOPREFIX;
if (iRow == 0 || iCol == 0)
{
if (pDC->GetTextExtent(s).cx < rect.Width())
{
nFlags = DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_CENTER;
} else
{
nFlags = DT_WORDBREAK|DT_NOPREFIX|DT_CENTER;
};
};
// Display row numbers
if (iCol == 0 && iRow != 0) s.Format("%i", iRow);
CRect rectT = rect;
rectT.left += 2;
rectT.top += 2;
pDC->SetTextColor(crT);
pDC->DrawText(s, &rectT, nFlags);
};
// Update the position
x += nWidth;
// Determine approximate number of columns from last drawn
m_nVisibleColumns = (long)(ceil(rectC.Width() / nWidth));
} else
{
rect = CRect();
}
// Store the position of the cell
if (iRow == 0) m_aRectCols.Add(rect);
};
y += nHeight;
xMax = max(x, xMax);
m_nVisibleRows = (long)ceil(rectC.Height() / nHeight);
m_aRectRows.Add(rect);
}
// Clear space to right (more smooth than repainting)
pDC->FillSolidRect(xMax, 0, rectC.right, y, RGB(192,192,192));
pDC->FillSolidRect(0, y, rectC.right, rectC.bottom, RGB(192,192,192));
// Set scroll position
SetScrollRange(SB_HORZ, 1, m_nCols-1, FALSE);
SetScrollPos(SB_HORZ, m_nFirstVisibleCol, TRUE);
SetScrollRange(SB_VERT, 1, m_nRows-1, FALSE);
SetScrollPos(SB_VERT, m_nFirstVisibleRow, TRUE);
// Tidy up
pDC->SelectObject(pFontOld);
}
///////////////////////////////////////////////////////////////////////////////
void CNRDBGrid::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
int nCol = 0;
switch(nSBCode)
{
case SB_LINELEFT:
if (m_nFirstVisibleCol > 1)
{
m_nFirstVisibleCol--;
while (m_nFirstVisibleCol > 1 && !m_aColumns[m_nFirstVisibleCol].m_bVisible) m_nFirstVisibleCol--;
}
else return;
break;
case SB_LINERIGHT:
// Skip hidden
if (m_nFirstVisibleCol+1 < m_nCols)
{
m_nFirstVisibleCol++;
while (m_nFirstVisibleCol+1 < m_nCols && !m_aColumns[m_nFirstVisibleCol].m_bVisible) m_nFirstVisibleCol++;
}
else return;
break;
// page left
case SB_PAGELEFT:
nCol = max(1, m_nFirstVisibleCol - m_nVisibleColumns);
if (nCol != m_nFirstVisibleCol) m_nFirstVisibleCol = nCol;
else return;
break;
// page right
case SB_PAGERIGHT:
nCol = min(m_nCols-1, m_nFirstVisibleCol + m_nVisibleColumns);
if (nCol != m_nFirstVisibleCol) m_nFirstVisibleCol = nCol;
else return;
break;
case SB_THUMBPOSITION:
m_nFirstVisibleCol = nPos;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -