⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rowview.cpp

📁 VC++技术内幕(第四版)的实例
💻 CPP
字号:
// rowview.cpp : implementation of the CRowView class (MM_TEXT)
//

#include "stdafx.h"
#include "resource.h" // for IDS_TOO_MANY_ROWS
#include "rowview.h"
#include <limits.h> // for INT_MAX

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CRowView, CScrollView)

///////////////////////////////////////////////////////////////
// CRowView

BEGIN_MESSAGE_MAP(CRowView, CScrollView)
    //{{AFX_MSG_MAP(CRowView)
    ON_WM_KEYDOWN()
    ON_WM_SIZE()
    ON_WM_LBUTTONDOWN()
    //}}AFX_MSG_MAP
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////
// CRowView construction, initialization, and destruction

CRowView::CRowView()
{
    m_nPrevSelectedRow = 0;
}

CRowView::~CRowView()
{
}

///////////////////////////////////////////////////////////////
// CRowView updating and drawing

void CRowView::OnInitialUpdate()
{
    m_nPrevRowCount = GetRowCount();
    m_nPrevSelectedRow = GetActiveRow();
    OnUpdate(this, 0, NULL);
}

///////////////////////////////////////////////////////////////
void CRowView::UpdateRow(int nInvalidRow)
{
    int nRowCount = GetRowCount();
    // If the number of rows has changed, adjust
    //  the scrolling range.
    if (nRowCount != m_nPrevRowCount) {
      UpdateScrollSizes();
      m_nPrevRowCount = nRowCount;
    }

    // When the currently selected row changes, scroll the view
    //  so that the newly selected row is visible, and ask the
    //  derived class to repaint the selected and previously
    //  selected rows.

    CClientDC dc(this);
    OnPrepareDC(&dc);

    // Determine the range of the rows that are currently fully
    //  visible in the window.  We want to do discrete
    //  scrolling so that the next or previous row is always
    //  fully visible.

    int   nFirstRow, nLastRow;
    CRect rectClient;

    GetClientRect(&rectClient);
    dc.DPtoLP(&rectClient);
    RectLPtoRowRange(rectClient, nFirstRow, nLastRow, FALSE);

    // If necessary, scroll the window so that the newly
    //  selected row is visible.

    CPoint pt = GetDeviceScrollPosition();
    BOOL   bNeedToScroll = TRUE;

    if (nInvalidRow < nFirstRow) {
      // The newly selected row is above those currently
      //  visible in the window. Scroll so that the newly
      //  selected row is at the very top of the window.
      //  The last row in the window might be only
      //  partially visible.
      pt.y = RowToYPos(nInvalidRow);
    }
    else if (nInvalidRow > nLastRow){
      // The newly selected row is below those currently
      //  visible in the window.  Scroll so that the newly
      //  selected row is at the very bottom of the window.
      //  The first row in the window might be only
      //  partially visible.
      pt.y = max(0, RowToYPos(nInvalidRow+1) -
                 rectClient.Height());
    }
    else {
      bNeedToScroll = FALSE;
    }
    if (bNeedToScroll) {
      ScrollToDevicePosition(pt);
      // Scrolling will cause the newly selected row to be
      //  redrawn in the invalidated area of the window.

      OnPrepareDC(&dc);  // Need to prepare the DC again
                         //  because ScrollToDevicePosition()
                         //  will have changed the viewport
                         //  origin. The DC is used some
                         //  more below.
    }

    CRect rectInvalid =
              RowToWndRect(&dc, nInvalidRow);
    InvalidateRect(&rectInvalid);

    // Give the derived class an opportunity to repaint the
    //  previously selected row, perhaps to un-highlight it.

    int nSelectedRow = GetActiveRow();
    if (m_nPrevSelectedRow != nSelectedRow) {
      CRect rectOldSelection =
                   RowToWndRect(&dc, m_nPrevSelectedRow);
      InvalidateRect(&rectOldSelection);
      m_nPrevSelectedRow = nSelectedRow;
    }
}

///////////////////////////////////////////////////////////////
void CRowView::UpdateScrollSizes()
{
    // UpdateScrollSizes() is called when it is necessary to
    //  adjust the scrolling range or page/line sizes. There
    //  are two occasions when this is necessary:
    //
    //  1. when a new row is added--see UpdateRow()
    //  2. when the window size changes--see OnSize()

    CRect rectClient;
    GetClientRect(&rectClient);

    CClientDC dc(this);
    CalculateRowMetrics(&dc);

    // The vertical scrolling range is the total display
    //  height of all the rows.
    CSize sizeTotal(m_nRowWidth, m_nRowHeight *
                   (min(GetRowCount(), LastViewableRow())));

    // The vertical per-page scrolling distance is equal to the
    //  number of rows that can be displayed in the current
    //  window, less one row for paging overlap.
    CSize sizePage(m_nRowWidth / 5, max(m_nRowHeight,
                  ((rectClient.bottom / m_nRowHeight) - 1) *
                    m_nRowHeight));

    // The vertical per-line scrolling distance is equal to the
    //  height of the row.
    CSize sizeLine(m_nRowWidth / 20, m_nRowHeight);

    SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
}


///////////////////////////////////////////////////////////////
void CRowView::OnDraw(CDC* pDC)
{
    if (GetRowCount() == 0) {
      return;
    }
    // The window has been invalidated and needs to be
    //  repainted, or a page needs to be printed (or previewed).
    // First, determine the range of rows that need to be
    //  displayed or printed.

    int   nFirstRow, nLastRow;
    CRect rectClip;
    pDC->GetClipBox(&rectClip); // Get the invalidated region.
    RectLPtoRowRange(rectClip, nFirstRow, nLastRow, TRUE);

    // Draw each row in the invalidated region of the window,
    //  or on the printed (previewed) page.

    int nActiveRow = GetActiveRow();
    int nRow, y;
    int nLastViewableRow = LastViewableRow();

    for (nRow = nFirstRow,  y = m_nRowHeight * nFirstRow;
         nRow <= nLastRow; nRow++, y += m_nRowHeight) {
      if (nRow >= (nLastViewableRow - 1)) {
        CString strWarning;
        strWarning.LoadString(IDS_TOO_MANY_ROWS);
        pDC->TextOut(0, y, strWarning);
        break;
      }
      // Prepare for highlighting or un-highlighting the row,
      //  depending on whether or not it is the currently 
      //  selected row. And paint the background (behind the
      //  text) accordingly.
      CBrush brushBackground;
      COLORREF crOldText, crOldBackground;
      if (!pDC->IsPrinting()) {
        if (nRow == nActiveRow) {
          brushBackground.CreateSolidBrush(
                        ::GetSysColor(COLOR_HIGHLIGHT));
          crOldBackground = pDC->SetBkColor(
                        ::GetSysColor(COLOR_HIGHLIGHT));
          crOldText = pDC->SetTextColor(
                        ::GetSysColor(COLOR_HIGHLIGHTTEXT));
        }
        else {
          brushBackground.CreateSolidBrush(
                        ::GetSysColor(COLOR_WINDOW));
        }

        CRect rectSelection;
        pDC->GetClipBox(&rectSelection);
        rectSelection.top = y;
        rectSelection.bottom = y + m_nRowHeight;
        pDC->FillRect(&rectSelection, &brushBackground);
      }
      OnDrawRow(pDC, nRow, y, nRow == nActiveRow);
      // Restore the DC. (MOVED FROM DERIVED CLASS)
      if (!pDC->IsPrinting() && (nRow == nActiveRow)) {
        pDC->SetBkColor(crOldBackground);
        pDC->SetTextColor(crOldText);
      }
    }
}

///////////////////////////////////////////////////////////////
// Implementation

int CRowView::RowToYPos(int nRow)
{
    return (nRow * m_nRowHeight);
}

///////////////////////////////////////////////////////////////
CRect CRowView::RowToWndRect(CDC* pDC, int nRow)
{
    CRect clientRect;

    GetClientRect(clientRect);
    pDC->DPtoLP(clientRect);
    CRect rect(clientRect.left, nRow * m_nRowHeight,
               clientRect.right, (nRow + 1) * m_nRowHeight);
    pDC->LPtoDP(&rect);
    return rect;
}

///////////////////////////////////////////////////////////////
int CRowView::LastViewableRow()
{
    return (INT_MAX / m_nRowHeight - 1);
}

///////////////////////////////////////////////////////////////
void CRowView::RectLPtoRowRange(const CRect& rect,
                                int& nFirstRow,
                                int& nLastRow,
                                BOOL bIncludePartiallyShownRows)
{
    int nRounding = bIncludePartiallyShownRows ?
                      0 : (m_nRowHeight - 1);
    nFirstRow = (rect.top + nRounding) / m_nRowHeight;
    nLastRow = min((rect.bottom - nRounding) / m_nRowHeight,
                    GetRowCount() - 1);
}

///////////////////////////////////////////////////////////////
void CRowView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
    // The size of text that is displayed, printed, or
    //  previewed changes depending on the DC.  We explicitly
    //  call OnPrepareDC() to prepare CClientDC objects used
    //  for calculating text positions and to prepare the text
    //  metric member variables of the CRowView object. The
    //  application framework also calls OnPrepareDC() before
    //  passing the DC to OnDraw().

    CScrollView::OnPrepareDC(pDC, pInfo);
    CalculateRowMetrics(pDC);
}

///////////////////////////////////////////////////////////////
// Overrides of CView for implementing printing

BOOL CRowView::OnPreparePrinting(CPrintInfo* pInfo)
{
    return DoPreparePrinting(pInfo);
}

///////////////////////////////////////////////////////////////
void CRowView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
    // OnBeginPrinting() is called after the user has committed
    //  to printing by OKing the Print dialog and after the
    //  application framework has created a CDC object for the
    //  printer or print preview.

    // This is the best opportunity to set up the page range.
    // Given the CDC object, we can determine how many rows
    //  will fit on a page, so we can in turn determine how
    //  many printed pages represent the entire document.

    int nPageHeight = pDC->GetDeviceCaps(VERTRES);
    CalculateRowMetrics(pDC);
    m_nRowsPerPrintedPage = nPageHeight / m_nRowHeight;
    int nPrintableRowCount = LastViewableRow() + 1;
    if (GetRowCount() < nPrintableRowCount) {
      nPrintableRowCount = GetRowCount();
    }
    pInfo->SetMaxPage((nPrintableRowCount +
                       m_nRowsPerPrintedPage - 1) /
                       m_nRowsPerPrintedPage);
    pInfo->m_nCurPage = 1;  // start previewing at page 1
}

///////////////////////////////////////////////////////////////
void CRowView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
    // Print the rows for the current page.

    int yTopOfPage = (pInfo->m_nCurPage -1) *
                      m_nRowsPerPrintedPage * m_nRowHeight;

    // Orient the viewport so that the first row to be printed
    //  has a viewport coordinate of (0, 0).
    pDC->SetViewportOrg(0, -yTopOfPage);

    // Draw as many rows as will fit on the printed page.
    // Clip the printed page so that there is no partially
    //  shown row at the bottom of the page (the same row that
    //  will be fully shown at the top of the next page).

    int nPageWidth = pDC->GetDeviceCaps(HORZRES);

    CRect rectClip = CRect(0, yTopOfPage, nPageWidth, yTopOfPage +
                           m_nRowsPerPrintedPage * m_nRowHeight);
    pDC->IntersectClipRect(&rectClip);
    OnDraw(pDC);
}

///////////////////////////////////////////////////////////////
// CRowView commands


void CRowView::OnSize(UINT nType, int cx, int cy)
{
    UpdateScrollSizes();
    CScrollView::OnSize(nType, cx, cy);
}

///////////////////////////////////////////////////////////////
void CRowView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    CRect clientRect;

    GetClientRect(clientRect);
    CClientDC dc(this);
    dc.DPtoLP(clientRect);
    
    switch (nChar)
    {
      case VK_HOME:
          ChangeSelectionToRow(0);
          break;
      case VK_END:
          ChangeSelectionToRow(min(GetRowCount() - 1,
                               LastViewableRow() - 2));
          break;
      case VK_UP:
          ChangeSelectionNextRow(FALSE);
          break;
      case VK_DOWN:
          ChangeSelectionNextRow(TRUE);
          break;
      case VK_LEFT:
          if (clientRect.Width() < GetTotalSize().cx) {
              OnHScroll(SB_LINELEFT, 0, NULL);
          }
          break;
      case VK_RIGHT:
          if (clientRect.Width() < GetTotalSize().cx) {
              OnHScroll(SB_LINERIGHT, 0, NULL);
          }
          break;
      case VK_PRIOR:
          if (clientRect.Height() < GetTotalSize().cy) {
              OnVScroll(SB_PAGEUP, 0, NULL);
          }
          break;
      case VK_NEXT:
          if (clientRect.Height() < GetTotalSize().cy) {
              OnVScroll(SB_PAGEDOWN, 0, NULL);
          }
          break;
        default:
          CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
    }
}

///////////////////////////////////////////////////////////////
void CRowView::OnLButtonDown(UINT, CPoint point)
{
    CClientDC dc(this);
    OnPrepareDC(&dc);
    dc.DPtoLP(&point);

    CRect rect(point, CSize(1,1));
    int   nFirstRow, nLastRow;

    RectLPtoRowRange(rect, nFirstRow, nLastRow, TRUE);
    if (nFirstRow <= (GetRowCount() - 1)) {
      ChangeSelectionToRow(nFirstRow);
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -