//函數實(shí)現畫(huà)單根K線(xiàn)的功能,坐標為普通坐標,而非對數坐標
void CStockGraph::DrawOneKLine(CDC * pDC, int nIndexPos, int nIndexKD, CKData * pKData, double dMin, double dMax, BOOL bGreyed ) { DECLARE_COLOR_DEFINATION
// Check Valid
//判斷當前位置的序列號是否有效,指的是顯示窗口,在當前的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;
//判斷當前位置的序列號是否有效,序列號是否是小于零或大于當前序列的長(cháng)度 if( !pKData || nIndexKD < 0 || nIndexKD >= pKData->GetSize() ) return; if( dMax-dMin < 1e-4 ) return;
// Get Region
//關(guān)于GetOneKLineRect請參看下面關(guān)于這個(gè)函數的分析
//這里需要注意的一個(gè)問(wèn)題就是rectK, rcEntity,是有不同的含義的,rectK是指顯示的K線(xiàn)矩形區域,實(shí)際的畫(huà)K線(xiàn)的區域是rcEntity,指的是畫(huà)K線(xiàn)實(shí)體的區域 CRect rectK, rcEntity; long xMedium = 0; if( !GetOneKLineRect( nIndexPos, &rectK, &rcEntity.left, &rcEntity.right, &xMedium ) )//參數xMedium 為K線(xiàn)實(shí)體的中間位置,對應畫(huà)K線(xiàn)的圖形 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);
//根據當前最低價(jià)格/最高價(jià)格/收盤(pán)價(jià)格/開(kāi)盤(pán)價(jià)格的計算出K線(xiàn)實(shí)體在當前顯示區域中坐標.(等比例的計算)
// 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) );
//計算出實(shí)體區域的上下坐標,左右坐標已經(jīng)根據序列位置計算出來(lái)了,到這個(gè)地方,已經(jīng)計算出了要畫(huà)K線(xiàn)的試題區域的具體坐標了.
rcEntity.top = min( yOpen, yClose ); rcEntity.bottom = max( yOpen, yClose ) + 1;
//上面已經(jīng)計算出了要畫(huà)的K線(xiàn)的坐標了,下面就開(kāi)始畫(huà)K線(xiàn)了
if( CStockGraph::klineCandle == m_nCurKLineMode ) { // Draw Entity
//畫(huà)實(shí)體區域了 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
//畫(huà)K線(xiàn)上的最高和最低價(jià)格的線(xiàn) 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 ); } } } } }
//函數GetOneKLineRect的分析,得到當前序列位置處要畫(huà)K線(xiàn)的區域
BOOL CStockGraph::GetOneKLineRect( int nIndex, LPRECT lpRect, long *pxEntityLeft, long *pxEntityRight, long *pxMedium ) {
//判斷當前的序列位置是在當前顯示的窗口區域中 if( nIndex == -1 || nIndex < m_nIndexStart || nIndex > m_nIndexEnd ) return FALSE;
//初始化畫(huà)K線(xiàn)的位置的矩形區域
CRect rectK = m_rectCenter;
//計算出K線(xiàn)位置的左右寬度的坐標,上下的坐標沒(méi)有給出,只是初始化為m_rectCenter中的參數
//左邊的起誓位置為,從K線(xiàn)顯示區域的左邊開(kāi)始m_rectKLineCenter.left,加上已經(jīng)顯示了nIndex-m_nIndexStart點(diǎn)的距離就是當前序列處的坐標 rectK.left = m_rectKLineCenter.left + (nIndex-m_nIndexStart) * m_nThickness;
//右邊的坐標最簡(jiǎn)單,就是左邊左邊加上寬度就可以了. rectK.right = rectK.left + m_nThickness;
if( rectK.Width() <= 0 || rectK.Height() <= 0 ) return FALSE;
//傳出參數lpRect if( lpRect ) *lpRect = rectK;
int xStart = rectK.left;
CRect rcEntity;
//根據當前的K線(xiàn)的寬度計算出序列的右邊的坐標點(diǎn),并傳出參數 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; } |