GridCtrl.cpp
上传用户:wenjimin
上传日期:2014-08-12
资源大小:111k
文件大小:67k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. // GridCtrl.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "MemDC.h"
  5. #include "GridCtrl.h"
  6. #include "MyGridFrame.h"
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CGridCtrl
  14. IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
  15. CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
  16. {
  17.     m_crWindowText        = ::GetSysColor(COLOR_WINDOWTEXT);
  18.     m_crWindowColour      = ::GetSysColor(COLOR_WINDOW);
  19.     m_cr3DFace            = ::GetSysColor(COLOR_3DFACE);
  20.     m_crShadow            = ::GetSysColor(COLOR_3DSHADOW);
  21.     m_crGridLineColour    = RGB(192,192,192);
  22. m_nRows               = 0;
  23.     m_nCols               = 0;
  24.     m_nFixedRows          = 0;
  25.     m_nFixedCols          = 0;
  26. // m_bFixedColumnSelection = TRUE;
  27. //  m_bFixedRowSelection  = TRUE;
  28. m_nVScrollMax         = 0;          // Scroll position 滚动指针
  29.     m_nHScrollMax         = 0;
  30. m_bSortOnClick        = FALSE;      // Sort on header row click
  31. m_bAscending          = TRUE;       // sorting stuff 排序...
  32. m_nSortColumn         = 1;
  33. #ifdef _WIN32_WCE
  34.     m_bDoubleBuffer       = FALSE;      // Use double buffering to avoid flicker?
  35.                                     // 使用双缓冲消除闪烁
  36. #else
  37.     m_bDoubleBuffer       = TRUE;       // Use double buffering to avoid flicker?
  38.                                     // 使用双缓冲消除闪烁
  39. #endif
  40.     m_nGridLines          = GVL_BOTH;  //表格线
  41. m_nBarState           = GVL_NONE;  //
  42. m_bColSizing          = FALSE;     //列Sizing状态
  43. m_bAllowDraw          = TRUE;       // allow draw updates  全部重画
  44. m_bAllowColHide       = TRUE;       // Columns can be contracted to 0-width via mouse
  45.     m_bAllowRowHide       = TRUE;       // Rows can be contracted to 0-height via mouse
  46.   
  47.     m_pRtcDefault = RUNTIME_CLASS(CGridCell);
  48. m_nResizeCaptureRange = 3;          // When resizing columns/row, the cursor has to be
  49.                                     //当改变行/列尺寸时,光标在分隔线
  50.                                         // within +/-3 pixels of the dividing line for
  51.                                     //左右+/-3个象素之内
  52.                                         // resizing to be possible
  53.                                     //可以改变尺寸
  54.     
  55. m_FillRect.top=m_FillRect.left=m_FillRect.bottom=m_FillRect.right=0;
  56.     
  57. m_pfnCompare   = NULL;
  58. SetGridBkColor(m_crShadow);
  59. SetupDefaultCells();//装载缺省的单元格数据(字体、颜色的信息)
  60.                     //也就是对m_cellDefault等几个变量的初始化
  61.                     //所以也就可以理解GetDefaultCell()的返回值了.
  62.     // Set up the initial grid size
  63. // 装配最初的表格尺寸
  64.     SetRowCount(nRows);
  65.     SetColumnCount(nCols);
  66. SetFixedRowCount(nFixedRows);
  67.     SetFixedColumnCount(nFixedCols);
  68.     // set initial selection range (ie. none)
  69. //    m_SelectedCellMap.RemoveAll();
  70. //    m_PrevSelectedCellMap.RemoveAll();
  71. }
  72. CGridCtrl::~CGridCtrl()
  73. {
  74. //KillTimer(2);
  75. }
  76. BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
  77. //{{AFX_MSG_MAP(CGridCtrl)
  78. ON_WM_PAINT()
  79. ON_WM_ERASEBKGND()
  80. ON_WM_LBUTTONDOWN()
  81. ON_WM_SIZE()
  82. ON_WM_HSCROLL()
  83. ON_WM_VSCROLL()
  84. ON_WM_MOUSEMOVE()
  85. ON_WM_LBUTTONUP()
  86. ON_WM_CREATE()
  87. ON_WM_LBUTTONDBLCLK()
  88. ON_WM_TIMER()
  89. ON_WM_DESTROY()
  90. //}}AFX_MSG_MAP
  91. END_MESSAGE_MAP()
  92. /////////////////////////////////////////////////////////////////////////////
  93. // CGridCtrl message handlers
  94. void CGridCtrl::SetupDefaultCells()
  95. {
  96.     m_cellDefault.SetGrid(this);            // Normal editable cell
  97. //原型是SetGrid(CGridCtrl* pGrid),因为现在就在CGridCtrl类里面,所以可以用this
  98. //另外,CGridDefaultCell继承自CGridCell,且没有改写SetGrid()函数,所以,其实是调用
  99. //CGridCell的SetGrid()函数.
  100. //又因为原型是SetGrid(CGridCtrl* pGrid),而CGridCtrl继承自CWnd,所以,参数其实是要一个
  101. //窗口指针(父窗口?)
  102.     m_cellFixedColDef.SetGrid(this);        // Cell for fixed columns
  103.     m_cellFixedRowDef.SetGrid(this);        // Cell for fixed rows
  104.     m_cellFixedRowColDef.SetGrid(this);     // Cell for area overlapped by fixed columns/rows
  105.     m_cellDefault.SetTextClr(m_crWindowText);   
  106.     m_cellDefault.SetBackClr(m_crWindowColour); 
  107.     m_cellFixedColDef.SetTextClr(m_crWindowText);
  108.     m_cellFixedColDef.SetBackClr(m_cr3DFace);
  109.     m_cellFixedRowDef.SetTextClr(m_crWindowText);
  110.     m_cellFixedRowDef.SetBackClr(m_cr3DFace);
  111.     m_cellFixedRowColDef.SetTextClr(m_crWindowText);
  112.     m_cellFixedRowColDef.SetBackClr(m_cr3DFace);
  113. }
  114. BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
  115. {
  116.     if (m_nFixedRows == nFixedRows)
  117.         return TRUE;
  118.     ASSERT(nFixedRows >= 0);
  119. //    ResetSelectedRange();
  120.     // Force recalculation
  121.     m_idTopLeftCell.col = -1;
  122.     if (nFixedRows > GetRowCount())
  123.         if (!SetRowCount(nFixedRows))
  124.             return FALSE;
  125.         
  126. //        if (m_idCurrentCell.row < nFixedRows)
  127. //            SetFocusCell(-1, - 1);
  128.         
  129.         if (1/*!GetVirtualMode()*/)
  130.         {
  131.             if (nFixedRows > m_nFixedRows)
  132.             {
  133.                 for (int i = m_nFixedRows; i < nFixedRows; i++)
  134.                     for (int j = 0; j < GetColumnCount(); j++)
  135.                     {
  136.                         SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDROW);//m_nState是在这里改变的
  137.                         SetItemBkColor(i, j, CLR_DEFAULT );
  138.                         SetItemFgColor(i, j, CLR_DEFAULT );
  139.                     }
  140.             }
  141.             else
  142.             {
  143.                 for (int i = nFixedRows; i < m_nFixedRows; i++)
  144.                 {
  145.                     int j;
  146.                     for (j = 0; j < GetFixedColumnCount(); j++)
  147.                         SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDROW );
  148.                     for (j = GetFixedColumnCount(); j < GetColumnCount(); j++)
  149.                     {
  150.                         SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDROW) );
  151.                         SetItemBkColor(i, j, CLR_DEFAULT );
  152.                         SetItemFgColor(i, j, CLR_DEFAULT );
  153.                     }
  154.                 }
  155.             }
  156.         }
  157.         m_nFixedRows = nFixedRows;
  158.         
  159.         Refresh();
  160.         
  161.         return TRUE;
  162. }
  163. BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
  164. {
  165.     if (m_nFixedCols == nFixedCols)
  166.         return TRUE;
  167.     ASSERT(nFixedCols >= 0);
  168.     if (nFixedCols > GetColumnCount())
  169.         if (!SetColumnCount(nFixedCols))
  170.             return FALSE;
  171. //    if (m_idCurrentCell.col < nFixedCols)
  172. //        SetFocusCell(-1, - 1);
  173. //    ResetSelectedRange();
  174.     // Force recalculation
  175.     m_idTopLeftCell.col = -1;
  176.     if (1/*!GetVirtualMode()*/)
  177.     {
  178.         if (nFixedCols > m_nFixedCols)
  179.         {
  180.             for (int i = 0; i < GetRowCount(); i++)
  181.                 for (int j = m_nFixedCols; j < nFixedCols; j++)
  182.                 {
  183.                     SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDCOL);
  184.                     SetItemBkColor(i, j, CLR_DEFAULT );
  185.                     SetItemFgColor(i, j, CLR_DEFAULT );
  186.                 }
  187.         }
  188.         else
  189.         {
  190. { // Scope limit i,j
  191.             for (int i = 0; i < GetFixedRowCount(); i++)
  192.             for (int j = nFixedCols; j < m_nFixedCols; j++)
  193.             SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDCOL );
  194. }
  195. {// Scope limit i,j
  196.             for (int i = GetFixedRowCount(); i < GetRowCount(); i++)
  197.             for (int j = nFixedCols; j < m_nFixedCols; j++)
  198.         {
  199.         SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDCOL) );
  200.     SetItemBkColor(i, j, CLR_DEFAULT );
  201. SetItemFgColor(i, j, CLR_DEFAULT );
  202.                 }
  203. }
  204.         }
  205.     }
  206.         
  207.     m_nFixedCols = nFixedCols;
  208.         
  209.     Refresh();
  210.         
  211.     return TRUE;
  212. }
  213. BOOL CGridCtrl::SetRowCount(int nRows)
  214. {
  215.     BOOL bResult = TRUE;
  216.     ASSERT(nRows >= 0);
  217.     if (nRows == GetRowCount())//新行数=总行数
  218.         return bResult;
  219.     // Force recalculation
  220. //    m_idTopLeftCell.col = -1;
  221.     if (nRows < m_nFixedRows)
  222.         m_nFixedRows = nRows;
  223. //    if (m_idCurrentCell.row >= nRows)
  224. //        SetFocusCell(-1, - 1);
  225.     int addedRows = nRows - GetRowCount();//增加的行数
  226.     // If we are about to lose rows, then we need to delete the GridCell objects
  227.     // in each column within each row
  228.     if (addedRows < 0)//如果增加的行数<0(有多余的行)
  229.     {
  230.         //删掉它们:
  231.             for (int row = nRows; row < m_nRows; row++)//删掉新行后面的行
  232.             {
  233.                 // Delete cells
  234. //删掉单元格
  235.                 for (int col = 0; col < m_nCols; col++)
  236.                     DestroyCell(row, col);
  237.             
  238.                 // Delete rows
  239. //删掉行
  240.                 GRID_ROW* pRow = m_RowData[row];
  241.                 if (pRow)
  242.                     delete pRow;//删掉数组中的一个元素
  243.             }
  244.         
  245.         m_nRows = nRows;//完成新设置
  246.     }
  247.     
  248.     TRY
  249.     {
  250.         m_arRowHeights.SetSize(nRows);//记录行高的数组
  251.           // Change the number of rows.
  252.             m_RowData.SetSize(nRows);//记录每行单元格的数组(在这里对m_RowData初始化!!!)
  253.             // If we have just added rows, we need to construct new elements for each cell
  254.             // and set the default row height
  255.             if (addedRows > 0)
  256.             {
  257.                 // initialize row heights and data
  258.                 int startRow = nRows - addedRows;
  259.                 for (int row = startRow; row < nRows; row++)
  260.                 {
  261.                     m_arRowHeights[row] = m_cellDefault.GetHeight();
  262.                     m_RowData[row] = new GRID_ROW;//创建了m_RowData的一个元素
  263.                     m_RowData[row]->SetSize(m_nCols);//对这个元素的初始化(因为它也是一个数组)
  264.                     for (int col = 0; col < m_nCols; col++)
  265.                     {
  266.                         GRID_ROW* pRow = m_RowData[row];
  267.                         if (pRow && 1/*!GetVirtualMode()*/)
  268.                             pRow->SetAt(col, CreateCell(row, col));//对数祖赋值
  269.                     }
  270.                     m_nRows++;
  271.                 }
  272.             }
  273.         
  274. }
  275.     CATCH (CMemoryException, e)
  276.     {
  277.         e->ReportError();
  278.         bResult = FALSE;
  279.     }
  280.     END_CATCH
  281. //    SetModified();
  282.     ResetScrollBars();
  283.     Refresh();
  284.     return bResult;
  285. }
  286. BOOL CGridCtrl::SetColumnCount(int nCols)
  287. {
  288.     BOOL bResult = TRUE;
  289.     ASSERT(nCols >= 0);
  290.     if (nCols == GetColumnCount())
  291.         return bResult;
  292.     // Force recalculation
  293. //    m_idTopLeftCell.col = -1;//一个CCellID型的变量
  294.     if (nCols < m_nFixedCols)
  295.         m_nFixedCols = nCols;
  296. //    if (m_idCurrentCell.col >= nCols)
  297. //        SetFocusCell(-1, - 1);
  298.     int addedCols = nCols - GetColumnCount();
  299.     // If we are about to lose columns, then we need to delete the GridCell objects
  300.     // within each column
  301.     if (addedCols < 0 /*&& !GetVirtualMode()*/)
  302.     {
  303.         for (int row = 0; row < m_nRows; row++)
  304.             for (int col = nCols; col < GetColumnCount(); col++)
  305.                 DestroyCell(row, col);
  306.     }
  307.     TRY 
  308.     {
  309.         // Change the number of columns.
  310.         m_arColWidths.SetSize(nCols);
  311.     
  312.         // Change the number of columns in each row.
  313.         if (1/*!GetVirtualMode()*/)
  314.             for (int i = 0; i < m_nRows; i++)
  315.                 if (m_RowData[i])
  316.                     m_RowData[i]->SetSize(nCols);
  317.         
  318.         // If we have just added columns, we need to construct new elements for each cell
  319.         // and set the default column width
  320.         if (addedCols > 0)
  321.         {
  322.             // initialized column widths
  323.             int startCol = nCols - addedCols;
  324.             for (int col = startCol; col < nCols; col++)
  325.                 m_arColWidths[col] = m_cellFixedColDef.GetWidth();
  326.         
  327.             // initialise column data
  328.             if (1/*!GetVirtualMode()*/)
  329.             {
  330.                 for (int row = 0; row < m_nRows; row++)
  331.                     for (col = startCol; col < nCols; col++)
  332.                     {
  333.                         GRID_ROW* pRow = m_RowData[row];
  334.                         if (pRow)
  335. {
  336.       pRow->SetAt(col, CreateCell(row, col));
  337. }
  338.                     }
  339.             }
  340.         }
  341.         // else    // check for selected cell ranges
  342.         //    ResetSelectedRange();
  343.     }
  344.     CATCH (CMemoryException, e)
  345.     {
  346.         e->ReportError();
  347.         bResult = FALSE;
  348.     }
  349.     END_CATCH
  350.     m_nCols = nCols;
  351. //    SetModified();
  352.     ResetScrollBars();//重值滚动条
  353.     Refresh();
  354.     return bResult;
  355. }
  356. BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
  357. {
  358.     ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
  359.     if (nCol < 0 || nCol >= m_nCols || width < 0)
  360.         return FALSE;
  361.     m_arColWidths[nCol] = width;
  362.     ResetScrollBars();
  363.     return TRUE;
  364. }
  365. void CGridCtrl::Refresh()
  366. {
  367.     if (GetSafeHwnd() && m_bAllowDraw)
  368.         Invalidate();
  369. }
  370. // Creates a new grid cell and performs any necessary initialisation
  371. /*virtual*/ CGridCellBase* CGridCtrl::CreateCell(int nRow, int nCol)
  372. {
  373. //    ASSERT(!GetVirtualMode());
  374.     if (!m_pRtcDefault || !m_pRtcDefault->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  375. //IsDerivedFrom是CRuntimeClass的一个检验函数,
  376. //判断m_pRtcDefault是否是指定类的派生类.
  377.     {
  378.         ASSERT( FALSE);
  379.         return NULL;
  380.     }
  381. //这起到类型识别和类型检验的作用
  382.     CGridCellBase* pCell = (CGridCellBase*) m_pRtcDefault->CreateObject();
  383. //m_pRtcDefault在初始化时被RUNTIME_CLASS宏绑定到CGridCell类,
  384. //所以这实际是用一个基类指针指向一个派生类对象(动态生成)
  385. //实际使用如下语句似乎也可以:
  386. //CGridCellBase* pCell = (CGridCellBase*) new CGridCell;
  387.     if (!pCell)
  388.         return NULL;
  389.     pCell->SetGrid(this);
  390. //    pCell->SetCoords(nRow, nCol); 
  391.     if (nCol < m_nFixedCols)//pCell就是固定列
  392.         pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDCOL);//是m_nState和GVIS_FIXED | GVIS_FIXEDCOL的运算结果
  393.                                                                     //所以m_nState是在这里改变的
  394.     if (nRow < m_nFixedRows)//pCell就是固定行
  395.         pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDROW);//是m_nState和GVIS_FIXED | GVIS_FIXEDROW的运算结果
  396.                                                                     //所以m_nState是在这里改变的
  397.     
  398. //    pCell->SetFormat(pCell->GetDefaultCell()->GetFormat());
  399.     return pCell;//这是非固定的单元格,其m_nState就是0;
  400. }
  401. /*virtual*/ void CGridCtrl::DestroyCell(int nRow, int nCol)
  402. {
  403.     // Should NEVER get here in virtual mode.
  404. //    ASSERT(!GetVirtualMode());
  405.     // Set the cells state to 0. If the cell is selected, this
  406.     // will remove the cell from the selected list.
  407.     SetItemState(nRow, nCol, 0);
  408.     delete GetCell(nRow, nCol);
  409. }
  410. BOOL CGridCtrl::SetItemBkColor(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  411. {
  412. //    if (GetVirtualMode())
  413. //        return FALSE;
  414.     CGridCellBase* pCell = GetCell(nRow, nCol);
  415.     ASSERT(pCell);
  416.     if (!pCell)
  417.         return FALSE;
  418.     pCell->SetBackClr(cr);
  419.     return TRUE;
  420. }
  421. BOOL CGridCtrl::SetItemFgColor(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  422. {
  423.     CGridCellBase* pCell = GetCell(nRow, nCol);
  424. //    ASSERT(pCell);
  425.     if (!pCell)
  426.         return FALSE;
  427.     
  428.     pCell->SetTextClr(cr);
  429.     return TRUE;
  430. }
  431. BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
  432. {
  433.     CGridCellBase* pCell = GetCell(nRow, nCol);
  434.     ASSERT(pCell);
  435.     if (!pCell)
  436.         return FALSE;
  437.     // Set the cell's state
  438.     pCell->SetState(state);
  439.     return TRUE;
  440. }
  441. UINT CGridCtrl::GetItemState(int nRow, int nCol) const
  442. {
  443.     CGridCellBase* pCell = GetCell(nRow, nCol);
  444.     ASSERT(pCell);
  445.     if (!pCell)
  446.         return 0;
  447.     return pCell->GetState();
  448. }
  449. void CGridCtrl::OnPaint() 
  450. {
  451. CPaintDC dc(this); // device context for painting
  452.    if (m_bDoubleBuffer)    // Use a memory DC to remove flicker
  453.                        // 使用内存DC消除闪烁
  454.     {
  455.         CMemDC MemDC(&dc);
  456.         OnDraw(&MemDC);
  457.     }
  458.     else                    // Draw raw - this helps in debugging vis problems.
  459.         OnDraw(&dc);
  460. // Do not call CWnd::OnPaint() for painting messages
  461. }
  462. void CGridCtrl::OnDraw(CDC* pDC)
  463. {
  464. if (!m_bAllowDraw)
  465.         return;
  466.     CRect clipRect;
  467.     if (pDC->GetClipBox(&clipRect) == ERROR)
  468.         return;
  469. GetClientRect(&clipRect);
  470.     EraseBkgnd(pDC);
  471. CRect rect;
  472.     int row, col;
  473.     CGridCellBase* pCell;
  474.     int nFixedRowHeight = GetFixedRowHeight();
  475.     int nFixedColWidth  = GetFixedColumnWidth();
  476. CCellID idTopLeft = GetTopleftNonFixedCell();//左上角非固定单元格ID(包含行号和列号)
  477.     int minVisibleRow = idTopLeft.row,//最小可见的行号
  478.         minVisibleCol = idTopLeft.col;//最小可见的列号
  479. CRect VisRect;
  480.     CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);//可见单元格的范围
  481.                                                                //同时初始化VisRect
  482.     int maxVisibleRow = VisCellRange.GetMaxRow(),//最大可见的行号
  483.         maxVisibleCol = VisCellRange.GetMaxCol();//最大可见的列号
  484. // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
  485. // 画左上角单元格(也可能是几行几列)
  486. //(第一行:一列,一列...,第二行:一列,一列....);
  487.     rect.bottom = -1;
  488.     for (row = 0; row < m_nFixedRows; row++)
  489.     {
  490.         if (GetRowHeight(row) <= 0) continue;//不执行下面语句,直接到下一循环
  491.         rect.top = rect.bottom+1;//有这一行,就不会因下一行的操作
  492.                          //而使单元格越画越窄了
  493.         rect.bottom = rect.top + GetRowHeight(row)-1;//增加一个行高
  494.         rect.right = -1;
  495.         for (col = 0; col < m_nFixedCols; col++)
  496.         {
  497.             if (GetColumnWidth(col) <= 0) continue;
  498.             rect.left = rect.right+1;//有这一行,就不会因下一行的操作
  499.                              //而使单元格越画越窄了
  500.             rect.right = rect.left + GetColumnWidth(col)-1;//增加一个列宽
  501.             pCell = GetCell(row, col);
  502.             if (pCell)
  503. {
  504. // pCell->SetCoords(row,col);//这是一个空函数,目前没有用
  505.                 pCell->Draw(pDC, row, col, rect, FALSE);
  506. }
  507.         }
  508.     }
  509. //////////////////////////////////////////////////////////////////////////////////
  510. // draw fixed column cells:  m_nFixedRows..n, 0..m_nFixedCols-1
  511. //画固定的列(行标头):(第一行:一列,一列...,第二行:一列,一列....);
  512. rect.bottom = nFixedRowHeight-1;
  513.     for (row = minVisibleRow; row <= maxVisibleRow; row++)
  514.     {
  515.         if (GetRowHeight(row) <= 0) continue;
  516.         rect.top = rect.bottom+1;
  517.         rect.bottom = rect.top + GetRowHeight(row)-1;
  518.         // rect.bottom = bottom pixel of previous row
  519.         if (rect.top > clipRect.bottom)
  520.             break;                // Gone past cliprect
  521.         if (rect.bottom < clipRect.top)
  522.             continue;             // Reached cliprect yet?
  523.         rect.right = -1;
  524.         for (col = 0; col < m_nFixedCols; col++)
  525.         {
  526.             if (GetColumnWidth(col) <= 0) continue;
  527.             rect.left = rect.right+1;
  528.             rect.right = rect.left + GetColumnWidth(col)-1;
  529.             if (rect.left > clipRect.right)
  530.                 break;            // gone past cliprect
  531.             if (rect.right < clipRect.left)
  532.                 continue;         // Reached cliprect yet?
  533.             pCell = GetCell(row, col);
  534.             if (pCell)
  535. {
  536. if(col==0)
  537. {
  538.   CString str;
  539.   str.Format("%d",row);
  540.   pCell->SetText(str);
  541. }
  542.                 pCell->Draw(pDC, row, col, rect, FALSE);
  543. }
  544.         }
  545.     }
  546. /////////////////////////////////////////////////////////////
  547.     // draw fixed row cells  0..m_nFixedRows, m_nFixedCols..n
  548. //画固定的行(列标头):(第一行:一列,一列...,第二行:一列,一列....);
  549.     rect.bottom = -1;
  550.     for (row = 0; row < m_nFixedRows; row++)
  551.     {
  552.         if (GetRowHeight(row) <= 0) continue;
  553.         rect.top = rect.bottom+1;
  554.         rect.bottom = rect.top + GetRowHeight(row)-1;
  555.         // rect.bottom = bottom pixel of previous row
  556.         if (rect.top > clipRect.bottom)
  557.             break;                // Gone past cliprect
  558.         if (rect.bottom < clipRect.top)
  559.             continue;             // Reached cliprect yet?
  560.         rect.right = nFixedColWidth-1;
  561.         for (col = minVisibleCol; col <= maxVisibleCol; col++)
  562.         {
  563.             if (GetColumnWidth(col) <= 0) continue;
  564.             rect.left = rect.right+1;
  565.             rect.right = rect.left + GetColumnWidth(col)-1;
  566.             if (rect.left > clipRect.right)
  567.                 break;        // gone past cliprect
  568.             if (rect.right < clipRect.left)
  569.                 continue;     // Reached cliprect yet?
  570.             pCell = GetCell(row, col);
  571.             if (pCell)
  572. {
  573.                 pCell->Draw(pDC, row, col, rect, FALSE);
  574. }
  575.         }
  576.     }
  577. ///////////////////////////////////////////////////////////////////
  578. // draw rest of non-fixed cells
  579. //画剩余的非固定的单元格:(第一行:一列,一列...,第二行:一列,一列....);
  580.     rect.bottom = nFixedRowHeight-1;
  581.     for (row = minVisibleRow; row <= maxVisibleRow; row++)
  582.     {
  583.         if (GetRowHeight(row) <= 0) continue;
  584.         rect.top = rect.bottom+1;
  585.         rect.bottom = rect.top + GetRowHeight(row)-1;
  586.         // rect.bottom = bottom pixel of previous row
  587.         if (rect.top > clipRect.bottom)
  588.             break;                // Gone past cliprect
  589.         if (rect.bottom < clipRect.top)
  590.             continue;             // Reached cliprect yet?
  591.         rect.right = nFixedColWidth-1;
  592.         for (col = minVisibleCol; col <= maxVisibleCol; col++)
  593.         {
  594.             if (GetColumnWidth(col) <= 0) continue;
  595.             rect.left = rect.right+1;
  596.             rect.right = rect.left + GetColumnWidth(col)-1;
  597.             if (rect.left > clipRect.right)
  598.                 break;        // gone past cliprect
  599.             if (rect.right < clipRect.left)
  600.                 continue;     // Reached cliprect yet?
  601.             pCell = GetCell(row, col);
  602.             // TRACE(_T("Cell %d,%d type: %sn"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
  603.             if (pCell)
  604. {
  605.                 pCell->Draw(pDC, row, col, rect, FALSE);
  606. }
  607.         }
  608.     }
  609. CPen pen;
  610.     pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
  611.     pDC->SelectObject(&pen);
  612.     // draw vertical lines (drawn at ends of cells)
  613. //画垂直分隔线:
  614.     if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  615.     {
  616.         int x = nFixedColWidth;
  617.         for (col =minVisibleCol; col <= maxVisibleCol; col++)
  618.         {
  619.             if (GetColumnWidth(col) <= 0) continue;
  620.             x += GetColumnWidth(col);
  621.             pDC->MoveTo(x-1, nFixedRowHeight);
  622.             pDC->LineTo(x-1, rect.bottom);
  623.         }
  624.     }
  625.     // draw horizontal lines (drawn at bottom of each cell)
  626. //画水平分隔线
  627.     if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  628.     {
  629.         int y = nFixedRowHeight;
  630.         for (row = minVisibleRow; row <= maxVisibleRow; row++)
  631.         {
  632.             if (GetRowHeight(row) <= 0) continue;
  633.             y += GetRowHeight(row);
  634.             pDC->MoveTo(nFixedColWidth, y-1);
  635.             pDC->LineTo(rect.right,  y-1);
  636.         }
  637.     }
  638.     pDC->SelectStockObject(NULL_PEN);
  639. }
  640. int CGridCtrl::GetFixedRowHeight() const
  641. {
  642.     int nHeight = 0;
  643.     for (int i = 0; i < m_nFixedRows; i++)
  644.         nHeight += GetRowHeight(i);
  645.     return nHeight;
  646. }
  647. int CGridCtrl::GetFixedColumnWidth() const
  648. {
  649.     int nWidth = 0;
  650.     for (int i = 0; i < m_nFixedCols; i++)
  651.         nWidth += GetColumnWidth(i);
  652.     return nWidth;
  653. }
  654. int CGridCtrl::GetRowHeight(int nRow) const
  655. {
  656.     ASSERT(nRow >= 0 && nRow < m_nRows);
  657.     if (nRow < 0 || nRow >= m_nRows)
  658.         return -1;
  659.     return m_arRowHeights[nRow];
  660. }
  661. int CGridCtrl::GetColumnWidth(int nCol) const
  662. {
  663.     ASSERT(nCol >= 0 && nCol < m_nCols);
  664.     if (nCol < 0 || nCol >= m_nCols)
  665.         return -1;
  666.     return m_arColWidths[nCol];
  667. }
  668. // Gets the first non-fixed cell ID
  669. CCellID CGridCtrl::GetTopleftNonFixedCell(BOOL bForceRecalculation /*=FALSE*/)
  670. {
  671.     // Used cached value if possible
  672. // 如果可能使用保存的值
  673.     if (m_idTopLeftCell.IsValid() && !bForceRecalculation)//因为bForceRecalculation却省为假
  674.                                                   //所以只要IsValid()返回真就执行
  675.         return m_idTopLeftCell;
  676.     int nVertScroll =GetScrollPos(SB_VERT), //没有滚动条或没有设置初始位置或没有滚动,
  677.         nHorzScroll =GetScrollPos(SB_HORZ); //会返回0值
  678.     m_idTopLeftCell.col = m_nFixedCols;//先赋值(却省情况下这是当然的)
  679.     int nRight = 0;
  680.     //这个循环比较特别,主要目的是要作m_idTopLeftCell.col++的操作,
  681. //因为各列的宽可能不一样,不能对计数器nRight简单的++,
  682. //因为nHorzScroll是以屏幕像素为单位的。
  683. while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount()-1))
  684.         nRight += GetColumnWidth(m_idTopLeftCell.col++);//作m_idTopLeftCell.col++操作
  685.                                                     //的同时对nRight每次增加一列的宽
  686.     //道理同上:
  687.     m_idTopLeftCell.row = m_nFixedRows;
  688.     int nTop = 0;
  689.     while (nTop < nVertScroll && m_idTopLeftCell.row < (GetRowCount()-1))
  690.         nTop += GetRowHeight(m_idTopLeftCell.row++);
  691.     TRACE2("TopLeft cell is row %d, col %dn",m_idTopLeftCell.row, m_idTopLeftCell.col);
  692.     return m_idTopLeftCell;//返回当前的左上角单元格ID(就是行列号)
  693. }
  694. // This gets even partially visible cells
  695. // 得到可见部分的单元格:
  696. CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/, 
  697.                                                   BOOL bForceRecalculation /*=FALSE*/)
  698. {
  699.     CRect rect;
  700.     GetClientRect(rect);//窗口的区域
  701.     
  702. //左上角非固定单元格的ID:
  703.     //GetTopleftNonFixedCell会根据滚动条的位置返回不同的左上角非固定单元格。
  704. //有了这个功能,GetVisibleNonFixedCellRange才会返回不同的单元格范围
  705.     CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);//左上角非固定单元格的ID
  706.     // calc bottom
  707. // 找到底部(可视单元格区域的底部)
  708.     int bottom = GetFixedRowHeight();//固定行的高
  709.     for (int i = idTopLeft.row; i < GetRowCount(); i++)
  710.     {
  711.         bottom += GetRowHeight(i);//为bottom增加那一行的高
  712.                           //因为可能用户调整后各行的高都不一样
  713.         if (bottom >= rect.bottom)//如果bottom大于等于窗口的底
  714.         {
  715.             bottom = rect.bottom;//botto就等于窗口的底
  716.             break;               //然后就跳出循环
  717.         }
  718.     }
  719.     int maxVisibleRow = min(i, GetRowCount() - 1);//在i和总行数-1中取小
  720.     // calc right
  721. //找到右边界
  722.     int right = GetFixedColumnWidth();//固定列的宽
  723.     for (i = idTopLeft.col; i < GetColumnCount(); i++)
  724.     {
  725.         right += GetColumnWidth(i);//为right增加那一列的宽
  726.                            //因为用户调整后各列的宽也可能不一样
  727.         if (right >= rect.right)//如果right大于等于窗口的right
  728.         {
  729.             right = rect.right;  //right就等于窗口的right
  730.             break;               //然后就跳出循环
  731.         }
  732.     }
  733.     int maxVisibleCol = min(i, GetColumnCount() - 1);//在i和总列数-1中取小
  734.     if (pRect)
  735.     {
  736.         //对pRect初始化:
  737. pRect->left = pRect->top = 0;
  738.         pRect->right = right;
  739.         pRect->bottom = bottom;
  740.     }
  741.     //返回可视部分的单元格范围:
  742.     return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  743. }
  744. BOOL CGridCtrl::OnEraseBkgnd(CDC* pDC) 
  745. {
  746. return true;
  747. // return CWnd::OnEraseBkgnd(pDC);
  748. }
  749. BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
  750. {
  751.     CGridCellBase* pCell = GetCell(nRow, nCol);
  752.     if (!pCell)
  753.         return FALSE;
  754.     pCell->SetText(str);
  755.     return TRUE;
  756. }
  757. void CGridCtrl::SetSortColumn(int nCol)
  758. {
  759.   //  if (m_nSortColumn >= 0)
  760.   //      InvalidateCellRect(0, m_nSortColumn);
  761.     m_nSortColumn = nCol;
  762.   //  if (nCol >= 0)
  763.   //      InvalidateCellRect(0, nCol);
  764. }
  765. void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
  766. {
  767. CCellID cellid=GetCellFromPt(point);//得到鼠标点中的CellID
  768. int row=cellid.row;
  769. int col=cellid.col;
  770.     COLORREF lastclr;
  771. CDC* pDC=GetDC();
  772. m_bLMouseButtonDown   = TRUE;//设置鼠标按下标志(OnMouseMove()中需要)
  773.     m_LeftClickDownPoint = point;//鼠标点(OnMouseMove()中需要)
  774. m_LeftClickDownCell  = GetCellFromPt(point);//鼠标点中的单元格ID(重要)
  775. CRect cellrect;
  776. GetCellRect(m_LeftClickDownCell,&cellrect);
  777. if(m_LeftClickDownPoint.x<=(cellrect.left+5))//如果鼠标点在此范围内,就设定为左边的单元格
  778. m_LeftClickDownCell.col--;               //这样,就限制只能从右边界调整单元格宽度
  779. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  780.     {
  781.             SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));//改变光标
  782. }
  783.    if(this->IsValid(m_SelectedCell))//m_SelectedCell保存上一次选择的单元格,因为没有初始化
  784.                                  //所以第一次是非法的。
  785.  //如果它合法:
  786.    {
  787.   CGridCellBase* pcell=GetCell(row,col);//得到鼠标点中的单元格
  788.   if(m_SelectedCell!=cellid)//如果m_SelectedCell不是当前鼠标点中的
  789.   {
  790.   if(pcell)
  791.   {
  792.   lastclr=GetDefaultCell(FALSE, FALSE)->GetBackClr();//缺省的非固定单元格的背景色
  793.   pcell->SetBackClr(RGB(128,196,255));//设置新的背景色
  794.   CGridCellBase* pSelcell=GetCell(m_SelectedCell.row,m_SelectedCell.col);//得到上次选中的单元格
  795.   pSelcell->SetBackClr(lastclr);//恢复他的背景色
  796.   m_SelectedCell=cellid;//保存这次选中的单元格
  797.   
  798.   }
  799.   
  800.   }
  801.   
  802.    }
  803.    else//m_SelectedCell为非法(第一次肯定是的)
  804.    {
  805.    CGridCellBase* pcell=GetCell(row,col);
  806.    if(pcell)
  807.    {
  808. lastclr=GetDefaultCell(FALSE, FALSE)->GetBackClr();
  809. pcell->SetBackClr(RGB(128,196,255));
  810. m_SelectedCell=cellid;
  811.    }
  812.    }
  813.    if(m_LeftClickDownCell.row < GetFixedRowCount())
  814.    {
  815.    OnFixedRowClick(m_LeftClickDownCell);
  816.    }
  817.    Invalidate();
  818.    // RedrawWindow();
  819. CWnd::OnLButtonDown(nFlags, point);
  820. }
  821. // If resizing or cell counts/sizes change, call this - it'll fix up the scroll bars
  822. void CGridCtrl::ResetScrollBars()
  823. {
  824.     // Force a refresh. 
  825.     m_idTopLeftCell.row = -1;
  826.     if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd())) 
  827.         return;
  828.     
  829.     CRect rect;
  830.     
  831.     // This would have caused OnSize event - Brian 
  832.     //EnableScrollBars(SB_BOTH, FALSE); 
  833.     
  834.     GetClientRect(rect);
  835.     
  836.     if (rect.left == rect.right || rect.top == rect.bottom)//没有窗口面积就返回
  837.         return;
  838.     
  839.     if (IsVisibleVScroll())
  840.         rect.right += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER);
  841.                   //GetSystemMetrics返回显示器的屏幕尺寸
  842.                   //GetSystemMetrics(SM_CXVSCROLL)得到垂直滚动条的宽
  843.                     
  844.     if (IsVisibleHScroll())
  845.         rect.bottom += GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYBORDER);
  846.     
  847.     rect.left += GetFixedColumnWidth();//左边界右移
  848.     rect.top += GetFixedRowHeight();//顶边界下移
  849.     
  850.     
  851.     if (rect.left >= rect.right || rect.top >= rect.bottom)//不显示滚动条的条件
  852.     {
  853.        // EnableScrollBarCtrl(SB_BOTH, FALSE);
  854.         return;
  855.     }
  856.     
  857. //可见区域:
  858.     CRect VisibleRect(GetFixedColumnWidth(), GetFixedRowHeight(), 
  859.               rect.right, rect.bottom);
  860. //虚区域:
  861.     CRect VirtualRect(GetFixedColumnWidth(), GetFixedRowHeight(),
  862.               GetVirtualWidth(), GetVirtualHeight());
  863.     
  864.     // Removed to fix single row scrollbar problem (Pontus Goffe)
  865.     // CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
  866.     // if (!IsValid(visibleCells)) return;
  867.         
  868.     //TRACE(_T("Visible: %d x %d, Virtual %d x %d.  H %d, V %dn"), 
  869.     //      VisibleRect.Width(), VisibleRect.Height(),
  870.     //      VirtualRect.Width(), VirtualRect.Height(),
  871.     //      IsVisibleHScroll(), IsVisibleVScroll());
  872.     // If vertical scroll bar, horizontal space is reduced
  873. //如果显示垂直滚动条,水平空间会减少一个滚动条的宽度
  874.     if (VisibleRect.Height() < VirtualRect.Height())
  875.         VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  876.     // If horz scroll bar, vert space is reduced
  877. //如果显示水平滚动条,垂直空间会减少一个滚动条的宽度
  878.     if (VisibleRect.Width() < VirtualRect.Width())
  879.         VisibleRect.bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
  880.     
  881.     // Recheck vertical scroll bar
  882.     //if (VisibleRect.Height() < VirtualRect.Height())
  883.     // VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  884.     
  885.     if (VisibleRect.Height() < VirtualRect.Height())
  886.     {
  887.         //EnableScrollBars(SB_VERT, TRUE); 
  888.         m_nVScrollMax = VirtualRect.Height() - 1;
  889.     }
  890.     else
  891.     {
  892.         // EnableScrollBars(SB_VERT, FALSE); 
  893.         m_nVScrollMax = 0;
  894.     }
  895.     if (VisibleRect.Width() < VirtualRect.Width())
  896.     {
  897.        // EnableScrollBars(SB_HORZ, TRUE); 
  898.         m_nHScrollMax = VirtualRect.Width() - 1;
  899.     }
  900.     else
  901.     {
  902.        // EnableScrollBars(SB_HORZ, FALSE); 
  903.         m_nHScrollMax = 0;
  904.     }
  905.     ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine
  906.     /* Old code - CJM
  907.     SCROLLINFO si;
  908.     si.cbSize = sizeof(SCROLLINFO);
  909.     si.fMask = SIF_PAGE;
  910.     si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
  911.     SetScrollInfo(SB_HORZ, &si, FALSE); 
  912.     si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
  913.     SetScrollInfo(SB_VERT, &si, FALSE);
  914.     SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
  915.     SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
  916.     */
  917.     // New code - Paul Runstedler 
  918. CMyGridFrame *pWnd=(CMyGridFrame*)(this->GetParent());
  919.     SCROLLINFO si;
  920.     si.cbSize = sizeof(SCROLLINFO);
  921.     si.fMask = SIF_PAGE | SIF_RANGE;
  922.     si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
  923.     si.nMin = 0;
  924.     si.nMax = m_nHScrollMax;
  925. //CWnd* pWnd=GetParent();
  926.     
  927. SetScrollInfo(SB_HORZ,&si, TRUE);
  928.     si.fMask |= SIF_DISABLENOSCROLL;
  929.     si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
  930.     si.nMin = 0;
  931.     si.nMax = m_nVScrollMax;
  932.     SetScrollInfo(SB_VERT,&si, TRUE);
  933. }
  934. void CGridCtrl::EnableScrollBars(int nBar, BOOL bEnable /*=TRUE*/)
  935. {
  936.     CMyGridFrame* pWnd=(CMyGridFrame*)(this->GetParent());
  937. if (bEnable)
  938.     {
  939.         if (!IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
  940.         {
  941.             m_nBarState |= GVL_HORZ;
  942. pWnd->EnableScrollBarCtrl(SB_HORZ, bEnable);
  943.             //CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
  944.         }
  945.         
  946.         if (!IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
  947.         {
  948.             m_nBarState |= GVL_VERT;
  949.             pWnd->EnableScrollBarCtrl(SB_VERT, bEnable);
  950.             //CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
  951.         }
  952.     }
  953.     else
  954.     {
  955.         if ( IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
  956.         {
  957.             m_nBarState &= ~GVL_HORZ; 
  958. pWnd->EnableScrollBarCtrl(SB_HORZ, bEnable);
  959.             //CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
  960.         }
  961.         
  962.         if ( IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
  963.         {
  964.             m_nBarState &= ~GVL_VERT;
  965. pWnd->EnableScrollBarCtrl(SB_VERT, bEnable);
  966.             //CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
  967.         }
  968.     }
  969. }
  970. long CGridCtrl::GetVirtualWidth() const
  971. {
  972.     long lVirtualWidth = 0;
  973.     int iColCount = GetColumnCount();
  974.     for (int i = 0; i < iColCount; i++)
  975.         lVirtualWidth += m_arColWidths[i];
  976.     return lVirtualWidth;
  977. }
  978. long CGridCtrl::GetVirtualHeight() const
  979. {
  980.     long lVirtualHeight = 0;
  981.     int iRowCount = GetRowCount();
  982.     for (int i = 0; i < iRowCount; i++)
  983.         lVirtualHeight += m_arRowHeights[i];
  984.     return lVirtualHeight;
  985. }
  986. void CGridCtrl::OnSize(UINT nType, int cx, int cy) 
  987. {
  988. CWnd::OnSize(nType, cx, cy);
  989. // this->EnableScrollBarCtrl(SB_BOTH,FALSE);//不能加这一句。否则会出 "Debug Assertion Failed"错误。
  990.                                              //你不能禁止滚动控件。
  991.                                          //你只是把滚动控制权交给了父窗口。
  992. //通过重载GetScrollBarCtrl()把滚动控制权交给了CMyGridFrame.
  993.    ResetScrollBars();
  994. }
  995. void CGridCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  996. {
  997. int scrollPos =GetScrollPos32(SB_HORZ);
  998.     CCellID idTopLeft = GetTopleftNonFixedCell();
  999.     CRect rect;
  1000.     GetClientRect(rect);
  1001.     switch (nSBCode)
  1002.     {
  1003.     case SB_LINERIGHT:
  1004.         if (scrollPos < m_nHScrollMax)
  1005.         {
  1006.             // may have contiguous hidden columns.  Blow by them
  1007.             while (idTopLeft.col < (GetColumnCount()-1)
  1008.                     && GetColumnWidth( idTopLeft.col) < 1 )
  1009.             {
  1010.                 idTopLeft.col++;
  1011.             }
  1012.             int xScroll = GetColumnWidth(idTopLeft.col);
  1013.             SetScrollPos32(SB_HORZ, scrollPos + xScroll);
  1014.             if (GetScrollPos32(SB_HORZ) == scrollPos)
  1015.                 break;          // didn't work
  1016.             rect.left = GetFixedColumnWidth();
  1017.             //rect.left = GetFixedColumnWidth() + xScroll;
  1018.             //ScrollWindow(-xScroll, 0, rect);
  1019.             //rect.left = rect.right - xScroll;
  1020.             InvalidateRect(rect);
  1021.         }
  1022.         break;
  1023.     case SB_LINELEFT:
  1024.         if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount())
  1025.         {
  1026.             int iColToUse = idTopLeft.col-1;
  1027.             // may have contiguous hidden columns.  Blow by them
  1028.             while(  iColToUse > GetFixedColumnCount()
  1029.                     && GetColumnWidth( iColToUse) < 1 )
  1030.             {
  1031.                 iColToUse--;
  1032.             }
  1033.             int xScroll = GetColumnWidth(iColToUse);
  1034.             SetScrollPos32(SB_HORZ, max(0, scrollPos - xScroll));
  1035.             rect.left = GetFixedColumnWidth();
  1036.             //ScrollWindow(xScroll, 0, rect);
  1037.             //rect.right = rect.left + xScroll;
  1038.             InvalidateRect(rect);
  1039.         }
  1040.         break;
  1041.     case SB_PAGERIGHT:
  1042.         if (scrollPos < m_nHScrollMax)
  1043.         {
  1044.             rect.left = GetFixedColumnWidth();
  1045.             int offset = rect.Width();
  1046.             int pos = min(m_nHScrollMax, scrollPos + offset);
  1047.             SetScrollPos32(SB_HORZ, pos);
  1048.             rect.left = GetFixedColumnWidth();
  1049.             InvalidateRect(rect);
  1050.         }
  1051.         break;
  1052.         
  1053.     case SB_PAGELEFT:
  1054.         if (scrollPos > 0)
  1055.         {
  1056.             rect.left = GetFixedColumnWidth();
  1057.             int offset = -rect.Width();
  1058.             int pos = max(0, scrollPos + offset);
  1059.             SetScrollPos32(SB_HORZ, pos);
  1060.             rect.left = GetFixedColumnWidth();
  1061.             InvalidateRect(rect);
  1062.         }
  1063.         break;
  1064.         
  1065.     case SB_THUMBPOSITION:
  1066.     case SB_THUMBTRACK:
  1067.         {
  1068.             SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
  1069.             m_idTopLeftCell.row = -1;
  1070.             CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1071.             if (idNewTopLeft != idTopLeft)
  1072.             {
  1073.                 rect.left = GetFixedColumnWidth();
  1074.                 InvalidateRect(rect);
  1075.             }
  1076.         }
  1077.         break;
  1078.         
  1079.     case SB_LEFT:
  1080.         if (scrollPos > 0)
  1081.         {
  1082.             SetScrollPos32(SB_HORZ, 0);
  1083.             Invalidate();
  1084.         }
  1085.         break;
  1086.         
  1087.     case SB_RIGHT:
  1088.         if (scrollPos < m_nHScrollMax)
  1089.         {
  1090.             SetScrollPos32(SB_HORZ, m_nHScrollMax);
  1091.             Invalidate();
  1092.         }
  1093.         break;
  1094.         
  1095.         
  1096.     default: 
  1097.         break;
  1098.     }
  1099. // CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
  1100. }
  1101. // Get/Set scroll position using 32 bit functions
  1102. int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
  1103. {
  1104.     SCROLLINFO si;
  1105.     si.cbSize = sizeof(SCROLLINFO);
  1106.    
  1107. if (bGetTrackPos)
  1108. {
  1109. if (GetScrollInfo(nBar,&si, SIF_TRACKPOS))
  1110.             return si.nTrackPos;
  1111. }
  1112. else
  1113. {
  1114. if (GetScrollInfo(nBar,&si, SIF_POS))
  1115.             return si.nPos;
  1116. }
  1117.     return 0;
  1118. }
  1119. BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
  1120. {
  1121.     m_idTopLeftCell.row = -1;
  1122.     SCROLLINFO si;
  1123.     si.cbSize = sizeof(SCROLLINFO);
  1124.     si.fMask  = SIF_POS;
  1125.     si.nPos   = nPos;
  1126.     return SetScrollInfo(nBar, &si, bRedraw);
  1127. }
  1128. void CGridCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  1129. {
  1130.     // Get the scroll position ourselves to ensure we get a 32 bit value
  1131.     int scrollPos = GetScrollPos32(SB_VERT);
  1132.     CCellID idTopLeft = GetTopleftNonFixedCell();
  1133.     CRect rect;
  1134.     GetClientRect(rect);
  1135.     switch (nSBCode)
  1136.     {
  1137.     case SB_LINEDOWN:
  1138.         if (scrollPos < m_nVScrollMax)
  1139.         {
  1140.             // may have contiguous hidden rows.  Blow by them
  1141.             while(  idTopLeft.row < (GetRowCount()-1)
  1142.                     && GetRowHeight( idTopLeft.row) < 1 )
  1143.             {
  1144.                 idTopLeft.row++;
  1145.             }
  1146.             int yScroll = GetRowHeight(idTopLeft.row);
  1147.             SetScrollPos32(SB_VERT, scrollPos + yScroll);
  1148.             if (GetScrollPos32(SB_VERT) == scrollPos)
  1149.                 break;          // didn't work
  1150.             rect.top = GetFixedRowHeight();
  1151.             //rect.top = GetFixedRowHeight() + yScroll;
  1152.             //ScrollWindow(0, -yScroll, rect);
  1153.             //rect.top = rect.bottom - yScroll;
  1154.             InvalidateRect(rect);
  1155.         }
  1156.         break;
  1157.         
  1158.     case SB_LINEUP:
  1159.         if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount())
  1160.         {
  1161.             int iRowToUse = idTopLeft.row-1;
  1162.             // may have contiguous hidden rows.  Blow by them
  1163.             while(  iRowToUse > GetFixedRowCount()
  1164.                     && GetRowHeight( iRowToUse) < 1 )
  1165.             {
  1166.                 iRowToUse--;
  1167.             }
  1168.             int yScroll = GetRowHeight( iRowToUse);
  1169.             SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
  1170.             rect.top = GetFixedRowHeight();
  1171.             //ScrollWindow(0, yScroll, rect);
  1172.             //rect.bottom = rect.top + yScroll;
  1173.             InvalidateRect(rect);
  1174.         }
  1175.         break;
  1176.         
  1177.     case SB_PAGEDOWN:
  1178.         if (scrollPos < m_nVScrollMax)
  1179.         {
  1180.             rect.top = GetFixedRowHeight();
  1181.             scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
  1182.             SetScrollPos32(SB_VERT, scrollPos);
  1183.             rect.top = GetFixedRowHeight();
  1184.             InvalidateRect(rect);
  1185.         }
  1186.         break;
  1187.         
  1188.     case SB_PAGEUP:
  1189.         if (scrollPos > 0)
  1190.         {
  1191.             rect.top = GetFixedRowHeight();
  1192.             int offset = -rect.Height();
  1193.             int pos = max(0, scrollPos + offset);
  1194.             SetScrollPos32(SB_VERT, pos);
  1195.             rect.top = GetFixedRowHeight();
  1196.             InvalidateRect(rect);
  1197.         }
  1198.         break;
  1199.         
  1200.     case SB_THUMBPOSITION:
  1201.     case SB_THUMBTRACK:
  1202.         {
  1203.             SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
  1204.             m_idTopLeftCell.row = -1;
  1205.             CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1206.             if (idNewTopLeft != idTopLeft)
  1207.             {
  1208.                 rect.top = GetFixedRowHeight();
  1209.                 InvalidateRect(rect);
  1210.             }
  1211.         }
  1212.         break;
  1213.         
  1214.     case SB_TOP:
  1215.         if (scrollPos > 0)
  1216.         {
  1217.             SetScrollPos32(SB_VERT, 0);
  1218.             Invalidate();
  1219.         }
  1220.         break;
  1221.         
  1222.     case SB_BOTTOM:
  1223.         if (scrollPos < m_nVScrollMax)
  1224.         {
  1225.             SetScrollPos32(SB_VERT, m_nVScrollMax);
  1226.             Invalidate();
  1227.         }
  1228.         
  1229.     default: 
  1230.         break;
  1231.     }
  1232. // CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
  1233. }
  1234. // Custom background erasure. This gets called from within the OnDraw function,
  1235. // 自定义的背景擦除函数,它在OnDraw函数内部被呼叫
  1236. // since we will (most likely) be using a memory DC to stop flicker. If we just
  1237. // 然后,我们要用一个内存DC来消除闪烁。如果我们只是
  1238. // erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
  1239. // 正常的通过OnEraseBkgnd函数去擦除背景,而不用颜色填充内存DC
  1240. // selected bitmap with colour, then all sorts of vis problems would occur
  1241. // 选择的位图,将会出现各式各样的难题。
  1242. void CGridCtrl::EraseBkgnd(CDC *pDC)
  1243. {
  1244. //经过试验,其实要消除闪烁只要在OnEraseBkgnd中什么也不做,而只返回真就行了。
  1245. //而这个EraseBkgnd函数的功能完全可以是OnDraw的一部分(因为它本来就是在OnDraw中调用的)。
  1246. //但如果不使用内存DC,而只使用本函数又会产生闪烁。
  1247. CRect  VisRect, ClipRect, rect;
  1248.     CBrush FixedRowColBack(GetDefaultCell(TRUE, TRUE)->GetBackClr()),
  1249.            FixedRowBack(GetDefaultCell(TRUE, FALSE)->GetBackClr()),
  1250.            FixedColBack(GetDefaultCell(FALSE, TRUE)->GetBackClr()),
  1251.            TextBack(GetDefaultCell(FALSE, FALSE)->GetBackClr());
  1252.     CBrush Back(GetGridBkColor()); 
  1253.     //CBrush Back(GetTextBkColor());
  1254.     if (pDC->GetClipBox(ClipRect) == ERROR)
  1255.         return ;
  1256. // ClipRect.bottom=ClipRect.bottom-22;
  1257. // ClipRect.right=ClipRect.right-22;
  1258.     GetVisibleNonFixedCellRange(VisRect);
  1259.     int nFixedColumnWidth = GetFixedColumnWidth();
  1260.     int nFixedRowHeight = GetFixedRowHeight();
  1261.     // Draw Fixed row/column background
  1262. // 画固定行/列背景:
  1263.     if (ClipRect.left < nFixedColumnWidth && ClipRect.top < nFixedRowHeight)
  1264.         pDC->FillRect(CRect(ClipRect.left, ClipRect.top, 
  1265.                       nFixedColumnWidth, nFixedRowHeight),
  1266.                       &FixedRowColBack);
  1267.     // Draw Fixed columns background
  1268. // 画固定列背景:
  1269. //VisRect.bottom=nFixedRowHeight*GetRowCount();
  1270.     if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
  1271.         pDC->FillRect(CRect(ClipRect.left, ClipRect.top, 
  1272.                       nFixedColumnWidth, VisRect.bottom),
  1273.                       &FixedColBack);
  1274.         
  1275.     // Draw Fixed rows background
  1276. // 画固定行背景:
  1277.     if (ClipRect.top < nFixedRowHeight && 
  1278.         ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
  1279.         pDC->FillRect(CRect(nFixedColumnWidth-1, ClipRect.top,
  1280.                       VisRect.right, nFixedRowHeight),
  1281.                       &FixedRowBack);
  1282.     // Draw non-fixed cell background
  1283. // 画非固定的单元格背景:
  1284.     if (rect.IntersectRect(VisRect, ClipRect)) 
  1285.     {
  1286.         CRect CellRect(max(nFixedColumnWidth, rect.left), 
  1287.                        max(nFixedRowHeight, rect.top),
  1288.                        rect.right, rect.bottom);
  1289.         pDC->FillRect(CellRect, &TextBack);
  1290.     }
  1291.     // Draw right hand side of window outside grid
  1292. // 画右手边外面的背景:
  1293.     if (VisRect.right < ClipRect.right) 
  1294.         pDC->FillRect(CRect(VisRect.right, ClipRect.top, 
  1295.                       ClipRect.right, ClipRect.bottom),
  1296.                       &Back);
  1297.     // Draw bottom of window below grid
  1298. // 画下面的背景:
  1299.     if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right) 
  1300.         pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
  1301.                       VisRect.right, ClipRect.bottom),
  1302.                       &Back);
  1303. }
  1304. // Get cell from point.
  1305. // point - client coordinates
  1306. // bAllowFixedCellCheck - if TRUE then fixed cells are checked
  1307. //从鼠标点得到单元格ID:
  1308. CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/)
  1309. {
  1310.     CCellID cellID; // return value
  1311.     CCellID idTopLeft = GetTopleftNonFixedCell();//得到可见范围内最左上角单元格的ID
  1312. if (!bAllowFixedCellCheck && !IsValid(idTopLeft))
  1313. return cellID;//???
  1314.     // calculate column index
  1315. // 找列号
  1316.     int fixedColWidth = GetFixedColumnWidth();//得到固定列宽(所有固定列宽的和)
  1317.     if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window(不在窗口内)
  1318.         cellID.col = -1;//使cellID非法
  1319.     else if (point.x < fixedColWidth) // in fixed col(在固定列内)
  1320.     {
  1321.         int xpos = 0;
  1322.         int col = 0;
  1323.         while (col < m_nFixedCols)//从第0列开始
  1324.         {
  1325.             xpos += GetColumnWidth(col);//增加一列的宽
  1326.             if (xpos > point.x)
  1327.                 break;//如果第一次就跳出,列号col就是0。
  1328. col++; //列号增加1
  1329.         }
  1330. //当col=m_nFixedCols时循环结束,所以最后一次是col=m_nFixedCols。
  1331.         cellID.col = col;//最后得到列号
  1332. //CString str;
  1333. //str.Format("%d",col);
  1334. //MessageBox(str);
  1335.     }
  1336.     else    // in non-fixed col(在非固定列)
  1337.     {
  1338.         int xpos = fixedColWidth;//固定列宽(所有固定列宽的和)
  1339. int col = idTopLeft.col; //左上角非固定单元格,其值=m_nFixedCols;
  1340.         
  1341. while ( col < GetColumnCount())//GetColumnCount返回总列数
  1342.         {
  1343.             xpos += GetColumnWidth(col);////增加一列的宽
  1344.             if (xpos > point.x)
  1345.                 break;//如果第一次就跳出,列号col就是左上角非固定单元格,其值=m_nFixedCols;
  1346. col++;//列号增加1
  1347.         }
  1348.         //当col=GetColumnCount()时循环结束,所以最后是col=GetColumnCount()。
  1349. //但是col是从0开始的,如果到col=GetColumnCount()会多一列。
  1350. //所以需要修正:
  1351.         if (col >= GetColumnCount())//
  1352.             cellID.col = -1;
  1353.         else
  1354.             cellID.col = col;
  1355.     }
  1356.     // calculate row index
  1357. // 找行号(类似找列号,注释略)
  1358.     int fixedRowHeight = GetFixedRowHeight();//得到固定行的高(所有固定行的高的和)
  1359.     if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window(不在窗口内)
  1360.         cellID.row = -1;//使cellID非法
  1361.     else if (point.y < fixedRowHeight) // in fixed col(在固定列)
  1362.     {
  1363.         int ypos = 0;
  1364.         int row = 0;
  1365.         while (row < m_nFixedRows) 
  1366.         {
  1367.             ypos += GetRowHeight(row);
  1368.             if (ypos > point.y)
  1369.                 break;
  1370. row++;
  1371.         }
  1372.         cellID.row = row;
  1373.     }
  1374.     else
  1375.     {
  1376.         int ypos = fixedRowHeight;
  1377. int row = idTopLeft.row; //m_nFixedRows;
  1378.         while ( row < GetRowCount() )
  1379.         {
  1380.             ypos += GetRowHeight(row);
  1381.             if (ypos > point.y)
  1382.                 break;
  1383. row++;
  1384.         }
  1385.         if (row >= GetRowCount())
  1386.             cellID.row = -1;
  1387.         else
  1388.             cellID.row = row;
  1389.     }
  1390.     return cellID;//返回单元格ID
  1391. }
  1392. // Is a given cell designation valid (ie within the bounds of our number
  1393. // of columns/rows)?
  1394. //合法性检验
  1395. BOOL CGridCtrl::IsValid(int nRow, int nCol) const
  1396. {
  1397.     return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
  1398. }
  1399. BOOL CGridCtrl::IsValid(const CCellID& cell) const
  1400. {
  1401.     return IsValid(cell.row, cell.col);
  1402. }
  1403. // Is a given cell range valid (ie within the bounds of our number
  1404. // of columns/rows)?
  1405. BOOL CGridCtrl::IsValid(const CCellRange& range) const
  1406. {
  1407.     return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
  1408.         range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
  1409.         range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
  1410.         range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
  1411. }
  1412. void CGridCtrl::OnMouseMove(UINT nFlags, CPoint point) 
  1413. {
  1414.     int leftcol=(m_LeftClickDownCell.col-1)>0 ? (m_LeftClickDownCell.col-1) : 0;//左边的列
  1415. int leftrow=m_LeftClickDownCell.row;
  1416. CRect leftrc;
  1417. GetCellRect(leftrow,leftcol,leftrc);
  1418. int left;
  1419. if(leftcol==0)
  1420. {
  1421. left=0;
  1422. }
  1423. else
  1424. {
  1425. left=leftrc.right;
  1426. }
  1427. CRect rect;
  1428.     GetClientRect(rect);
  1429. if( MouseOverColumnResizeArea(point))
  1430. {
  1431. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  1432. //m_LastMousePoint = point;
  1433. if(nFlags==MK_LBUTTON)
  1434. {
  1435. m_bColSizing=true;
  1436. }
  1437. else
  1438. {
  1439. m_bColSizing=false;
  1440. }
  1441. }
  1442. if(m_bColSizing)
  1443. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  1444. if(point.x>=left+15)
  1445. {
  1446. if(m_bColSizing && nFlags==MK_LBUTTON )
  1447. {
  1448. m_bLMouseButtonDown=false;
  1449.     CDC* pDC = GetDC();
  1450.             if (!pDC)
  1451.                 return;
  1452. CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
  1453.             m_LastMousePoint.x + 1, rect.bottom);
  1454.             pDC->InvertRect(&oldInvertedRect);//(用反色填充矩形)用它擦除上一个鼠标位置画的线
  1455.             CRect newInvertedRect(point.x, rect.top, 
  1456.                   point.x + 1, rect.bottom);
  1457.     pDC->InvertRect(&newInvertedRect);//(用反色填充矩形)在新位置画线,两句形成一条移动的分隔线
  1458.             ReleaseDC(pDC);
  1459. }
  1460.     m_LastMousePoint = point;
  1461. }
  1462. CWnd::OnMouseMove(nFlags, point);
  1463. }
  1464. // Forces a redraw of a cell immediately (using a direct DC construction,
  1465. // or the supplied dc)
  1466. BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
  1467. {
  1468.     return RedrawCell(cell.row, cell.col, pDC);
  1469. }
  1470. BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
  1471. {
  1472.     BOOL bResult = TRUE;
  1473.     BOOL bMustReleaseDC = FALSE;
  1474.     if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
  1475.         return FALSE;
  1476.     CRect rect;
  1477.     if (!GetCellRect(nRow, nCol, rect))
  1478.         return FALSE;
  1479.     if (!pDC)
  1480.     {
  1481.         pDC = GetDC();
  1482.         if (pDC)
  1483.             bMustReleaseDC = TRUE;
  1484.     }
  1485.     if (pDC)
  1486.     {
  1487.         // Redraw cells directly
  1488.         if (nRow < m_nFixedRows || nCol < m_nFixedCols)
  1489.         {
  1490.             CGridCellBase* pCell = GetCell(nRow, nCol);
  1491.             if (pCell)
  1492.                 bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
  1493.         }
  1494.         else
  1495.         {
  1496.             CGridCellBase* pCell = GetCell(nRow, nCol);
  1497.             if (pCell)
  1498.                 bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
  1499.             // Since we have erased the background, we will need to redraw the gridlines
  1500.             CPen pen;
  1501.             pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
  1502.             CPen* pOldPen = (CPen*) pDC->SelectObject(&pen);
  1503.             if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1504.             {
  1505.                 pDC->MoveTo(rect.left,    rect.bottom);
  1506.                 pDC->LineTo(rect.right + 1, rect.bottom);
  1507.             }
  1508.             if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1509.             {
  1510.                 pDC->MoveTo(rect.right, rect.top);
  1511.                 pDC->LineTo(rect.right, rect.bottom + 1);
  1512.             }
  1513.             pDC->SelectObject(pOldPen);
  1514.         }
  1515.     } else
  1516.         InvalidateRect(rect, TRUE);     // Could not get a DC - invalidate it anyway
  1517.     // and hope that OnPaint manages to get one
  1518.     if (bMustReleaseDC)
  1519.         ReleaseDC(pDC);
  1520.     return bResult;
  1521. }
  1522. // redraw a complete row
  1523. BOOL CGridCtrl::RedrawRow(int row)
  1524. {
  1525.     BOOL bResult = TRUE;
  1526.     CDC* pDC = GetDC();
  1527.     for (int col = 0; col < GetColumnCount(); col++)
  1528.         bResult = RedrawCell(row, col, pDC) && bResult;
  1529.     if (pDC)
  1530.         ReleaseDC(pDC);
  1531.     return bResult;
  1532. }
  1533. // Returns the bounding box of the cell
  1534. BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect)
  1535. {
  1536.     return GetCellRect(cell.row, cell.col, pRect);
  1537. }
  1538. BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect)
  1539. {
  1540.     CPoint CellOrigin;
  1541.     if (!GetCellOrigin(nRow, nCol, &CellOrigin))
  1542.         return FALSE;
  1543.     pRect->left   = CellOrigin.x;
  1544.     pRect->top    = CellOrigin.y;
  1545.     pRect->right  = CellOrigin.x + GetColumnWidth(nCol)-1;
  1546.     pRect->bottom = CellOrigin.y + GetRowHeight(nRow)-1;
  1547.     //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d:  %d,%d - %d,%dn",
  1548.     //      nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
  1549.     //      pRect->left, pRect->top, pRect->right, pRect->bottom);
  1550.     return TRUE;
  1551. }
  1552. BOOL CGridCtrl::IsCellVisible(CCellID cell) 
  1553. {
  1554.     return IsCellVisible(cell.row, cell.col);
  1555. }
  1556. BOOL CGridCtrl::IsCellVisible(int nRow, int nCol)
  1557. {
  1558.     if (!IsWindow(m_hWnd))
  1559.         return FALSE;
  1560.     int x, y;
  1561.     CCellID TopLeft;
  1562.     if (nCol >= GetFixedColumnCount() || nRow >= GetFixedRowCount())
  1563.     {
  1564.         TopLeft = GetTopleftNonFixedCell();
  1565.         if (nCol >= GetFixedColumnCount() && nCol < TopLeft.col)
  1566.             return FALSE;
  1567.         if (nRow >= GetFixedRowCount() && nRow < TopLeft.row)
  1568.             return FALSE;
  1569.     }
  1570.     
  1571.     CRect rect;
  1572.     GetClientRect(rect);
  1573.     if (nCol < GetFixedColumnCount())
  1574.     {
  1575.         x = 0;
  1576.         for (int i = 0; i <= nCol; i++) 
  1577.         {
  1578.             if (x >= rect.right)
  1579.                 return FALSE;
  1580.             x += GetColumnWidth(i);    
  1581.         }
  1582.     } 
  1583.     else 
  1584.     {
  1585.         x = GetFixedColumnWidth();
  1586.         for (int i = TopLeft.col; i <= nCol; i++) 
  1587.         {
  1588.             if (x >= rect.right)
  1589.                 return FALSE;
  1590.             x += GetColumnWidth(i);    
  1591.         }
  1592.     }
  1593.     
  1594.     if (nRow < GetFixedRowCount())
  1595.     {
  1596.         y = 0;
  1597.         for (int i = 0; i <= nRow; i++) 
  1598.         {
  1599.             if (y >= rect.bottom)
  1600.                 return FALSE;
  1601.             y += GetRowHeight(i);    
  1602.         }
  1603.     } 
  1604.     else 
  1605.     {
  1606.         if (nRow < TopLeft.row)
  1607.             return FALSE;
  1608.         y = GetFixedRowHeight();
  1609.         for (int i = TopLeft.row; i <= nRow; i++) 
  1610.         {
  1611.             if (y >= rect.bottom)
  1612.                 return FALSE;
  1613.             y += GetRowHeight(i);    
  1614.         }
  1615.     }
  1616.     
  1617.     return TRUE;
  1618. }
  1619. // returns the top left point of the cell. Returns FALSE if cell not visible.
  1620. BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p)
  1621. {
  1622.     int i;
  1623.     if (!IsValid(nRow, nCol))
  1624.         return FALSE;
  1625.     CCellID idTopLeft;
  1626.     if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
  1627.         idTopLeft = GetTopleftNonFixedCell();
  1628.     if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
  1629.         (nCol>= m_nFixedCols && nCol < idTopLeft.col))
  1630.         return FALSE;
  1631.     p->x = 0;
  1632.     if (nCol < m_nFixedCols)                      // is a fixed column
  1633.         for (i = 0; i < nCol; i++)
  1634.             p->x += GetColumnWidth(i);
  1635.         else 
  1636.         {                                        // is a scrollable data column
  1637.             for (i = 0; i < m_nFixedCols; i++)
  1638.                 p->x += GetColumnWidth(i);
  1639.             for (i = idTopLeft.col; i < nCol; i++)
  1640.                 p->x += GetColumnWidth(i);
  1641.         }
  1642.         
  1643.         p->y = 0;
  1644.         if (nRow < m_nFixedRows)                      // is a fixed row
  1645.             for (i = 0; i < nRow; i++)
  1646.                 p->y += GetRowHeight(i);
  1647.             else 
  1648.             {                                        // is a scrollable data row
  1649.                 for (i = 0; i < m_nFixedRows; i++)
  1650.                     p->y += GetRowHeight(i);
  1651.                 for (i = idTopLeft.row; i < nRow; i++)
  1652.                     p->y += GetRowHeight(i);
  1653.             }
  1654.             
  1655.             return TRUE;
  1656. }
  1657. BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p)
  1658. {
  1659.     return GetCellOrigin(cell.row, cell.col, p);
  1660. }
  1661. // TRUE if the mouse is over a column resize area. point is in Client coords
  1662. //当鼠标在一个列的resize范围之内时返回真
  1663. BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point)
  1664. {
  1665.    
  1666. if (point.y >= GetFixedRowHeight())
  1667.         return FALSE;
  1668.     CCellID idCurrentCell = GetCellFromPt(point);
  1669.     CPoint start;
  1670.     if (!GetCellOrigin(idCurrentCell, &start))
  1671.         return FALSE;
  1672.     int endx = start.x + GetColumnWidth(idCurrentCell.col);
  1673.     if ((point.x - start.x < m_nResizeCaptureRange && idCurrentCell.col != 0) ||
  1674.         endx - point.x < m_nResizeCaptureRange)
  1675.     {
  1676.         return TRUE;
  1677.     }
  1678.     else
  1679.         return FALSE;
  1680. }
  1681. void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
  1682. {
  1683.     int leftcol=(m_LeftClickDownCell.col-1)>0 ? (m_LeftClickDownCell.col-1) : 0;//左边的列
  1684. int leftrow=m_LeftClickDownCell.row;//行号
  1685. CRect leftrc;
  1686. GetCellRect(leftrow,leftcol,leftrc);//得到指定单元格的大小
  1687. int left;
  1688. if(leftcol==0)
  1689. {
  1690. left=0;
  1691. }
  1692. else
  1693. {
  1694. left=leftrc.right;
  1695. }
  1696.     
  1697.     CRect rect;
  1698.         GetClientRect(rect);
  1699.         CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 1, rect.bottom);//划线的矩形
  1700.         
  1701.         CDC* pDC = GetDC();
  1702.         if (pDC)
  1703.         {
  1704.             if(m_bColSizing)
  1705. pDC->InvertRect(&invertedRect);//擦除最后一次画的移动分隔线
  1706.             ReleaseDC(pDC);
  1707.         }
  1708.         
  1709.         if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
  1710.         {   
  1711.             CPoint start;
  1712.             if (!GetCellOrigin(m_LeftClickDownCell, &start))
  1713.                 return;
  1714. if(point.x<=left+15)
  1715. point.x=left+15;
  1716.             int nColumnWidth = point.x-left;//max(point.x - start.x, m_bAllowColHide? 0 : 1);
  1717.             if(m_bColSizing)
  1718. {
  1719. // int lie=m_LeftClickDownCell.col;
  1720. // CString s;
  1721. // s.Format("%d",lie);
  1722. // MessageBox(s);
  1723. SetColumnWidth(m_LeftClickDownCell.col, nColumnWidth);//设置新的列宽
  1724. m_bColSizing=false;
  1725. }
  1726.             ResetScrollBars();
  1727. Invalidate();
  1728.         }
  1729. // CWnd::OnLButtonUp(nFlags, point);
  1730. }
  1731. //////排序
  1732. void CGridCtrl::OnFixedRowClick(CCellID& cell)
  1733. {
  1734.     if (!IsValid(cell))
  1735.         return;
  1736. if(cell.col==0)// 序号列不排序
  1737. return;
  1738.     if (GetHeaderSort())//GetHeaderSort()得到允许排序的标志,使用SetHeaderSort(true)可以允许排序
  1739.     {
  1740.         CWaitCursor waiter;
  1741.         int sort=GetSortColumn();
  1742. if (cell.col == GetSortColumn())
  1743.             SortItems(cell.col, !GetSortAscending());
  1744.         else
  1745.             SortItems(cell.col, TRUE);//
  1746.         Invalidate();
  1747.     }
  1748. }
  1749. // Sorts on a given column using the cell text and using the specified comparison
  1750. // function
  1751. BOOL CGridCtrl::SortItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
  1752. {
  1753.     SetSortColumn(nCol);
  1754.     SetSortAscending(bAscending);
  1755. //    ResetSelectedRange();
  1756. //    SetFocusCell(-1, - 1);
  1757. if(nCol!=2)
  1758. m_pfnCompare=pfnCellNumericCompare;
  1759. else
  1760. m_pfnCompare=NULL;
  1761. if (m_pfnCompare == NULL)
  1762. return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
  1763. else
  1764.     return CGridCtrl::SortItems(m_pfnCompare, nCol, bAscending, data);//
  1765. }
  1766. // Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
  1767. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
  1768.                           LPARAM data /* = 0 */)
  1769. {
  1770.     SetSortColumn(nCol);
  1771.     SetSortAscending(bAscending);
  1772. //    ResetSelectedRange();
  1773. //    SetFocusCell(-1, -1);
  1774.     return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
  1775. }
  1776. // private recursive sort implementation
  1777. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
  1778.                           int low, int high)
  1779. {
  1780.     if (nCol >= GetColumnCount())
  1781.         return FALSE;
  1782.     if (high == -1)
  1783.         high = GetRowCount() - 1;
  1784.     int lo = low;
  1785.     int hi = high;
  1786.     
  1787.     if (hi <= lo)
  1788.         return FALSE;
  1789.     int mm=(lo + hi)/2;
  1790.     //LPARAM midItem = GetItemData((lo + hi)/2, nCol);
  1791. LPARAM pMidCell = (LPARAM) GetCell((lo + hi)/2, nCol);
  1792.     
  1793.     // loop through the list until indices cross
  1794.     while (lo <= hi)
  1795.     {
  1796.         // Find the first element that is greater than or equal to the partition 
  1797.         // element starting from the left Index.
  1798.         if (bAscending)
  1799. while (lo < high  && pfnCompare( (LPARAM)GetCell(lo, nCol), (LPARAM) pMidCell, data)< 0)
  1800.         ++lo;
  1801.         else
  1802.             while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), pMidCell, data) > 0)
  1803. ++lo;
  1804.     
  1805. // Find an element that is smaller than or equal to  the partition 
  1806. // element starting from the right Index.
  1807. if (bAscending)
  1808. while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) > 0)
  1809. --hi;
  1810. else
  1811. while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) < 0)
  1812. --hi;
  1813.                         
  1814.         // If the indexes have not crossed, swap if the items are not equal
  1815.         if (lo <= hi)
  1816.         {
  1817. // swap only if the items are not equal
  1818.             if (pfnCompare((LPARAM)GetCell(lo, nCol), (LPARAM)GetCell(hi, nCol), data) != 0)
  1819.             {
  1820. for (int col = 0; col < GetColumnCount(); col++)
  1821.                 {
  1822. CGridCellBase *pCell = GetCell(lo, col);
  1823.                     SetCell(lo, col, GetCell(hi, col));
  1824.                     SetCell(hi, col, pCell);
  1825.                 }
  1826.                 UINT nRowHeight = m_arRowHeights[lo];
  1827.                 m_arRowHeights[lo] = m_arRowHeights[hi];
  1828.                 m_arRowHeights[hi] = nRowHeight;
  1829.             }
  1830.                             
  1831.             ++lo;
  1832.             --hi;
  1833.          }
  1834.     }
  1835.     
  1836.     // If the right index has not reached the left side of array
  1837.     // must now sort the left partition.
  1838.     if (low < hi)
  1839.         SortItems(pfnCompare, nCol, bAscending, data, low, hi);
  1840.     
  1841.     // If the left index has not reached the right side of array
  1842.     // must now sort the right partition.
  1843.     if (lo < high)
  1844.         SortItems(pfnCompare, nCol, bAscending, data, lo, high);
  1845.     
  1846.     return TRUE;
  1847. }
  1848. // Sorts on a given column using the cell text
  1849. BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
  1850. {
  1851.     SetSortColumn(nCol);
  1852.     SetSortAscending(bAscending);
  1853. //    ResetSelectedRange();
  1854. //    SetFocusCell(-1, - 1);
  1855.     return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
  1856. }
  1857. int CALLBACK CGridCtrl::pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  1858. {
  1859. UNUSED_ALWAYS(lParamSort);
  1860. CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
  1861. CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
  1862. if (!pCell1 || !pCell2) return 0;
  1863. return _tcscmp(pCell1->GetText(), pCell2->GetText());//作字符串的比较
  1864. }
  1865. int CALLBACK CGridCtrl::pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  1866. {
  1867. UNUSED_ALWAYS(lParamSort);
  1868. CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
  1869. CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
  1870. if (!pCell1 || !pCell2) return 0;
  1871. //double// float
  1872.     double nValue1 = atof(pCell1->GetText());//_ttol(pCell1->GetText());
  1873. double nValue2 = atof(pCell2->GetText());//_ttol(pCell2->GetText());
  1874. //作数字的比较:
  1875. if (nValue1 < nValue2)
  1876. return -1;
  1877. else if (nValue1 == nValue2)
  1878. return 0;
  1879. else
  1880. return 1;
  1881. }
  1882. int CGridCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  1883. {
  1884. if (CWnd::OnCreate(lpCreateStruct) == -1)
  1885. return -1;
  1886.    TRY
  1887.     {
  1888.        //初始化数组 
  1889.    m_arRowHeights.SetSize(m_nRows);    // initialize row heights
  1890.        m_arColWidths.SetSize(m_nCols);     // initialize column widths
  1891.     }
  1892.     CATCH (CMemoryException, e)
  1893.     {
  1894.         e->ReportError();
  1895.         return FALSE;
  1896.     }
  1897.     END_CATCH
  1898.     
  1899. //填写数组:
  1900. int i;
  1901.     for (i = 0; i < m_nRows; i++)
  1902.         m_arRowHeights[i] = m_cellDefault.GetHeight();
  1903.     for (i = 0; i < m_nCols; i++)
  1904.         m_arColWidths[i] = m_cellDefault.GetWidth();
  1905. SetTimer(2,30000,NULL);//设置定时器,间隔30秒
  1906. return 0;
  1907. }
  1908. void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
  1909. {
  1910. CCellID cellid=GetCellFromPt(point);//得到鼠标点中的CellID
  1911. int row=cellid.row;
  1912. int col=cellid.col;
  1913. CGridCellBase* pCell=GetCell(row,1);//只找股票代码
  1914. CString str=pCell->GetText();//需要把str发送给父窗口
  1915. int strlen=str.GetLength();
  1916. if(strlen==0)
  1917. // return;
  1918. str="600255";
  1919. CMyGridFrame* pParent=(CMyGridFrame*)GetParent();
  1920. pParent->m_szLabel=str;
  1921. pParent->OnStringChange();
  1922. CWnd::OnLButtonDblClk(nFlags, point);
  1923. }
  1924. void CGridCtrl::ClearCells()
  1925. {
  1926.     CRect rect;
  1927. this->GetClientRect(&rect);
  1928. CCellRange Selection=this->GetVisibleNonFixedCellRange(rect);
  1929. for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
  1930.     {
  1931.         for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
  1932.         {
  1933.             // don't clear hidden cells
  1934.             if ( m_arRowHeights[row] > 0 && m_arColWidths[col] > 0 )
  1935.             {
  1936.                 SetItemText(row, col, _T(""));
  1937. SetItemBkColor(row,col,GetDefaultCell(FALSE,FALSE)->GetBackClr());
  1938.             }
  1939. }
  1940. }
  1941.     Refresh();
  1942. }
  1943. void CGridCtrl::OnTimer(UINT nIDEvent) 
  1944. {
  1945. //if(m_nSortColumn!=-1)
  1946. //{
  1947. SortItems(GetSortColumn(),GetSortAscending());
  1948. Refresh();
  1949. //}
  1950. CWnd::OnTimer(nIDEvent);
  1951. }
  1952. CScrollBar* CGridCtrl::GetScrollBarCtrl(int nBar) const
  1953. {
  1954. return ((CMyGridFrame*)GetParent())->GetScrollBar(nBar);  
  1955. // return CWnd::GetScrollBarCtrl(nBar);
  1956. }
  1957. void CGridCtrl::OnDestroy() 
  1958. {
  1959. CWnd::OnDestroy();
  1960. KillTimer(2);
  1961. }