📄 gridctrl.cpp
字号:
case SB_PAGELEFT:
if (scrollPos > 0)
{
rect.left = GetFixedColumnWidth();
int offset = -rect.Width();
int pos = max(0, scrollPos + offset);
SetScrollPos32(SB_HORZ, pos);
rect.left = GetFixedColumnWidth();
InvalidateRect(rect);
}
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
{
SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
m_idTopLeftCell.row = -1;
CCellID idNewTopLeft = GetTopleftNonFixedCell();
if (idNewTopLeft != idTopLeft)
{
rect.left = GetFixedColumnWidth();
InvalidateRect(rect);
}
}
break;
case SB_LEFT:
if (scrollPos > 0)
{
SetScrollPos32(SB_HORZ, 0);
Invalidate();
}
break;
case SB_RIGHT:
if (scrollPos < m_nHScrollMax)
{
SetScrollPos32(SB_HORZ, m_nHScrollMax);
Invalidate();
}
break;
default:
break;
}
// CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}
// Get/Set scroll position using 32 bit functions
int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
if (bGetTrackPos)
{
if (GetScrollInfo(nBar,&si, SIF_TRACKPOS))
return si.nTrackPos;
}
else
{
if (GetScrollInfo(nBar,&si, SIF_POS))
return si.nPos;
}
return 0;
}
BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
{
m_idTopLeftCell.row = -1;
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = nPos;
return SetScrollInfo(nBar, &si, bRedraw);
}
void CGridCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// Get the scroll position ourselves to ensure we get a 32 bit value
int scrollPos = GetScrollPos32(SB_VERT);
CCellID idTopLeft = GetTopleftNonFixedCell();
CRect rect;
GetClientRect(rect);
switch (nSBCode)
{
case SB_LINEDOWN:
if (scrollPos < m_nVScrollMax)
{
// may have contiguous hidden rows. Blow by them
while( idTopLeft.row < (GetRowCount()-1)
&& GetRowHeight( idTopLeft.row) < 1 )
{
idTopLeft.row++;
}
int yScroll = GetRowHeight(idTopLeft.row);
SetScrollPos32(SB_VERT, scrollPos + yScroll);
if (GetScrollPos32(SB_VERT) == scrollPos)
break; // didn't work
rect.top = GetFixedRowHeight();
//rect.top = GetFixedRowHeight() + yScroll;
//ScrollWindow(0, -yScroll, rect);
//rect.top = rect.bottom - yScroll;
InvalidateRect(rect);
}
break;
case SB_LINEUP:
if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount())
{
int iRowToUse = idTopLeft.row-1;
// may have contiguous hidden rows. Blow by them
while( iRowToUse > GetFixedRowCount()
&& GetRowHeight( iRowToUse) < 1 )
{
iRowToUse--;
}
int yScroll = GetRowHeight( iRowToUse);
SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
rect.top = GetFixedRowHeight();
//ScrollWindow(0, yScroll, rect);
//rect.bottom = rect.top + yScroll;
InvalidateRect(rect);
}
break;
case SB_PAGEDOWN:
if (scrollPos < m_nVScrollMax)
{
rect.top = GetFixedRowHeight();
scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
SetScrollPos32(SB_VERT, scrollPos);
rect.top = GetFixedRowHeight();
InvalidateRect(rect);
}
break;
case SB_PAGEUP:
if (scrollPos > 0)
{
rect.top = GetFixedRowHeight();
int offset = -rect.Height();
int pos = max(0, scrollPos + offset);
SetScrollPos32(SB_VERT, pos);
rect.top = GetFixedRowHeight();
InvalidateRect(rect);
}
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
{
SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
m_idTopLeftCell.row = -1;
CCellID idNewTopLeft = GetTopleftNonFixedCell();
if (idNewTopLeft != idTopLeft)
{
rect.top = GetFixedRowHeight();
InvalidateRect(rect);
}
}
break;
case SB_TOP:
if (scrollPos > 0)
{
SetScrollPos32(SB_VERT, 0);
Invalidate();
}
break;
case SB_BOTTOM:
if (scrollPos < m_nVScrollMax)
{
SetScrollPos32(SB_VERT, m_nVScrollMax);
Invalidate();
}
default:
break;
}
// CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}
// Custom background erasure. This gets called from within the OnDraw function,
// 自定义的背景擦除函数,它在OnDraw函数内部被呼叫
// since we will (most likely) be using a memory DC to stop flicker. If we just
// 然后,我们要用一个内存DC来消除闪烁。如果我们只是
// erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
// 正常的通过OnEraseBkgnd函数去擦除背景,而不用颜色填充内存DC
// selected bitmap with colour, then all sorts of vis problems would occur
// 选择的位图,将会出现各式各样的难题。
void CGridCtrl::EraseBkgnd(CDC *pDC)
{
//经过试验,其实要消除闪烁只要在OnEraseBkgnd中什么也不做,而只返回真就行了。
//而这个EraseBkgnd函数的功能完全可以是OnDraw的一部分(因为它本来就是在OnDraw中调用的)。
//但如果不使用内存DC,而只使用本函数又会产生闪烁。
CRect VisRect, ClipRect, rect;
CBrush FixedRowColBack(GetDefaultCell(TRUE, TRUE)->GetBackClr()),
FixedRowBack(GetDefaultCell(TRUE, FALSE)->GetBackClr()),
FixedColBack(GetDefaultCell(FALSE, TRUE)->GetBackClr()),
TextBack(GetDefaultCell(FALSE, FALSE)->GetBackClr());
CBrush Back(GetGridBkColor());
//CBrush Back(GetTextBkColor());
if (pDC->GetClipBox(ClipRect) == ERROR)
return ;
// ClipRect.bottom=ClipRect.bottom-22;
// ClipRect.right=ClipRect.right-22;
GetVisibleNonFixedCellRange(VisRect);
int nFixedColumnWidth = GetFixedColumnWidth();
int nFixedRowHeight = GetFixedRowHeight();
// Draw Fixed row/column background
// 画固定行/列背景:
if (ClipRect.left < nFixedColumnWidth && ClipRect.top < nFixedRowHeight)
pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
nFixedColumnWidth, nFixedRowHeight),
&FixedRowColBack);
// Draw Fixed columns background
// 画固定列背景:
//VisRect.bottom=nFixedRowHeight*GetRowCount();
if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
nFixedColumnWidth, VisRect.bottom),
&FixedColBack);
// Draw Fixed rows background
// 画固定行背景:
if (ClipRect.top < nFixedRowHeight &&
ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
pDC->FillRect(CRect(nFixedColumnWidth-1, ClipRect.top,
VisRect.right, nFixedRowHeight),
&FixedRowBack);
// Draw non-fixed cell background
// 画非固定的单元格背景:
if (rect.IntersectRect(VisRect, ClipRect))
{
CRect CellRect(max(nFixedColumnWidth, rect.left),
max(nFixedRowHeight, rect.top),
rect.right, rect.bottom);
pDC->FillRect(CellRect, &TextBack);
}
// Draw right hand side of window outside grid
// 画右手边外面的背景:
if (VisRect.right < ClipRect.right)
pDC->FillRect(CRect(VisRect.right, ClipRect.top,
ClipRect.right, ClipRect.bottom),
&Back);
// Draw bottom of window below grid
// 画下面的背景:
if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right)
pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
VisRect.right, ClipRect.bottom),
&Back);
}
// Get cell from point.
// point - client coordinates
// bAllowFixedCellCheck - if TRUE then fixed cells are checked
//从鼠标点得到单元格ID:
CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/)
{
CCellID cellID; // return value
CCellID idTopLeft = GetTopleftNonFixedCell();//得到可见范围内最左上角单元格的ID
if (!bAllowFixedCellCheck && !IsValid(idTopLeft))
return cellID;//???
// calculate column index
// 找列号
int fixedColWidth = GetFixedColumnWidth();//得到固定列宽(所有固定列宽的和)
if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window(不在窗口内)
cellID.col = -1;//使cellID非法
else if (point.x < fixedColWidth) // in fixed col(在固定列内)
{
int xpos = 0;
int col = 0;
while (col < m_nFixedCols)//从第0列开始
{
xpos += GetColumnWidth(col);//增加一列的宽
if (xpos > point.x)
break;//如果第一次就跳出,列号col就是0。
col++; //列号增加1
}
//当col=m_nFixedCols时循环结束,所以最后一次是col=m_nFixedCols。
cellID.col = col;//最后得到列号
//CString str;
//str.Format("%d",col);
//MessageBox(str);
}
else // in non-fixed col(在非固定列)
{
int xpos = fixedColWidth;//固定列宽(所有固定列宽的和)
int col = idTopLeft.col; //左上角非固定单元格,其值=m_nFixedCols;
while ( col < GetColumnCount())//GetColumnCount返回总列数
{
xpos += GetColumnWidth(col);////增加一列的宽
if (xpos > point.x)
break;//如果第一次就跳出,列号col就是左上角非固定单元格,其值=m_nFixedCols;
col++;//列号增加1
}
//当col=GetColumnCount()时循环结束,所以最后是col=GetColumnCount()。
//但是col是从0开始的,如果到col=GetColumnCount()会多一列。
//所以需要修正:
if (col >= GetColumnCount())//
cellID.col = -1;
else
cellID.col = col;
}
// calculate row index
// 找行号(类似找列号,注释略)
int fixedRowHeight = GetFixedRowHeight();//得到固定行的高(所有固定行的高的和)
if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window(不在窗口内)
cellID.row = -1;//使cellID非法
else if (point.y < fixedRowHeight) // in fixed col(在固定列)
{
int ypos = 0;
int row = 0;
while (row < m_nFixedRows)
{
ypos += GetRowHeight(row);
if (ypos > point.y)
break;
row++;
}
cellID.row = row;
}
else
{
int ypos = fixedRowHeight;
int row = idTopLeft.row; //m_nFixedRows;
while ( row < GetRowCount() )
{
ypos += GetRowHeight(row);
if (ypos > point.y)
break;
row++;
}
if (row >= GetRowCount())
cellID.row = -1;
else
cellID.row = row;
}
return cellID;//返回单元格ID
}
// Is a given cell designation valid (ie within the bounds of our number
// of columns/rows)?
//合法性检验
BOOL CGridCtrl::IsValid(int nRow, int nCol) const
{
return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
}
BOOL CGridCtrl::IsValid(const CCellID& cell) const
{
return IsValid(cell.row, cell.col);
}
// Is a given cell range valid (ie within the bounds of our number
// of columns/rows)?
BOOL CGridCtrl::IsValid(const CCellRange& range) const
{
return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
}
void CGridCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
int leftcol=(m_LeftClickDownCell.col-1)>0 ? (m_LeftClickDownCell.col-1) : 0;//左边的列
int leftrow=m_LeftClickDownCell.row;
CRect leftrc;
GetCellRect(leftrow,leftcol,leftrc);
int left;
if(leftcol==0)
{
left=0;
}
else
{
left=leftrc.right;
}
CRect rect;
GetClientRect(rect);
if( MouseOverColumnResizeArea(point))
{
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
//m_LastMousePoint = point;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -