📄 gridctrl.cpp
字号:
bResult = FALSE;
}
END_CATCH
m_nCols = nCols;
// SetModified();
ResetScrollBars();//重值滚动条
Refresh();
return bResult;
}
BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
{
ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
if (nCol < 0 || nCol >= m_nCols || width < 0)
return FALSE;
m_arColWidths[nCol] = width;
ResetScrollBars();
return TRUE;
}
void CGridCtrl::Refresh()
{
if (GetSafeHwnd() && m_bAllowDraw)
Invalidate();
}
// Creates a new grid cell and performs any necessary initialisation
/*virtual*/ CGridCellBase* CGridCtrl::CreateCell(int nRow, int nCol)
{
// ASSERT(!GetVirtualMode());
if (!m_pRtcDefault || !m_pRtcDefault->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
//IsDerivedFrom是CRuntimeClass的一个检验函数,
//判断m_pRtcDefault是否是指定类的派生类.
{
ASSERT( FALSE);
return NULL;
}
//这起到类型识别和类型检验的作用
CGridCellBase* pCell = (CGridCellBase*) m_pRtcDefault->CreateObject();
//m_pRtcDefault在初始化时被RUNTIME_CLASS宏绑定到CGridCell类,
//所以这实际是用一个基类指针指向一个派生类对象(动态生成)
//实际使用如下语句似乎也可以:
//CGridCellBase* pCell = (CGridCellBase*) new CGridCell;
if (!pCell)
return NULL;
pCell->SetGrid(this);
// pCell->SetCoords(nRow, nCol);
if (nCol < m_nFixedCols)//pCell就是固定列
pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDCOL);//是m_nState和GVIS_FIXED | GVIS_FIXEDCOL的运算结果
//所以m_nState是在这里改变的
if (nRow < m_nFixedRows)//pCell就是固定行
pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDROW);//是m_nState和GVIS_FIXED | GVIS_FIXEDROW的运算结果
//所以m_nState是在这里改变的
// pCell->SetFormat(pCell->GetDefaultCell()->GetFormat());
return pCell;//这是非固定的单元格,其m_nState就是0;
}
/*virtual*/ void CGridCtrl::DestroyCell(int nRow, int nCol)
{
// Should NEVER get here in virtual mode.
// ASSERT(!GetVirtualMode());
// Set the cells state to 0. If the cell is selected, this
// will remove the cell from the selected list.
SetItemState(nRow, nCol, 0);
delete GetCell(nRow, nCol);
}
BOOL CGridCtrl::SetItemBkColor(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
{
// if (GetVirtualMode())
// return FALSE;
CGridCellBase* pCell = GetCell(nRow, nCol);
ASSERT(pCell);
if (!pCell)
return FALSE;
pCell->SetBackClr(cr);
return TRUE;
}
BOOL CGridCtrl::SetItemFgColor(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
{
CGridCellBase* pCell = GetCell(nRow, nCol);
// ASSERT(pCell);
if (!pCell)
return FALSE;
pCell->SetTextClr(cr);
return TRUE;
}
BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
{
CGridCellBase* pCell = GetCell(nRow, nCol);
ASSERT(pCell);
if (!pCell)
return FALSE;
// Set the cell's state
pCell->SetState(state);
return TRUE;
}
UINT CGridCtrl::GetItemState(int nRow, int nCol) const
{
CGridCellBase* pCell = GetCell(nRow, nCol);
ASSERT(pCell);
if (!pCell)
return 0;
return pCell->GetState();
}
void CGridCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (m_bDoubleBuffer) // Use a memory DC to remove flicker
// 使用内存DC消除闪烁
{
CMemDC MemDC(&dc);
OnDraw(&MemDC);
}
else // Draw raw - this helps in debugging vis problems.
OnDraw(&dc);
// Do not call CWnd::OnPaint() for painting messages
}
void CGridCtrl::OnDraw(CDC* pDC)
{
if (!m_bAllowDraw)
return;
CRect clipRect;
if (pDC->GetClipBox(&clipRect) == ERROR)
return;
GetClientRect(&clipRect);
EraseBkgnd(pDC);
CRect rect;
int row, col;
CGridCellBase* pCell;
int nFixedRowHeight = GetFixedRowHeight();
int nFixedColWidth = GetFixedColumnWidth();
CCellID idTopLeft = GetTopleftNonFixedCell();//左上角非固定单元格ID(包含行号和列号)
int minVisibleRow = idTopLeft.row,//最小可见的行号
minVisibleCol = idTopLeft.col;//最小可见的列号
CRect VisRect;
CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);//可见单元格的范围
//同时初始化VisRect
int maxVisibleRow = VisCellRange.GetMaxRow(),//最大可见的行号
maxVisibleCol = VisCellRange.GetMaxCol();//最大可见的列号
// draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
// 画左上角单元格(也可能是几行几列)
//(第一行:一列,一列...,第二行:一列,一列....);
rect.bottom = -1;
for (row = 0; row < m_nFixedRows; row++)
{
if (GetRowHeight(row) <= 0) continue;//不执行下面语句,直接到下一循环
rect.top = rect.bottom+1;//有这一行,就不会因下一行的操作
//而使单元格越画越窄了
rect.bottom = rect.top + GetRowHeight(row)-1;//增加一个行高
rect.right = -1;
for (col = 0; col < m_nFixedCols; col++)
{
if (GetColumnWidth(col) <= 0) continue;
rect.left = rect.right+1;//有这一行,就不会因下一行的操作
//而使单元格越画越窄了
rect.right = rect.left + GetColumnWidth(col)-1;//增加一个列宽
pCell = GetCell(row, col);
if (pCell)
{
// pCell->SetCoords(row,col);//这是一个空函数,目前没有用
pCell->Draw(pDC, row, col, rect, FALSE);
}
}
}
//////////////////////////////////////////////////////////////////////////////////
// draw fixed column cells: m_nFixedRows..n, 0..m_nFixedCols-1
//画固定的列(行标头):(第一行:一列,一列...,第二行:一列,一列....);
rect.bottom = nFixedRowHeight-1;
for (row = minVisibleRow; row <= maxVisibleRow; row++)
{
if (GetRowHeight(row) <= 0) continue;
rect.top = rect.bottom+1;
rect.bottom = rect.top + GetRowHeight(row)-1;
// rect.bottom = bottom pixel of previous row
if (rect.top > clipRect.bottom)
break; // Gone past cliprect
if (rect.bottom < clipRect.top)
continue; // Reached cliprect yet?
rect.right = -1;
for (col = 0; col < m_nFixedCols; col++)
{
if (GetColumnWidth(col) <= 0) continue;
rect.left = rect.right+1;
rect.right = rect.left + GetColumnWidth(col)-1;
if (rect.left > clipRect.right)
break; // gone past cliprect
if (rect.right < clipRect.left)
continue; // Reached cliprect yet?
pCell = GetCell(row, col);
if (pCell)
{
if(col==0)
{
CString str;
str.Format("%d",row);
pCell->SetText(str);
}
pCell->Draw(pDC, row, col, rect, FALSE);
}
}
}
/////////////////////////////////////////////////////////////
// draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
//画固定的行(列标头):(第一行:一列,一列...,第二行:一列,一列....);
rect.bottom = -1;
for (row = 0; row < m_nFixedRows; row++)
{
if (GetRowHeight(row) <= 0) continue;
rect.top = rect.bottom+1;
rect.bottom = rect.top + GetRowHeight(row)-1;
// rect.bottom = bottom pixel of previous row
if (rect.top > clipRect.bottom)
break; // Gone past cliprect
if (rect.bottom < clipRect.top)
continue; // Reached cliprect yet?
rect.right = nFixedColWidth-1;
for (col = minVisibleCol; col <= maxVisibleCol; col++)
{
if (GetColumnWidth(col) <= 0) continue;
rect.left = rect.right+1;
rect.right = rect.left + GetColumnWidth(col)-1;
if (rect.left > clipRect.right)
break; // gone past cliprect
if (rect.right < clipRect.left)
continue; // Reached cliprect yet?
pCell = GetCell(row, col);
if (pCell)
{
pCell->Draw(pDC, row, col, rect, FALSE);
}
}
}
///////////////////////////////////////////////////////////////////
// draw rest of non-fixed cells
//画剩余的非固定的单元格:(第一行:一列,一列...,第二行:一列,一列....);
rect.bottom = nFixedRowHeight-1;
for (row = minVisibleRow; row <= maxVisibleRow; row++)
{
if (GetRowHeight(row) <= 0) continue;
rect.top = rect.bottom+1;
rect.bottom = rect.top + GetRowHeight(row)-1;
// rect.bottom = bottom pixel of previous row
if (rect.top > clipRect.bottom)
break; // Gone past cliprect
if (rect.bottom < clipRect.top)
continue; // Reached cliprect yet?
rect.right = nFixedColWidth-1;
for (col = minVisibleCol; col <= maxVisibleCol; col++)
{
if (GetColumnWidth(col) <= 0) continue;
rect.left = rect.right+1;
rect.right = rect.left + GetColumnWidth(col)-1;
if (rect.left > clipRect.right)
break; // gone past cliprect
if (rect.right < clipRect.left)
continue; // Reached cliprect yet?
pCell = GetCell(row, col);
// TRACE(_T("Cell %d,%d type: %s\n"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
if (pCell)
{
pCell->Draw(pDC, row, col, rect, FALSE);
}
}
}
CPen pen;
pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
pDC->SelectObject(&pen);
// draw vertical lines (drawn at ends of cells)
//画垂直分隔线:
if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
{
int x = nFixedColWidth;
for (col =minVisibleCol; col <= maxVisibleCol; col++)
{
if (GetColumnWidth(col) <= 0) continue;
x += GetColumnWidth(col);
pDC->MoveTo(x-1, nFixedRowHeight);
pDC->LineTo(x-1, rect.bottom);
}
}
// draw horizontal lines (drawn at bottom of each cell)
//画水平分隔线
if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
{
int y = nFixedRowHeight;
for (row = minVisibleRow; row <= maxVisibleRow; row++)
{
if (GetRowHeight(row) <= 0) continue;
y += GetRowHeight(row);
pDC->MoveTo(nFixedColWidth, y-1);
pDC->LineTo(rect.right, y-1);
}
}
pDC->SelectStockObject(NULL_PEN);
}
int CGridCtrl::GetFixedRowHeight() const
{
int nHeight = 0;
for (int i = 0; i < m_nFixedRows; i++)
nHeight += GetRowHeight(i);
return nHeight;
}
int CGridCtrl::GetFixedColumnWidth() const
{
int nWidth = 0;
for (int i = 0; i < m_nFixedCols; i++)
nWidth += GetColumnWidth(i);
return nWidth;
}
int CGridCtrl::GetRowHeight(int nRow) const
{
ASSERT(nRow >= 0 && nRow < m_nRows);
if (nRow < 0 || nRow >= m_nRows)
return -1;
return m_arRowHeights[nRow];
}
int CGridCtrl::GetColumnWidth(int nCol) const
{
ASSERT(nCol >= 0 && nCol < m_nCols);
if (nCol < 0 || nCol >= m_nCols)
return -1;
return m_arColWidths[nCol];
}
// Gets the first non-fixed cell ID
CCellID CGridCtrl::GetTopleftNonFixedCell(BOOL bForceRecalculation /*=FALSE*/)
{
// Used cached value if possible
// 如果可能使用保存的值
if (m_idTopLeftCell.IsValid() && !bForceRecalculation)//因为bForceRecalculation却省为假
//所以只要IsValid()返回真就执行
return m_idTopLeftCell;
int nVertScroll =GetScrollPos(SB_VERT), //没有滚动条或没有设置初始位置或没有滚动,
nHorzScroll =GetScrollPos(SB_HORZ); //会返回0值
m_idTopLeftCell.col = m_nFixedCols;//先赋值(却省情况下这是当然的)
int nRight = 0;
//这个循环比较特别,主要目的是要作m_idTopLeftCell.col++的操作,
//因为各列的宽可能不一样,不能对计数器nRight简单的++,
//因为nHorzScroll是以屏幕像素为单位的。
while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount()-1))
nRight += GetColumnWidth(m_idTopLeftCell.col++);//作m_idTopLeftCell.col++操作
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -