|      
 
 //函數(shù)實現(xiàn)畫單根K線的功能,坐標(biāo)為普通坐標(biāo),而非對數(shù)坐標(biāo) 
void CStockGraph::DrawOneKLine(CDC * pDC, int nIndexPos, int nIndexKD, CKData * pKData, double dMin, double dMax, BOOL bGreyed ) {  DECLARE_COLOR_DEFINATION 
 // Check Valid 
 //判斷當(dāng)前位置的序列號是否有效,指的是顯示窗口,在當(dāng)前的m_nIndexStart 和 m_nIndexEnd之間  ASSERT( pDC && nIndexPos >= m_nIndexStart && nIndexPos <= m_nIndexEnd && nIndexPos >= 0 );  if( !(pDC && nIndexPos >= m_nIndexStart && nIndexPos <= m_nIndexEnd && nIndexPos >= 0) )   return; 
 //判斷當(dāng)前位置的序列號是否有效,序列號是否是小于零或大于當(dāng)前序列的長度  if( !pKData || nIndexKD < 0 || nIndexKD >= pKData->GetSize() )   return;  if( dMax-dMin < 1e-4 )   return; 
 // Get Region 
 //關(guān)于GetOneKLineRect請參看下面關(guān)于這個函數(shù)的分析 
 //這里需要注意的一個問題就是rectK, rcEntity,是有不同的含義的,rectK是指顯示的K線矩形區(qū)域,實際的畫K線的區(qū)域是rcEntity,指的是畫K線實體的區(qū)域  CRect rectK, rcEntity;  long xMedium = 0;  if( !GetOneKLineRect( nIndexPos, &rectK, &rcEntity.left, &rcEntity.right, &xMedium ) )//參數(shù)xMedium 為K線實體的中間位置,對應(yīng)畫K線的圖形   return; 
 int xStart = rectK.left;  int xEnd = rectK.right;  ASSERT( xEnd <= m_rectKLineCenter.right );  if( xEnd > m_rectKLineCenter.right )   return; 
 KDATA kd = pKData->ElementAt(nIndexKD); 
//根據(jù)當(dāng)前最低價格/最高價格/收盤價格/開盤價格的計算出K線實體在當(dāng)前顯示區(qū)域中坐標(biāo).(等比例的計算) 
 // Set rcEntity's top and bottom, set yLow, yHigh  int yLow = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fLow - dMin) / (dMax-dMin) );  int yHigh = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fHigh - dMin) / (dMax-dMin) );  int yOpen = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fOpen - dMin) / (dMax-dMin) );  int yClose = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fClose - dMin) / (dMax-dMin) ); 
 //計算出實體區(qū)域的上下坐標(biāo),左右坐標(biāo)已經(jīng)根據(jù)序列位置計算出來了,到這個地方,已經(jīng)計算出了要畫K線的試題區(qū)域的具體坐標(biāo)了. 
 rcEntity.top = min( yOpen, yClose );  rcEntity.bottom = max( yOpen, yClose ) + 1; 
  
 //上面已經(jīng)計算出了要畫的K線的坐標(biāo)了,下面就開始畫K線了 
 if( CStockGraph::klineCandle == m_nCurKLineMode )  {   // Draw Entity 
  //畫實體區(qū)域了   COLORREF clr = clrRise;   if( kd.m_fClose < kd.m_fOpen )    clr = clrFallEntity;   if( kd.m_date > m_dwLatestDate )    clr = clrNewKLine;   if( bGreyed )    clr = clrDJ;   pDC->SetBkColor( clrBK );   if( kd.m_fClose < kd.m_fOpen )    pDC->FillSolidRect( &rcEntity, clr );   else    pDC->Draw3dRect( &rcEntity, clr, clr );      // Draw Line 
  //畫K線上的最高和最低價格的線   CPen pen( PS_SOLID, 1, clr );   CPen *pOldPen = pDC->SelectObject( &pen );   pDC->MoveTo( xMedium, yHigh );   pDC->LineTo( xMedium, rcEntity.top );   pDC->MoveTo( xMedium, rcEntity.bottom );   pDC->LineTo( xMedium, yLow ); 
  pDC->SelectObject( pOldPen );  }  else if( CStockGraph::klineAmerica == m_nCurKLineMode )  {   // Draw Entity   COLORREF clr = clrRise;   if( kd.m_date > m_dwLatestDate )    clr = clrNewKLine;   if( bGreyed )    clr = clrDJ;   pDC->SetBkColor( clrBK );      // Draw Line   CPen pen( PS_SOLID, 1, clr );   CPen *pOldPen = pDC->SelectObject( &pen );   pDC->MoveTo( xStart, yHigh );   pDC->LineTo( xStart, yLow );   pDC->MoveTo( xStart, yClose );   pDC->LineTo( xEnd, yClose ); 
  pDC->SelectObject( pOldPen );  }  else if( CStockGraph::klineTower == m_nCurKLineMode )  {      // Draw Entity   COLORREF clr = clrRise;   if( kd.m_fClose < kd.m_fOpen )    clr = clrFallEntity;   if( kd.m_date > m_dwLatestDate )    clr = clrNewKLine;   if( bGreyed )    clr = clrDJ;   pDC->SetBkColor( clrBK );   if( kd.m_fClose < kd.m_fOpen )    pDC->FillSolidRect( &rcEntity, clr );   else    pDC->Draw3dRect( &rcEntity, clr, clr ); 
  if( nIndexKD > 0 )   {    KDATA kdLast = pKData->ElementAt(nIndexKD-1);    int yOpenLast = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kdLast.m_fOpen - dMin) / (dMax-dMin) );    int yCloseLast = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kdLast.m_fClose - dMin) / (dMax-dMin) );    if( kdLast.m_fClose > kdLast.m_fOpen && kd.m_fClose < kd.m_fOpen )    {     rcEntity.bottom = min(yOpenLast,rcEntity.bottom);     if( rcEntity.bottom > rcEntity.top )     {      pDC->FillSolidRect( &rcEntity, clrBK );      clr = clrRise;      if( kd.m_date > m_dwLatestDate )       clr = clrNewKLine;      if( bGreyed )       clr = clrDJ;      pDC->Draw3dRect( &rcEntity, clr, clr );     }    }    else if( kdLast.m_fClose < kdLast.m_fOpen && kd.m_fClose > kd.m_fOpen )    {     rcEntity.top = max(yOpenLast,rcEntity.top);     if( rcEntity.bottom > rcEntity.top )     {      clr = clrFallEntity;      if( kd.m_date > m_dwLatestDate )       clr = clrNewKLine;      if( bGreyed )       clr = clrDJ;      pDC->FillSolidRect( &rcEntity, clr );     }    }   }  } } 
  
