略谈如何在对话框创建视图类画图

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

作者:朱金灿

来源:blog.csdn.net/clever101

 

     在对话框上画图可以通过添加控件来进行,但这种画图有一个严重弊端就是画图范围受控件范围控制。最近做一个程序,需要一个数据报告窗口,因为输出的内容比较多,格式不一致(涉及多个表,但每个表的数据要严格对齐),所以如ListControl等控件并不适合。所以我想到在对话框上创建视图类上进行数据显示。

 

一是视图窗口如何动态创建。首先是视图窗口的定位。一般的动态创建窗口定位窗口的位置不太容易。我从网上找到的一个好办法在对话框上加一个静态文本控件,然后把视图创建在该控件之上。这个问题想好,创建就基本完成了。

 

创建的具体步骤如下:

1.     定义一个派生自CScrollView类的视图类CDrawView(至于为什么不是CView而是CScrollView,原因我会在下面谈)。

 

2. 在对话框类上定义一个CDrawView类指针*m_pDrawView

具体代码如何:

  1. BOOL CStaticDataReport::OnInitDialog()  
  2. {  
  3.     CDialog::OnInitDialog();  
  4.   
  5.     UINT TargetCtrlID = IDC_STATIC;  
  6.     CWnd *pWnd = this->GetDlgItem(TargetCtrlID);  
  7.     CRect RectTargetCtrl;  
  8.     pWnd->GetWindowRect(RectTargetCtrl);  
  9.     pWnd->DestroyWindow();  
  10.     this->ScreenToClient(RectTargetCtrl);  
  11.   
  12.     //在目标位置动态创建CScrollView  
  13.     if (NULL==m_pDrawView)  
  14.     {  
  15.         return FALSE;  
  16.     }  
  17.     m_pDrawView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW|WS_VSCROLL|WS_HSCROLL, RectTargetCtrl, this, TargetCtrlID);  
  18.     m_pDrawView->ShowWindow(SW_SHOW);  
  19.     return TRUE;  
  20. }  
BOOL CStaticDataReport::OnInitDialog(){ CDialog::OnInitDialog(); UINT TargetCtrlID = IDC_STATIC; CWnd *pWnd = this->GetDlgItem(TargetCtrlID); CRect RectTargetCtrl; pWnd->GetWindowRect(RectTargetCtrl); pWnd->DestroyWindow(); this->ScreenToClient(RectTargetCtrl); //在目标位置动态创建CScrollView if (NULL==m_pDrawView) {  return FALSE; } m_pDrawView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW|WS_VSCROLL|WS_HSCROLL, RectTargetCtrl, this, TargetCtrlID); m_pDrawView->ShowWindow(SW_SHOW); return TRUE;}

二.前面我已经谈到了在对话框上绘图的一个弊端是绘图范围受控件范围所谓,一不小心就会出界,如下图所示:

  绘图范围受控件范围所

  

 使用视图类的好处是你可以使用滚动条扩大绘图范围,这也是我为何将自定义视图类继承CScrollView类的原因。

 

   实际上滚动条的处理也是不太容易的,主要是滚动条添加后如何重绘新的显示范围比较麻烦。为此我重翻petzod的名著《Windows程序设计》的里面一节:建立更好的滚动。将里面的Win API代码改为MFC实现。因为我的程序是输出文字的,我就以如何在文字输出视图窗口创建滚动条。

 

   首先要创建窗口的滚动条,你就必须在动态创建是指定两种窗口风格:WS_VSCROLL|WS_HSCROLL

 

   其次你需要指定窗口的滚动范围,具体就是滚动的最大高度和宽度。我的做法是在视图类定义两个变量:

    int m_iMaxWidth;    // 滚动的的最大宽度

    int m_MaxNumLines;  // 滚动的最大高度

 

这个你可以自定义滚动范围。

 

其次你还要定义一些文字大小的相关变量:

    int m_cxChar;

    int m_cxCaps;

    int m_cyChar;

 

OnCreate函数()(WM_CREATE消息映射函数)获取字体大小,代码如下:

 

 

  1. int CDrawView::OnCreate(LPCREATESTRUCT lpCreateStruct)   
  2. {  
  3.     if (CScrollView::OnCreate(lpCreateStruct) == -1)  
  4.         return -1;  
  5.   
  6.     // TODO: Add your specialized creation code here  
  7.     CDC *pDC = GetDC();  
  8.     TEXTMETRIC  tm ;  
  9.     pDC->GetTextMetrics(&tm) ;  
  10.   
  11.     m_cxChar = tm.tmAveCharWidth ;  
  12.   
  13.     m_cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * m_cxChar / 2 ;  
  14.   
  15.     m_cyChar = tm.tmHeight + tm.tmExternalLeading ;  
  16.     ReleaseDC(pDC);  
  17.   
  18.     return 0;  
  19. }  
int CDrawView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CScrollView::OnCreate(lpCreateStruct) == -1)  return -1; // TODO: Add your specialized creation code here CDC *pDC = GetDC(); TEXTMETRIC  tm ; pDC->GetTextMetrics(&tm) ; m_cxChar = tm.tmAveCharWidth ; m_cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * m_cxChar / 2 ; m_cyChar = tm.tmHeight + tm.tmExternalLeading ;    ReleaseDC(pDC); return 0;}

 

