﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Thinking in C++-文章分类-VC</title><link>http://www.cppblog.com/yishanhante/category/3726.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 01:29:33 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 01:29:33 GMT</pubDate><ttl>60</ttl><item><title>使用VC6.0实现窗口的任意分割[转]</title><link>http://www.cppblog.com/yishanhante/articles/20772.html</link><dc:creator>jay</dc:creator><author>jay</author><pubDate>Wed, 28 Mar 2007 07:20:00 GMT</pubDate><guid>http://www.cppblog.com/yishanhante/articles/20772.html</guid><wfw:comment>http://www.cppblog.com/yishanhante/comments/20772.html</wfw:comment><comments>http://www.cppblog.com/yishanhante/articles/20772.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yishanhante/comments/commentRss/20772.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yishanhante/services/trackbacks/20772.html</trackback:ping><description><![CDATA[
		<p>
				<b>一、关于CSplitterWnd类</b>
				<br />我们在使用CuteFtp或者NetAnt等工具的时候，一般都会被其复杂的界面所吸引，在这些界面中窗口被分割为若干的区域，真正做到了窗口的任意分割。 那么我们自己如何创建类似的界面，也实现窗口的任意的分割呢 ？在VC6.0中这就需要使用到CSplitterWnd类。CSplitterWnd看上去像是一种特殊的框架窗口，每个窗口都被相同的或者不同的视图所填充。当窗口被切分后用户可以使用鼠标移动切分条来调整窗口的相对尺寸。虽然VC6.0支持从AppWizard中创建分割窗口，但是自动加入的分割条总是不能让我们满意，因此我们还是通过手工增加代码来熟悉这个类。 <br />CSplitterWnd的构造函数主要包括下面三个。 <br /></p>
		<pre>BOOL Create(CWnd* pParentWnd,int nMaxRows,int nMaxCols,SIZE sizeMin,CCreateContext* pContext,DWORD dwStyle,UINT nID);</pre>功能描述：该函数用来创建动态切分窗口。 参数含义：pParentWnd 切分窗口的父框架窗口。 nMaxRows,nMaxCols是创建的最大的列数和行数。 sizeMin是窗格的现实大小。 pContext 大多数情况下传给父窗口。 nID是字窗口的ID号. <pre>BOOL CreateStatic(CWnd* pParentWnd,int nRows,int nCols,DWORD dwStyle,UINT nID) </pre>功能描述：用来创建切分窗口。 参数含义同上。 <pre>BOOL CreateView (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext);</pre>功能描述：为静态切分的窗口的网格填充视图。在将视图于切分窗口联系在一起的时候必 须先将切分窗口创建好。 <br />参数含义：同上。<br />从CSplitterWnd源程序可以看出不管是使用动态创建Create还是使用静态创建CreateStatic，在函数中都调用了一个保护函数CreateCommon，从下面的CreateCommon函数中的关键代码可以看出创建CSplitterWnd的实质是创建了一系列的MDI子窗口。 <br /><pre>DWORD dwCreateStyle = dwStyle &amp; ~(WS_HSCROLL|WS_VSCROLL);
if (afxData.bWin4) 
       dwCreateStyle &amp;= ~WS_BORDER; //create with the same wnd-class as MDI-Frame (no erase bkgnd) 
if (!CreateEx(0, _afxWndMDIFrame, NULL, dwCreateStyle, 
          0, 0, 0, 0,pParentWnd-&gt;m_hWnd, (HMENU)nID, NULL)) 
       return FALSE; // create invisible 
          </pre><br /><b>二、创建嵌套分割窗口</b><br /><b>2.1创建动态分割窗口</b><br />动态分割窗口使用Create方法。下面的代码将创建2x2的窗格。 <br /><pre>m_wndSplitter.Create(this,2,2,CSize(100,100),pContext);</pre><br />但是动态创建的分割窗口的窗格数目不能超过2x2，而且对于所有的窗格，都必须共享同一个视图，所受的限制也比较多，因此我们不将动态创建作为重点。我们的主要精力放在静态分割窗口的创建上。 <br /><b>2.2创建静态分割窗口</b><br />与动态创建相比，静态创建的代码要简单许多，而且可以最多创建16x16的窗格。不同的窗格我们可以使用CreateView填充不同的视图。 <br />在这里我们将创建CuteFtp的窗口分割。CuteFtp的分割情况如下： 
<div align="center"><table height="223" cellspacing="1" cellpadding="0" width="446" bgcolor="#666666" border="0"><tbody><tr bgcolor="#eeeeee"><td colspan="2" height="46"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CCuteFTPView</font></div></td></tr><tr bgcolor="#eeeeee"><td height="123"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CView2</font></div></td><td height="123"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CView3</font></div></td></tr><tr bgcolor="#eeeeee"><td colspan="2" height="44"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CView4</font></div></td></tr></tbody></table></div><p>创建步骤： <br />▲ 在创建之前我们必须先用AppWizard生成单文档CuteFTP，生成的视类为 CCuteFTPView.同时在增加三个视类或者从视类继承而来的派生类CView2,CView3 CView4. <br />▲ <b>增加成员：</b><br />在Cmainfrm.h中我们将增加下面的代码： <br /></p><pre>CSplitterWnd wndSplitter1;
                  CSplitterWnd wndSplitter2;</pre>▲ <b>重载CMainFrame::OnCreateClient()函数：</b><pre>BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT  /*lpcs*/, CCreateContext* pContext) 
{ //创建一个静态分栏窗口，分为三行一列 
     if(m_wndSplitter1.CreateStatic(this,3,1)==NULL) 
              return FALSE;
  //将CCuteFTPView连接到0行0列窗格上
     m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CCuteFTPView),CSize(100,100), pContext); 
     m_wndSplitter1.CreateView(2,0,RUNTIME_CLASS(CView4),CSize(100,100),pContext); 
  //将CView4连接到0行2列
     if(m_wndSplitter2.CreateStatic(&amp;m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE, 
          m_wndSplitter.IdFromRowCol(1, 0))==NULL) 
               return FALSE; //将第1行0列再分开1行2列 
  //将CView2类连接到第二个分栏对象的0行0列
          m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(400,300),pContext); 
  //将CView3类连接到第二个分栏对象的0行1列
          m_wndSplitter2.CreateView(0,1,RUNTIME_CLASS(CView3),CSize(400,300),pContext); 
               return TRUE; 
} </pre><b>2.3实现各个分割区域的通信</b><br />■<b>有文档相连的视图之间的通信<br /></b>由AppWizard生成的CCuteFTPView是与文档相连的，同时我们也让CView2与文档相连，因此我们需要修改CCuteFTPApp的InitInstance()函数，我们将增加下面的部分。<br /><pre>AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, 
          
          RUNTIME_CLASS(CMainDoc), 
          RUNTIME_CLASS(CMDIChildWnd), 
          RUNTIME_CLASS(CView2))); </pre>我们现在来实现CCuteFTPView与CView2之间的通信。由于跟文档类相连的视图类 是不能安全的与除文档类之外的其余的视图类通信的。因此我们只能让他们都与文档 类通信。在文档中我们设置相应的指针以用来获的各个视图。我们重载 CCuteFTPView::OnOpenDocument()函数； <br /><pre>CCuteFTPView* pCuteFTPView;<br />CView2* pView2;
POSITION pos;
CView* pView;
while(pos!=NULL)
{
      pView=GetNextView(pos); 
      if(pView-&gt;IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) 
          pCuteFTPView=(CCuteFTPView*)pView; 
      else(pView-&gt;IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) 
          pView2=(CView2*)pView; 
} </pre>这样我们在文档类中就获的了跟它相连的所有的视图的指针。<br />如果需要在 CCuteFTPView中调用CView2中的一个方法DoIt()则代码如下： <br /><pre>CCuteFTPDoc* pDoc=GetDocument();<br />CView2* pView2=pDoc-&gt;pView3;<br />pView3.DoIt(); </pre><br />■<b>无文档视图与文档关联视图之间的通信<br /></b>CView3和CView4都是不与文档相关联的。我们现在实现CView3与CView2的通信.正如前面所说，CView2只能安全的与CCuteFTPDoc通信，因此，CView3如果需要跟CView2通信，也必须借助于文档类。因此程序的关键是如何在CView3中获得文档的指针。视图类中没有这样的类成员可以用来直接访问文档类。但是我们知道在主窗口类MainFrame中我们可以获得程序的任意窗口类的指针。因此我们只要获得程序主窗口了的指针，就可以解决问题了。代码实现在CView3中访问CView2中的DoIt()方法。<br /><br />CView3中的代码如下： <pre>CMainFrame* MainFrame=(CMainFrame*)this-&gt;GetParent()-&gt;GetParent(); 
          
          CCuteFTPDoc* Doc=(CCuteFTPDoc*)MainFrame-&gt;GetActiveDocument();
          if(Doc!=NULL) Doc-&gt;DoIt(); 
          
          CCuteFTPDoc中的相应的处理函数DoIt()代码如下： 
          
          CView2* pView2; 
          POSITION pos; 
          CView* pView; 
          while(pos!=NULL) 
          { 
                  pView=GetNextView(pos);
                  if(pView-&gt;IsKindOf(RUNTIME_CLASS(CView2))==NULL) 
                  pView2=(CView2*)pView; 
          } 
          pView2-&gt;DoIt(); </pre>■<b>无文档关联视图之间的通信<br /></b>CView3和CView4都是不跟文档相连的，如何实现他们之间的通信呢。 正如我们在上面所说的那样，由于在主框架中我们可以访问任意的视图，因此我们的主要任 务还是在程序中获得主框架的指针。在CView3中访问CView4中的方法DoIt()。 <br /><pre>CMainFrame* MainFrame=(CMainFrame*)this-&gt;GetParent()-&gt;GetParent(); 
          
          CView4* View4=(CView4*)MainFrame-&gt;m_wndSplitter1.GetPane(2,0); 
          View4-&gt;DoIt(); </pre><br />到现在我们已经实现了CuteFTP的主窗口的框架并且能够实现他们之间相互通信的框架。 同样的我们可以实现其他的一些流行界面例如NetAnts，Foxmail的分割。 <br /><br /><b>三、关于对话框的分割</b><br />到目前为止，只有基于文档/视图的程序才能使用CSplitterWnd，而基于对话框的应用程序却不支持CSplitterWnd,但是如果我们在继承类中重载一些虚拟方法，也能使CSplitterWnd 在对话框程序中使用。从MFC的源程序WinSplit.cpp中可以看出，为了获得父窗口的地方程序都调用了虚拟方法GetParentFrame(),因此如果在对话框中使用，我们必须将它改为GetParent();因此我们将CSplitterWnd的下面几个方法重载。<br /><pre>virtual void StartTracking(int ht); 
virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol  = NULL); 
virtual void SetActivePane( int row, int col, CWnd* pWnd  = NULL ); 
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); 
virtual BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult ); 
virtual BOOL OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult ); </pre>具体实现如下，实现中我将给出原有代码的主要部分以及修改后的代码以作对比。<br />在cpp文件中加入下面的枚举类型。 <br /><pre>enum HitTestValue 
{ 
                  noHit = 0,//表示没有选中任何对象
                  vSplitterBox = 1,
                  hSplitterBox = 2,
                  bothSplitterBox = 3,
                  vSplitterBar1 = 101,//代表各个方向的水平分割条
                  vSplitterBar15 = 115,
                  hSplitterBar1 = 201,//代表垂直方向的各个分割条
                  hSplitterBar15 = 215,
                  splitterIntersection1 = 301,//代表各个交叉点
                  splitterIntersection225 = 525
};
          <br />
CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol)
          {
                  ASSERT_VALID(this); 
                  //获得当前的获得焦点的窗口
                  //下面注释粗体的是原有的代码的主要部分。
                  // CWnd* pView = NULL;
                  //CFrameWnd* pFrameWnd = GetParentFrame();
                  //ASSERT_VALID(pFrameWnd);
                  //pView = pFrameWnd-&gt;GetActiveView();
                  //if (pView == NULL)
                  // pView = GetFocus();
                  CWnd* pView = GetFocus();
                  if (pView != NULL &amp;&amp; !IsChildPane(pView, pRow, pCol))
                          pView = NULL;
                  return pView; 
} 
          
void CxSplitterWnd::SetActivePane( int row, int col, CWnd* pWnd) 
{
                  CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd; 
                  //下面加注释粗体的是原有代码的主要部分。
                  //FrameWnd* pFrameWnd = GetParentFrame();
                  //ASSERT_VALID(pFrameWnd); 
                  //pFrameWnd-&gt;SetActiveView((CView*)pPane); 
                  pPane-&gt;SetFocus();//修改后的语句 
}
          
void CxSplitterWnd::StartTracking(int ht)
{
                  ASSERT_VALID(this); 
                  if (ht == noHit) 
                          return;
                  // GetHitRect will restrict ''''m_rectLimit'''' as appropriate 
          
                  GetInsideRect(m_rectLimit);
                  if (ht &gt;= splitterIntersection1 &amp;&amp; ht &lt;= splitterIntersection225) 
          
                  { 
                          // split two directions (two tracking rectangles) 
          
                          int row = (ht - splitterIntersection1) / 15; 
          
                          int col = (ht - splitterIntersection1) % 15; 
          
                          GetHitRect(row + vSplitterBar1, m_rectTracker); 
          
                          int yTrackOffset = m_ptTrackOffset.y; 
                          m_bTracking2 = TRUE; 
                          GetHitRect(col + hSplitterBar1, m_rectTracker2); 
          
                          m_ptTrackOffset.y = yTrackOffset; 
                  } 
                  else if (ht == bothSplitterBox) 
                  { 
                  // hit on splitter boxes (for keyboard) 
                  GetHitRect(vSplitterBox, m_rectTracker); 
                  int yTrackOffset = m_ptTrackOffset.y; 
                  m_bTracking2 = TRUE; 
                  GetHitRect(hSplitterBox, m_rectTracker2); 
                  m_ptTrackOffset.y = yTrackOffset; // center it 
                  m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2); m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 
          0); 
                  } 
                  else
                  { 
                  // only hit one bar 
                  GetHitRect(ht, m_rectTracker); 
                  } 
          
          //下面加注释的将从程序中删去。 
          //CView* pView = (CView*)GetActivePane(); 
          //if (pView != NULL &amp;&amp; pView-&gt;IsKindOf(RUNTIME_CLASS(CView))) 
          //{ 
          // ASSERT_VALID(pView); 
          // CFrameWnd* pFrameWnd = GetParentFrame(); 
          //ASSERT_VALID(pFrameWnd); 
          //pView-&gt;OnActivateFrame(WA_INACTIVE, pFrameWnd); 
          // } 
          // steal focus and capture
                  SetCapture();
                  SetFocus();
                  // make sure no updates are pending 
                  RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); 
          
                  // set tracking state and appropriate cursor
                  m_bTracking = TRUE;
                  OnInvertTracker(m_rectTracker); 
                  if (m_bTracking2) 
                          OnInvertTracker(m_rectTracker2); 
                  m_htTrack = ht; 
                  SetSplitCursor(ht); 
}
          
BOOL CxSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam) 
{ 
                  if (CWnd::OnCommand(wParam, lParam)) 
                          return TRUE; 
                  //下面粗体的是原程序的语句 
          //<b>return GetParentFrame()-&gt;SendMessage(WM_COMMAND, wParam, lParam); 
          </b>
                  return GetParent()-&gt;SendMessage(WM_COMMAND, wParam, lParam); 
          
}
BOOL CxSplitterWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
                  if (CWnd::OnNotify(wParam, lParam, pResult)) 
                          return TRUE; 
                  //下面粗体的是源程序的语句
                  //<b>*pResult = GetParentFrame()-&gt;SendMessage(WM_NOTIFY, 
          wParam, lParam);</b>
                  *pResult = GetParent()-&gt;SendMessage(WM_NOTIFY, wParam, lParam);
                  return TRUE;
} 
          