//函數(shù)GetOneKLineRect的分析,得到當(dāng)前序列位置處要畫K線的區(qū)域 
BOOL CStockGraph::GetOneKLineRect( int nIndex, LPRECT lpRect, long *pxEntityLeft, long *pxEntityRight, long *pxMedium ) { 
 //判斷當(dāng)前的序列位置是在當(dāng)前顯示的窗口區(qū)域中  if( nIndex == -1 || nIndex < m_nIndexStart || nIndex > m_nIndexEnd )   return FALSE; 
 //初始化畫K線的位置的矩形區(qū)域 
 CRect rectK = m_rectCenter; 
 //計算出K線位置的左右寬度的坐標(biāo),上下的坐標(biāo)沒有給出,只是初始化為m_rectCenter中的參數(shù) 
 //左邊的起誓位置為,從K線顯示區(qū)域的左邊開始m_rectKLineCenter.left,加上已經(jīng)顯示了nIndex-m_nIndexStart點的距離就是當(dāng)前序列處的坐標(biāo)  rectK.left = m_rectKLineCenter.left + (nIndex-m_nIndexStart) * m_nThickness; 
//右邊的坐標(biāo)最簡單,就是左邊左邊加上寬度就可以了.  rectK.right = rectK.left + m_nThickness; 
 if( rectK.Width() <= 0 || rectK.Height() <= 0 )   return FALSE; 
//傳出參數(shù)lpRect   if( lpRect )   *lpRect = rectK; 
 int xStart = rectK.left; 
 CRect rcEntity; 
 //根據(jù)當(dāng)前的K線的寬度計算出序列的右邊的坐標(biāo)點,并傳出參數(shù)  switch( m_nThickness )  {  case 1:  case 2:   rcEntity.left = xStart;   rcEntity.right = xStart + 1;   break;  case 4:  case 5:   rcEntity.left = xStart;   rcEntity.right = xStart + 3;   break;  case 6:  case 7:   rcEntity.left = xStart;   rcEntity.right = xStart + 5;   break;  case 9:  case 10:   rcEntity.left = xStart;   rcEntity.right = xStart + 7;   break;  case 13:  case 15:   rcEntity.left = xStart;   rcEntity.right = xStart + 11;   break;  default:   ASSERT( FALSE );   rcEntity.left = xStart;   rcEntity.right = xStart + 3;   return FALSE;  }  if( pxEntityLeft )   *pxEntityLeft = rcEntity.left;  if( pxEntityRight )   *pxEntityRight = rcEntity.right;  if( pxMedium )   *pxMedium = rcEntity.left + rcEntity.Width() / 2; 
 return TRUE; }   |