OnSize函数(WM_SIZE消息映射函数)设置滚动范围:

[c-sharp] view plain copy print ?
  1. void CDrawView::OnSize(UINT nType, int cx, int cy)  
  2. {  
  3.     SCROLLINFO  si ;  
  4.   
  5.     si.cbSize     = sizeof (si) ;  
  6.   
  7.     si.fMask      = SIF_RANGE | SIF_PAGE ;  
  8.   
  9.     si.nMin       = 0 ;  
  10.   
  11.     si.nMax       = m_MaxNumLines - 1 ;  
  12.   
  13.     si.nPage      = cy/m_cyChar ;  
  14.   
  15.     SetScrollInfo (SB_VERT, &si, TRUE) ;  
  16.   
  17.     // Set horizontal scroll bar range and page size  
  18.     si.cbSize     = sizeof (si) ;  
  19.   
  20.     si.fMask      = SIF_RANGE | SIF_PAGE ;  
  21.   
  22.     si.nMin       = 0 ;  
  23.   
  24.     si.nMax  = m_iMaxWidth;  
  25.   
  26.     si.nPage      = cx/m_cxChar ;  
  27.   
  28.     SetScrollInfo (SB_HORZ, &si, TRUE) ;  
  29.   
  30. }  
void CDrawView::OnSize(UINT nType, int cx, int cy){ SCROLLINFO  si ; si.cbSize     = sizeof (si) ; si.fMask      = SIF_RANGE | SIF_PAGE ; si.nMin       = 0 ; si.nMax       = m_MaxNumLines - 1 ; si.nPage      = cy/m_cyChar ; SetScrollInfo (SB_VERT, &si, TRUE) ; // Set horizontal scroll bar range and page size si.cbSize     = sizeof (si) ; si.fMask      = SIF_RANGE | SIF_PAGE ; si.nMin       = 0 ;    si.nMax  = m_iMaxWidth; si.nPage      = cx/m_cxChar ; SetScrollInfo (SB_HORZ, &si, TRUE) ;}

分别响应WM_VSCROLL消息和WM_HSCROLL,主要目的是设置滚定信息和决定是否要更新窗口:

  1. void CDrawView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.     SCROLLINFO  si ;  
  5.     si.cbSize     = sizeof (si) ;  
  6.     si.fMask      = SIF_ALL ;  
  7.     GetScrollInfo (SB_VERT, &si) ;  
  8.     // Save the position for comparison later on  
  9.   
  10.     int iVertPos = si.nPos ;  
  11.     switch (nSBCode)  
  12.     {  
  13.     case   SB_TOP:  
  14.         si.nPos       = si.nMin ;  
  15.         break ;  
  16.     case   SB_BOTTOM:  
  17.         si.nPos       = si.nMax ;  
  18.         break ;  
  19.     case SB_LINEUP:  
  20.         si.nPos -= 1 ;  
  21.         break ;  
  22.     case   SB_LINEDOWN:  
  23.         si.nPos += 1 ;  
  24.         break ;  
  25.     case   SB_PAGEUP:  
  26.         si.nPos -= si.nPage ;  
  27.         break ;  
  28.     case   SB_PAGEDOWN:  
  29.         si.nPos += si.nPage ;  
  30.         break ;  
  31.     case   SB_THUMBTRACK:  
  32.         si.nPos = si.nTrackPos ;  
  33.         break ;  
  34.     default:  
  35.         break ;         
  36.   
  37.     }  
  38.   
  39.     // Set the position and then retrieve it.  Due to adjustments  
  40.   
  41.     //  by Windows it may not be the same as the value set.  
  42.     si.fMask = SIF_POS ;  
  43.   
  44.     SetScrollInfo(SB_VERT, &si, TRUE) ;  
  45.   
  46.     GetScrollInfo(SB_VERT, &si) ;  
  47.     // If the position has changed, scroll the window and update it  
  48.   
  49.     if (si.nPos != iVertPos)  
  50.     {                    
  51.         ScrollWindow (0, m_cyChar * (iVertPos - si.nPos),NULL, NULL) ;  
  52.         UpdateWindow() ;  
  53.   
  54.     }  
  55.   
  56.     CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);  
  57. }  
  58.   
  59. void CDrawView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)   
  60. {  
  61.     // TODO: Add your message handler code here and/or call default  
  62.     // Get the minimum and maximum scroll-bar positions.  
  63.     // Get all the vertical scroll bar information  
  64.   
  65.     int minpos=0;  
  66.     int maxpos = 2 + m_iMaxWidth/m_cxChar ;  
  67.   
  68.     SCROLLINFO  si ;  
  69.     si.cbSize = sizeof (si) ;  
  70.     si.fMask  = SIF_ALL ;  
  71.   
  72.     // Save the position for comparison later on  
  73.     GetScrollInfo (SB_HORZ, &si) ;  
  74.     int iHorzPos = si.nPos ;  
  75.   
  76.     switch (nSBCode)  
  77.     {  
  78.     case SB_LEFT:      // Scroll to far left.  
  79.         si.nPos = minpos;  
  80.         break;  
  81.   
  82.     case SB_RIGHT:      // Scroll to far right.  
  83.         si.nPos = maxpos;  
  84.         break;  
  85.   
  86.     case SB_ENDSCROLL:   // End scroll.  
  87.         break;  
  88.   
  89.     case SB_LINELEFT:      // Scroll left.  
  90.         if (si.nPos > minpos)  
  91.             si.nPos--;  
  92.         break;  
  93.   
  94.     case SB_LINERIGHT:   // Scroll right.  
  95.         if (si.nPos < maxpos)  
  96.             si.nPos++;  
  97.         break;  
  98.   
  99.     case SB_PAGELEFT:    // Scroll one page left.  
  100.         {  
  101.             // Get the page size.   
  102.             SCROLLINFO   info;  
  103.             GetScrollInfo (SIF_ALL, &info) ;  
  104.             //          pScrollBar->GetScrollInfo(&info, SIF_ALL);  
  105.   
  106.             if (si.nPos > minpos)  
  107.                 si.nPos = max(minpos, si.nPos - (int) info.nPage);  
  108.         }  
  109.         break;  
  110.   
  111.     case SB_PAGERIGHT:      // Scroll one page right.  
  112.         {  
  113.             // Get the page size.   
  114.             SCROLLINFO   info;  
  115.             GetScrollInfo (SIF_ALL, &info) ;  
  116.             //          pScrollBar->GetScrollInfo(&info, SIF_ALL);  
  117.   
  118.             if (si.nPos < maxpos)  
  119.                 si.nPos = min(maxpos, si.nPos + (int) info.nPage);  
  120.         }  
  121.         break;  
  122.   
  123.     case SB_THUMBPOSITION: // Scroll to absolute position. nPos is the position  
  124.         si.nPos = nPos;      // of the scroll box at the end of the drag operation.  
  125.         break;  
  126.   
  127.     case SB_THUMBTRACK:   // Drag scroll box to specified position. nPos is the  
  128.         si.nPos = nPos;     // position that the scroll box has been dragged to.  
  129.         break;  
  130.     }  
  131.   
  132.     si.fMask = SIF_POS ;  
  133.   
  134.     SetScrollInfo (SB_HORZ, &si, TRUE) ;  
  135.   
  136.     GetScrollInfo (SB_HORZ, &si) ;  
  137.     // If the position has changed, scroll the window  
  138.     if (si.nPos != iHorzPos)  
  139.     {  
  140. ScrollWindow (m_cxChar * (iHorzPos - si.nPos), 0,NULL, NULL) ;  
  141.     }  
  142.     CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);  
  143. }  
void CDrawView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: Add your message handler code here and/or call default SCROLLINFO  si ; si.cbSize     = sizeof (si) ; si.fMask      = SIF_ALL ; GetScrollInfo (SB_VERT, &si) ; // Save the position for comparison later on int iVertPos = si.nPos ; switch (nSBCode) { case   SB_TOP:  si.nPos       = si.nMin ;  break ; case   SB_BOTTOM:  si.nPos       = si.nMax ;  break ; case SB_LINEUP:  si.nPos -= 1 ;  break ; case   SB_LINEDOWN:  si.nPos += 1 ;  break ; case   SB_PAGEUP:  si.nPos -= si.nPage ;  break ; case   SB_PAGEDOWN:  si.nPos += si.nPage ;  break ; case   SB_THUMBTRACK:  si.nPos = si.nTrackPos ;  break ; default:  break ;        } // Set the position and then retrieve it.  Due to adjustments //  by Windows it may not be the same as the value set. si.fMask = SIF_POS ; SetScrollInfo(SB_VERT, &si, TRUE) ; GetScrollInfo(SB_VERT, &si) ; // If the position has changed, scroll the window and update it if (si.nPos != iVertPos) {                    ScrollWindow (0, m_cyChar * (iVertPos - si.nPos),NULL, NULL) ;  UpdateWindow() ; } CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);}void CDrawView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: Add your message handler code here and/or call default // Get the minimum and maximum scroll-bar positions. // Get all the vertical scroll bar information int minpos=0; int maxpos = 2 + m_iMaxWidth/m_cxChar ; SCROLLINFO  si ; si.cbSize = sizeof (si) ; si.fMask  = SIF_ALL ; // Save the position for comparison later on GetScrollInfo (SB_HORZ, &si) ; int iHorzPos = si.nPos ; switch (nSBCode) { case SB_LEFT:      // Scroll to far left.  si.nPos = minpos;  break; case SB_RIGHT:      // Scroll to far right.  si.nPos = maxpos;  break; case SB_ENDSCROLL:   // End scroll.  break; case SB_LINELEFT:      // Scroll left.  if (si.nPos > minpos)   si.nPos--;  break; case SB_LINERIGHT:   // Scroll right.  if (si.nPos < maxpos)   si.nPos++;  break; case SB_PAGELEFT:    // Scroll one page left.  {   // Get the page size.    SCROLLINFO   info;   GetScrollInfo (SIF_ALL, &info) ;   //   pScrollBar->GetScrollInfo(&info, SIF_ALL);   if (si.nPos > minpos)    si.nPos = max(minpos, si.nPos - (int) info.nPage);  }  break; case SB_PAGERIGHT:      // Scroll one page right.  {   // Get the page size.    SCROLLINFO   info;   GetScrollInfo (SIF_ALL, &info) ;   //   pScrollBar->GetScrollInfo(&info, SIF_ALL);   if (si.nPos < maxpos)    si.nPos = min(maxpos, si.nPos + (int) info.nPage);  }  break; case SB_THUMBPOSITION: // Scroll to absolute position. nPos is the position  si.nPos = nPos;      // of the scroll box at the end of the drag operation.  break; case SB_THUMBTRACK:   // Drag scroll box to specified position. nPos is the  si.nPos = nPos;     // position that the scroll box has been dragged to.  break; } si.fMask = SIF_POS ; SetScrollInfo (SB_HORZ, &si, TRUE) ; GetScrollInfo (SB_HORZ, &si) ; // If the position has changed, scroll the window if (si.nPos != iHorzPos) {ScrollWindow (m_cxChar * (iHorzPos - si.nPos), 0,NULL, NULL) ; } CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);}