BOOL CxSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{ 
                  // The code line below is necessary if using CxSplitterWnd 
          in a regular dll 
                  // AFX_MANAGE_STATE(AfxGetStaticModuleState());
                  return CWnd::OnWndMsg(message, wParam, lParam, pResult); 
          
} </pre>这样我们就可以在对话框中使用CxSplitterWnd类了。 <br /><br /><b>四、CSplitterWnd的扩展</b><br />CSplitterWnd扩展话题是很多的，我们可以通过对原有方法的覆盖或者增加新的方法来扩展CSplitterWnd。我们在此仅举两个方面的例子。 <br /><b>4.1锁定切分条</b><br />当用户创建好分割窗口后，有时并不希望通过拖动切分条来调节窗口的大小。这时就必须锁定切分条。锁定切分条的最简单的方法莫过于不让CSplitterWnd来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息，而是将这些消息交给CWnd窗口进行处理，从而屏蔽掉这些消息。拿WM_LBUTTONDOWN处理过程来说。修改为如下： <br /><pre>void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) <br />{ 
        CWnd::OnLButtonDown(nFlags,point);
} </pre>其余的处理方法类似。 <br /><b>4.2切分条的定制</b><br />由Window自己生成的切分条总是固定的，没有任何的变化，我们在使用一些软件比如ACDSee的时候却能发现它们的切分条却是和自动生成的切分条不一样的。那么如何定制自己的切分条呢？通过重载CSplitterWnd的虚方法OnDrawSplitter和OnInvertTracker可以达到这样的目的。下面的代码生成的效果是分割窗口的边界颜色为红色，分割条的颜色为绿色.代码如下：<br /><pre>void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &amp;rectArg)
{
                  if(pDC==NULL) 
                  { 
                  RedrawWindow(rectArg,NULL,RDW_INVALIDATE|RDW_NOCHILDREN);
                  return;
                  } 
                  ASSERT_VALID(pDC);
                  CRect rc=rectArg;
                  switch(nType) 
                  { 
                  case splitBorder:
                  //重画分割窗口边界,使之为红色 
                          pDC-&gt;Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));
                          rc.InflateRect(-CX_BORDER,-CY_BORDER); 
                          pDC-&gt;Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); 
          
                          return; 
                  case splitBox:
                          pDC-&gt;Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                          rc.InflateRect(-CX_BORDER,-CY_BORDER); 
                          pDC-&gt;Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                          rc.InflateRect(-CX_BORDER,-CY_BORDER);
                          pDC-&gt;FillSolidRect(rc,RGB(0,0,0)); 
                          pDC-&gt;Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                          return; 
                  case splitBar: 
                  //重画分割条，使之为绿色 
                          pDC-&gt;FillSolidRect(rc,RGB(255,255,255));
                          rc.InflateRect(-5,-5); 
                          pDC-&gt;Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); 
          
                          return; 
                  default: 
                          ASSERT(FALSE); 
                  } 
                  pDC-&gt;FillSolidRect(rc,RGB(0,0,255));
} 
void CSplitterWndEx::OnInvertTracker(CRect &amp;rect) 
{ 
                  ASSERT_VALID(this);
                  ASSERT(!rect.IsRectEmpty()); 
                  ASSERT((GetStyle()&amp;WS_CLIPCHILDREN)==0);
                  CRect rc=rect; 
                  rc.InflateRect(2,2);
                  CDC* pDC=GetDC(); 
                  CBrush* pBrush=CDC::GetHalftoneBrush();
                  HBRUSH hOldBrush=NULL;
                  if(pBrush!=NULL) hOldBrush=(HBRUSH)SelectObject(pDC-&gt;m_hDC,pBrush-&gt;m_hObject);
                  pDC-&gt;PatBlt(rc.left,rc.top,rc.Width(),rc.Height(),BLACKNESS); 
          
                  if(hOldBrush!=NULL) 
                  SelectObject(pDC-&gt;m_hDC,hOldBrush);
                  ReleaseDC(pDC); 
} </pre><img src ="http://www.cppblog.com/yishanhante/aggbug/20772.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yishanhante/" target="_blank">jay</a> 2007-03-28 15:20 <a href="http://www.cppblog.com/yishanhante/articles/20772.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>visual C++ 6.0开发工具与调试</title><link>http://www.cppblog.com/yishanhante/articles/18923.html</link><dc:creator>jay</dc:creator><author>jay</author><pubDate>Fri, 23 Feb 2007 07:13:00 GMT</pubDate><guid>http://www.cppblog.com/yishanhante/articles/18923.html</guid><wfw:comment>http://www.cppblog.com/yishanhante/comments/18923.html</wfw:comment><comments>http://www.cppblog.com/yishanhante/articles/18923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yishanhante/comments/commentRss/18923.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yishanhante/services/trackbacks/18923.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、          								如何快速地				规				范代				码缩进				格式								选				中所需要				规				范的代				码				，按shift+F8														2、          								如何在Release				状态				下		...&nbsp;&nbsp;<a href='http://www.cppblog.com/yishanhante/articles/18923.html'>阅读全文</a><img src ="http://www.cppblog.com/yishanhante/aggbug/18923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yishanhante/" target="_blank">jay</a> 2007-02-23 15:13 <a href="http://www.cppblog.com/yishanhante/articles/18923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中用于调试程序的宏</title><link>http://www.cppblog.com/yishanhante/articles/18922.html</link><dc:creator>jay</dc:creator><author>jay</author><pubDate>Fri, 23 Feb 2007 06:57:00 GMT</pubDate><guid>http://www.cppblog.com/yishanhante/articles/18922.html</guid><wfw:comment>http://www.cppblog.com/yishanhante/comments/18922.html</wfw:comment><comments>http://www.cppblog.com/yishanhante/articles/18922.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yishanhante/comments/commentRss/18922.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yishanhante/services/trackbacks/18922.html</trackback:ping><description><![CDATA[
		<p style="LINE-HEIGHT: 12pt">
				<strong>
						<span style="COLOR: red">
								<font size="1">
										<font face="Georgia">ASSERT()</font>
								</font>
						</span>
				</strong>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<strong>
						<span style="COLOR: red">
						</span>
				</strong>
				<font size="1">
						<font face="Georgia">     ASSERT()被测试它的参数，若参数为<span>0，则中断执行并打印一段说明消息。在 Release 版本的程序中它不起任何作用。ASSERT()使用的时候必须保证参数表达式中不能有函数调用（译者注：ASSERT()宏在 Release 版本中不对表达式求值），因此对于任何有函数调用的参数表达式，应该使用宏 VERIFY()，以保证表达式中的函数调用在 Release 版本中会被正确求值。</span></font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">断言<span>(assertion)用带断言信息(程序, 模块, assertion行)的对话框执行. 对话框有3个按钮: "Break", "Repeat" ("Debug"), and "Continue" ("Ignore"). "Break" 结束程序, "Continue" 忽略断言, 最有用的是"Repeat"按钮. 按下它在断言的地方打开源代码编辑器. 在这里你可以测试所有的变量值并明白哪里出了问题。</span></font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<span style="FONT-SIZE: 9pt">
						<font size="1">
								<font face="Georgia">例如：ASSERT(pPointer);ASSERT(n&gt;0 &amp;&amp; n&lt;100);ASSERT(0);</font>
						</font>
				</span>
		</p>
		<p style="LINE-HEIGHT: 12pt" align="left">
				<font size="1">
						<font face="Georgia">ASSERT在执行简单验证时很有用，但对于<span>C++对象，特别是由CObject派生的对象，则有更好的方法ASSERT_VALID来实现类似操作。作为一般规则，我们应在开始使用每一个对象之前检查数据讹误,</span></font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt" align="left">
				<span>
						<font face="Georgia" size="1">
						</font>
				</span> </p>
		<p style="LINE-HEIGHT: 12pt" align="left">
				<span>
						<font size="1">
								<font face="Georgia">
										<strong>ASSERT_VALID</strong>宏使得对CObject的派生类实现该操作非常简单。</font>
						</font>
				</span>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<span style="FONT-SIZE: 9pt">
						<font size="1">
								<font face="Georgia">例如：ASSERT_VALID(this);ASSERT_VALID(pView);</font>
						</font>
				</span>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<span style="FONT-SIZE: 9pt">
						<font face="Georgia" size="1">
						</font>
				</span> </p>
		<p style="LINE-HEIGHT: 12pt" align="left">
				<span style="COLOR: red">
						<strong>
								<font size="1">
										<font face="Georgia">VERIFY()</font>
								</font>
						</strong>
				</span>
		</p>
		<p style="LINE-HEIGHT: 12pt" align="left">
				<span style="COLOR: red">
				</span>
				<font face="Georgia">
						<font size="1">    VERIFY()和<span> ASSERT()很相似，区别在于在 Release 版本中它仍然有效（译者注：原作者在这里没有讲清楚，VERIFY()不会打印说明，只是会对参数表达式求值）。 </span></font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt" align="left">
				<span>
						<font face="Georgia" size="1">
						</font>
				</span> </p>
		<p style="LINE-HEIGHT: 12pt">
				<span style="COLOR: red">
						<strong>
								<font size="1">
										<font face="Georgia">TRACE()</font>
								</font>
						</strong>
				</span>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<span style="COLOR: red">
				</span>
				<font size="1">
						<font face="Georgia">
								<font color="#ff0000">
										<strong> </strong>
								</font>    TRACE()基本上就是函数 <span>printf()</span>的一个复制品，唯一的区别是它把结果输出到调试窗口。在 Release 版本中，它也是无效的。一般是用TRACE0(),TRACE1(),TRACE2()…而不用TRACE()。</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia"> 这三个宏在<span> Release 版本中都不会产生任何实质性的影响，它们是否起作用取决于是否定义了预定义了宏 _DEBUG。这是对 Microsoft Visual C++ 而言，在其它的编译器中可能其它不同的宏。</span></font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<span>
						<font face="Georgia" size="1">
						</font>
				</span> </p>
		<p style="LINE-HEIGHT: 12pt">
				<strong>
						<font size="1">
								<font face="Georgia">常用用法：</font>
						</font>
				</strong>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<strong>
						<font face="Georgia" size="1">
						</font>
				</strong> </p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">为了控制传进的指针:</font>
				</font>
		</p>
		<p>
				<font size="1">
						<font face="Georgia">void SomeFun(SomeType* pPointer)</font>
				</font>
		</p>
		<p>
				<font size="1">
						<font face="Georgia">{</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<span style="FONT-SIZE: 9pt">
						<font size="1">
								<font face="Georgia"> <strong> ASSERT(pPointer);</strong></font>
						</font>
				</span>
		</p>
		<p>
				<font size="1">
						<font face="Georgia"> //some instructions.</font>
				</font>
		</p>
		<p>
				<font size="1">
						<font face="Georgia">}</font>
				</font>
		</p>
		<p>
				<font face="Georgia" size="1">
				</font> </p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">你可以在"switch" 和 "if"操作中捕获奇怪的值<br />例如:</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">switch(nRGBColors){<br />  case nRed:   {//some instructions.} break;<br />  case nGreen: {//some instructions.} break;<br />  case nBlue:  {//some instructions.} break;<br />  <strong>default: ASSERT(0);</strong>    // we should have never come here!<br />}</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">if(nWaterTemp &gt;=0 &amp;&amp; nWaterTemp &lt; 50){<br />  //some instructions.<br />}<br />else if(nWaterTemp &gt;= 50 &amp;&amp; nWaterTemp &lt;= 100){<br />  //some instructions.<br />}<br />else{<br />  <strong>ASSERT(0); </strong>   // we should have never come here!<br />}</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<font face="Georgia" size="1">
				</font> </p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">对值的断言: <br />ASSERT(nSomeValue &gt;= MinValue and nSomeValue &lt;= MaxValue);<br />ASSERT(nOtherValue != 0);</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<strong>
						<font face="Georgia" size="1">
						</font>
				</strong> </p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">
								<strong>可爱的 ASSERT 错误</strong>
								<br />ASSERT( m_MyWnd.Create() );</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<font size="1">
						<font face="Georgia">呕! 这是一个可怕的错误! 程序在调试版中正常工作, 在发行版中不工作. 记住: 这是一个在发行版中将被移除的宏. 以这种方法你的窗口将永远不会被创建. 如果你用 MFC, 这样做:</font>
				</font>
		</p>
		<p style="LINE-HEIGHT: 12pt">
				<strong>
						<font size="1">
								<font face="Georgia">VERIFY( m_MyWnd.Create() );</font>
						</font>
				</strong>
		</p>
		<p>
				<font face="Georgia">
						<font size="1">
								<span style="FONT-SIZE: 10.5pt">它在调试版中像</span>
								<span style="FONT-SIZE: 10.5pt">ASSERT</span>
								<span style="FONT-SIZE: 10.5pt">一样并且在发行版中执行</span>
								<span style="FONT-SIZE: 10.5pt">m_MyWnd.Create()</span>
								<span style="FONT-SIZE: 10.5pt">。</span>
						</font>
				</font>
		</p>
<img src ="http://www.cppblog.com/yishanhante/aggbug/18922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yishanhante/" target="_blank">jay</a> 2007-02-23 14:57 <a href="http://www.cppblog.com/yishanhante/articles/18922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>