然后在OnPaint函数(WM_PAINT消息响应函数)你就可以获取当前绘图范围了:

  1. void CDrawView::OnPaint()   
  2. {  
  3.     CPaintDC dc(this); // device context for painting  
  4. SCROLLINFO  si ;  
  5.     si.cbSize = sizeof (si) ;  
  6.   
  7.     si.fMask  = SIF_POS ;  
  8.   
  9.     GetScrollInfo(SB_VERT, &si) ;  
  10.     int iVertPos = si.nPos ;  
  11.     // Get horizontal scroll bar position  
  12.   
  13.     GetScrollInfo (SB_HORZ, &si) ;  
  14.     int iHorzPos = si.nPos ;  
  15.   
  16.     // Find painting limits  
  17.     int iPaintBeg = max(0,iVertPos + dc.m_ps.rcPaint.top /m_cyChar) ;  
  18.     int iPaintEnd = min(m_MaxNumLines - 1,iVertPos + dc.m_ps.rcPaint.bottom/m_cyChar);  
  19.   
  20.     int x = 0;  
  21.     int y = 0;  
  22.     int i = 0;  
  23.     int j =0;  
  24. // iPaintBeg为绘图起始行,iPaintEnd为绘图结束行  
  25.     for (i = iPaintBeg ; i <= iPaintEnd;i++)  
  26.     {  
  27.          
  28. ……  
  29. }  
  30.   
  31. }  
void CDrawView::OnPaint() { CPaintDC dc(this); // device context for paintingSCROLLINFO  si ; si.cbSize = sizeof (si) ; si.fMask  = SIF_POS ; GetScrollInfo(SB_VERT, &si) ; int iVertPos = si.nPos ; // Get horizontal scroll bar position GetScrollInfo (SB_HORZ, &si) ; int iHorzPos = si.nPos ; // Find painting limits int iPaintBeg = max(0,iVertPos + dc.m_ps.rcPaint.top /m_cyChar) ; int iPaintEnd = min(m_MaxNumLines - 1,iVertPos + dc.m_ps.rcPaint.bottom/m_cyChar); int x = 0; int y = 0; int i = 0; int j =0;// iPaintBeg为绘图起始行,iPaintEnd为绘图结束行 for (i = iPaintBeg ; i <= iPaintEnd;i++) {       ……}}

效果图如下:

效果图

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/gdruhv/article/details/84194697