1, 将CreditStatic.h CreditStatic.cpp文件添加到工程目录下,并加到程序中 2, 在相应的对话框中添加变量:CCreditStatic m_static; 3, 在相应的对话框中添加静态文本,并修改其ID为:IDC_DISPLAY_STATIC 4, 在相应的对话框的OnInitDialog函数中添加代码如下:
m_static.SubclassDlgItem(IDC_DISPLAY_STATIC,this); m_static.SetBkImage(IDB_BITMAP1); m_static.SetCredits(pArrCredit,'|'); m_static.SetSpeed(1); m_static.SetColor(BACKGROUND_COLOR, RGB(0,0,0)); m_static.SetTransparent(); m_static.StartScrolling();
其中::pArrCredit为char*类型,里边放要显示的字幕,在相应对话框的CDlg中声明并初始化,如:: char *pArrCredit = { "¸感谢你||购买本书||" "本书会让你受益匪浅||本书作者||" "BITMAP1^|||" }; 1.CreditStatic.cpp 的代码: // CreditStatic.cpp : implementation file // #include "stdafx.h" #include "CreditStatic.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define DISPLAY_TIMER_ID 150 // timer id ///////////////////////////////////////////////////////////////////////////// // CCreditStatic CCreditStatic::CCreditStatic() { m_Colors[0] = RGB(0,0,0); // Black m_Colors[1] = RGB(255,0,0); // Red m_Colors[2] = RGB(255,255,0); // Yellow m_Colors[3] = RGB(0,255,255); // Turquoise m_Colors[4] = RGB(255,255,255); // White m_TextHeights[0] = 21; m_TextHeights[1] = 19; m_TextHeights[2] = 17; m_TextHeights[3] = 15; m_nCurrentFontHeight = m_TextHeights[NORMAL_TEXT_HEIGHT]; m_Escapes[0] = '\t'; m_Escapes[1] = '\n'; m_Escapes[2] = '\r'; m_Escapes[3] = '^'; m_DisplaySpeed[0] = 70; m_DisplaySpeed[1] = 40; m_DisplaySpeed[2] = 10; m_CurrentSpeed = 1; m_ScrollAmount = -1; m_bProcessingBitmap = FALSE; m_ArrIndex = NULL; m_nCounter = 1; m_nClip = 0; m_bFirstTime = TRUE; m_bDrawText = FALSE; m_bFirstTurn = TRUE; m_Gradient = GRADIENT_NONE; m_bTransparent = FALSE; n_MaxWidth = 0; TimerOn = 0; } CCreditStatic::~CCreditStatic() { } BEGIN_MESSAGE_MAP(CCreditStatic, CStatic) //{{AFX_MSG_MAP(CCreditStatic) ON_WM_PAINT() ON_WM_ERASEBKGND() ON_WM_TIMER() ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CCreditStatic message handlers BOOL CCreditStatic::StartScrolling() { //滚动字符为空,返回 if(m_ArrCredit.IsEmpty()) return FALSE; if(m_BmpMain.m_hObject != NULL) { m_BmpMain.DeleteObject(); m_BmpMain.m_hObject = NULL; } //设置定时间隔 TimerOn = SetTimer(DISPLAY_TIMER_ID,m_DisplaySpeed[m_CurrentSpeed],NULL); ASSERT(TimerOn != 0); m_ArrIndex = m_ArrCredit.GetHeadPosition(); m_nCounter = 1; m_nClip = 0; m_bFirstTime = TRUE; m_bDrawText = FALSE; return TRUE; } //结束滚动 void CCreditStatic::EndScrolling() { //结束定时 KillTimer(DISPLAY_TIMER_ID); TimerOn = 0; if(m_BmpMain.m_hObject != NULL) { m_BmpMain.DeleteObject(); m_BmpMain.m_hObject = NULL; } } //得到分开的字符串,用来滚动显示 void CCreditStatic::SetCredits(LPCTSTR credits,char delimiter) { char *str,*ptr1,*ptr2; ASSERT(credits); if((str = strdup(credits)) == NULL) return; m_ArrCredit.RemoveAll(); ptr1 = str; //得到分开的字符串,其中'/'表示行与行之间的间隔 while((ptr2 = strchr(ptr1,delimiter)) != NULL) { *ptr2 = '\0'; m_ArrCredit.AddTail(ptr1); ptr1 = ptr2+1; } m_ArrCredit.AddTail(ptr1); free(str); m_ArrIndex = m_ArrCredit.GetHeadPosition(); m_nCounter = 1; m_nClip = 0; m_bFirstTime = TRUE; m_bDrawText = FALSE; } void CCreditStatic::SetCredits(UINT nID,char delimiter) { CString credits; if(!credits.LoadString(nID)) return; SetCredits((LPCTSTR)credits, delimiter); } //设置滚动速度 void CCreditStatic::SetSpeed(UINT index, int speed) { ASSERT(index <= DISPLAY_FAST); if(speed) m_DisplaySpeed[index] = speed; m_CurrentSpeed = index; } //设置颜色,包括前景和背景 void CCreditStatic::SetColor(UINT index, COLORREF col) { ASSERT(index <= NORMAL_TEXT_COLOR); m_Colors[index] = col; } //设置字符高度 void CCreditStatic::SetTextHeight(UINT index, int height) { ASSERT(index <= NORMAL_TEXT_HEIGHT); m_TextHeights[index] = height; } void CCreditStatic::SetEscape(UINT index, char escape) { ASSERT(index <= DISPLAY_BITMAP); m_Escapes[index] = escape; } void CCreditStatic::SetGradient(UINT value) { ASSERT(value <= GRADIENT_LEFT_LIGHT); m_Gradient = value; } //设置是否透明 void CCreditStatic::SetTransparent(BOOL bTransparent) { m_bTransparent = bTransparent; } void CCreditStatic::OnPaint() { CPaintDC dc(this); // device context for painting if(TimerOn) return; CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap *pOldMemDCBitmap = NULL; CRect m_ScrollRect; GetClientRect(&m_ScrollRect); if(m_BmpMain.m_hObject == NULL) { CDC memDC2; CBitmap bitmap; memDC2.CreateCompatibleDC(&dc); bitmap.CreateCompatibleBitmap( &dc, m_ScrollRect.Width(), m_ScrollRect.Height() ); CBitmap *pOldMemDC2Bitmap = (CBitmap*)memDC2.SelectObject(&bitmap); DrawCredit(&memDC2, m_ScrollRect); AddBackGround(&memDC2, m_ScrollRect, m_ScrollRect); pOldMemDCBitmap = (CBitmap*)memDC.SelectObject(&m_BmpMain); memDC.BitBlt( 0, 0, m_ScrollRect.Width(), m_ScrollRect.Height(), &memDC2, 0, 0, SRCCOPY ); memDC2.SelectObject(pOldMemDC2Bitmap); } else pOldMemDCBitmap = (CBitmap*)memDC.SelectObject(&m_BmpMain); dc.BitBlt( 0, 0, m_ScrollRect.Width(), m_ScrollRect.Height(), &memDC, 0, 0, SRCCOPY ); } BOOL CCreditStatic::OnEraseBkgnd(CDC* pDC) { return TRUE; // return CStatic::OnEraseBkgnd(pDC); } //************************************************************************ // OnTimer // // On each of the display timers, scroll the window 1 unit. Each 20 // units, fetch the next array element and load into work string. Call // Invalidate and UpdateWindow to invoke the OnPaint which will paint // the contents of the newly updated work string. //************************************************************************ void CCreditStatic::OnTimer(UINT nIDEvent) { //非设置的定时器ID,返回 if (nIDEvent != DISPLAY_TIMER_ID) { CStatic::OnTimer(nIDEvent); return; } BOOL bCheck = FALSE; //如果上次读入的字符串表示的不是位图名字 if (!m_bProcessingBitmap) { //根据m_nCurrentFontHeight高度决定需要多少次time响应才换一行字符显示 if (m_nCounter++ % m_nCurrentFontHeight == 0) { m_nCounter=1; //读出字符串队列中下一行要显示的字符串 m_szWork = m_ArrCredit.GetNext(m_ArrIndex); if(m_bFirstTurn) bCheck = TRUE; if(m_ArrIndex == NULL) { m_bFirstTurn = FALSE; m_ArrIndex = m_ArrCredit.GetHeadPosition(); } m_nClip = 0; m_bDrawText=TRUE; } } CClientDC dc(this); CRect m_ScrollRect; GetClientRect(&m_ScrollRect);//得到整个CStatic的客户区坐标 CRect m_ClientRect(m_ScrollRect); //用来表示滚动字符的范围 m_ClientRect.left = (m_ClientRect.Width()-n_MaxWidth)/2; m_ClientRect.right = m_ClientRect.left + n_MaxWidth; MoveCredit(&dc, m_ScrollRect, m_ClientRect, bCheck);//实现字幕滚动1单元 AddBackGround(&dc, m_ScrollRect, m_ClientRect);//添加背景 CStatic::OnTimer(nIDEvent); } //设置背景 void CCreditStatic::AddBackGround(CDC* pDC, CRect& m_ScrollRect, CRect& m_ClientRect) { CDC memDC; memDC.CreateCompatibleDC( pDC ); if( m_bitmap.m_hObject == NULL ) { CBitmap* pOldBitmap = memDC.SelectObject( &m_BmpMain ); pDC->BitBlt( 0, 0, m_ScrollRect.Width(), m_ScrollRect.Height(), &memDC, 0, 0, SRCCOPY ); memDC.SelectObject(pOldBitmap); return; } // Draw bitmap in the background if one has been set // Now create a mask CBitmap bitmap; bitmap.CreateCompatibleBitmap( pDC, m_ClientRect.Width(), m_ClientRect.Height() ); CBitmap* pOldMemDCBitmap = memDC.SelectObject( &bitmap ); CDC tempDC; tempDC.CreateCompatibleDC(pDC); CBitmap* pOldTempDCBitmap = tempDC.SelectObject( &m_BmpMain ); memDC.BitBlt( 0, 0, m_ClientRect.Width(), m_ClientRect.Height(), &tempDC, m_ClientRect.left, m_ClientRect.top, SRCCOPY ); CDC maskDC; maskDC.CreateCompatibleDC(pDC); CBitmap maskBitmap; // Create monochrome bitmap for the mask maskBitmap.CreateBitmap( m_ClientRect.Width(), m_ClientRect.Height(), 1, 1, NULL ); CBitmap* pOldMaskDCBitmap = maskDC.SelectObject( &maskBitmap ); memDC.SetBkColor(m_bTransparent? RGB(192,192,192): m_Colors[BACKGROUND_COLOR]); // Create the mask from the memory DC maskDC.BitBlt( 0, 0, m_ClientRect.Width(), m_ClientRect.Height(), &memDC, 0, 0, SRCCOPY ); tempDC.SelectObject(pOldTempDCBitmap); pOldTempDCBitmap = tempDC.SelectObject( &m_bitmap ); CDC imageDC; CBitmap bmpImage; imageDC.CreateCompatibleDC( pDC ); bmpImage.CreateCompatibleBitmap( pDC, m_ScrollRect.Width(), m_ScrollRect.Height() ); CBitmap* pOldImageDCBitmap = imageDC.SelectObject( &bmpImage ); if( pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL ) { pDC->SelectPalette( &m_pal, FALSE ); pDC->RealizePalette(); imageDC.SelectPalette( &m_pal, FALSE ); } // Get x and y offset // Draw bitmap in tiled manner to imageDC for( int i = 0; i < m_ScrollRect.right; i += m_cxBitmap ) for( int j = 0; j < m_ScrollRect.bottom; j += m_cyBitmap ) imageDC.BitBlt( i, j, m_cxBitmap, m_cyBitmap, &tempDC, 0, 0, SRCCOPY ); // Set the background in memDC to black. Using SRCPAINT with black and any other // color results in the other color, thus making black the transparent color memDC.SetBkColor(RGB(0,0,0)); memDC.SetTextColor(RGB(255,255,255)); memDC.BitBlt(0, 0, m_ClientRect.Width(), m_ClientRect.Height(), &maskDC, 0, 0, SRCAND); // Set the foreground to black. See comment above. imageDC.SetBkColor(RGB(255,255,255)); imageDC.SetTextColor(RGB(0,0,0)); imageDC.BitBlt(m_ClientRect.left, m_ClientRect.top, m_ClientRect.Width(), m_ClientRect.Height(), &maskDC, 0, 0, SRCAND); // Combine the foreground with the background imageDC.BitBlt(m_ClientRect.left, m_ClientRect.top, m_ClientRect.Width(), m_ClientRect.Height(), &memDC, 0, 0,SRCPAINT); // Draw the final image to the screen pDC->BitBlt( 0, 0, m_ScrollRect.Width(), m_ScrollRect.Height(), &imageDC, 0, 0, SRCCOPY ); imageDC.SelectObject(pOldImageDCBitmap); maskDC.SelectObject(pOldMaskDCBitmap); tempDC.SelectObject(pOldTempDCBitmap); memDC.SelectObject(pOldMemDCBitmap); } void CCreditStatic::DrawBitmap(CDC* pDC, CDC* pDC2, CRect *rBitmap) { if(!m_bTransparent || m_bitmap.m_hObject != NULL) { pDC->BitBlt( rBitmap->left, rBitmap->top, rBitmap->Width(), rBitmap->Height(), pDC2, 0, 0, SRCCOPY ); return; } //创建与pDC兼容的设备 CDC memDC; memDC.CreateCompatibleDC( pDC ); // 创建兼容位图并且选进设备 CBitmap bitmap; bitmap.CreateCompatibleBitmap( pDC, rBitmap->Width(), rBitmap->Height() ); CBitmap* pOldMemDCBitmap = memDC.SelectObject( &bitmap ); //将pDC2中的位图拷贝到memDC memDC.BitBlt( 0, 0, rBitmap->Width(), rBitmap->Height(), pDC2, 0, 0, SRCCOPY ); CDC maskDC; maskDC.CreateCompatibleDC(pDC); // 创建单色位图并且选入设备 CBitmap maskBitmap; maskBitmap.CreateBitmap( rBitmap->Width(), rBitmap->Height(), 1, 1, NULL ); CBitmap* pOldMaskDCBitmap = maskDC.SelectObject( &maskBitmap ); memDC.SetBkColor(RGB(192,192,192));//背景为系统色 // 将memDC中的位图拷贝到maskDC,maskDC中的的1表示位图背景色,0表示前景,即位图 maskDC.BitBlt( 0, 0, rBitmap->Width(), rBitmap->Height(), &memDC, 0, 0, SRCCOPY ); CDC imageDC; CBitmap bmpImage; imageDC.CreateCompatibleDC( pDC ); bmpImage.CreateCompatibleBitmap( pDC, rBitmap->Width(), rBitmap->Height() ); CBitmap* pOldImageDCBitmap = imageDC.SelectObject( &bmpImage ); //将pDC中对应位图背景区域拷贝到imageDC imageDC.BitBlt(0, 0, rBitmap->Width(), rBitmap->Height(), pDC, rBitmap->left, rBitmap->top, SRCCOPY); //下面的代码实现透明位图,见msdn的"Drawing Transparent Bitmaps" // Set the background in memDC to black. Using SRCPAINT with black and any other // color results in the other color, thus making black the transparent color //设置背景为黑色 memDC.SetBkColor(RGB(0,0,0)); memDC.SetTextColor(RGB(255,255,255)); memDC.BitBlt(0, 0, rBitmap->Width(), rBitmap->Height(), &maskDC, 0, 0, SRCAND); // 设置前景为黑色 imageDC.SetBkColor(RGB(255,255,255)); imageDC.SetTextColor(RGB(0,0,0)); imageDC.BitBlt(0, 0, rBitmap->Width(), rBitmap->Height(), &maskDC, 0, 0, SRCAND); //得到透明的位图 imageDC.BitBlt(0, 0, rBitmap->Width(), rBitmap->Height(), &memDC, 0, 0,SRCPAINT); // 将位图移动到合适位置 pDC->BitBlt( rBitmap->left, rBitmap->top, rBitmap->Width(), rBitmap->Height(), &imageDC, 0, 0, SRCCOPY ); imageDC.SelectObject(pOldImageDCBitmap); maskDC.SelectObject(pOldMaskDCBitmap); memDC.SelectObject(pOldMemDCBitmap); } void CCreditStatic::FillGradient(CDC *pDC, CRect *m_ScrollRect, CRect *m_FillRect, COLORREF color) { float fStep,fRStep,fGStep,fBStep; // How large is each band? int iOnBand; // Loop index WORD R = GetRValue(color); WORD G = GetGValue(color); WORD B = GetBValue(color); // Determine how large each band should be in order to cover the // client with 256 bands (one for every color intensity level) if(m_Gradient % 2) { fRStep = (float)R / 255.0f; fGStep = (float)G / 255.0f; fBStep = (float)B / 255.0f; } else { fRStep = (float)(255-R) / 255.0f; fGStep = (float)(255-G) / 255.0f; fBStep = (float)(255-B) / 255.0f; } COLORREF OldCol = pDC->GetBkColor(); // Start filling bands fStep = (float)m_ScrollRect->Width() / 256.0f; for(iOnBand = (256*m_FillRect->left)/m_ScrollRect->Width(); (int)(iOnBand*fStep) < m_FillRect->right && iOnBand < 256; iOnBand++) { CRect r((int)(iOnBand * fStep), m_FillRect->top, (int)((iOnBand+1) * fStep), m_FillRect->bottom+1); COLORREF col; switch(m_Gradient) { case GRADIENT_RIGHT_DARK: col = RGB((int)(R-iOnBand*fRStep),(int)(G-iOnBand*fGStep),(int)(B-iOnBand*fBStep)); break; case GRADIENT_RIGHT_LIGHT: col = RGB((int)(R+iOnBand*fRStep),(int)(G+iOnBand*fGStep),(int)(B+iOnBand*fBStep)); break; case GRADIENT_LEFT_DARK: col = RGB((int)(iOnBand*fRStep),(int)(iOnBand*fGStep),(int)(iOnBand*fBStep)); break; case GRADIENT_LEFT_LIGHT: col = RGB(255-(int)(iOnBand*fRStep),255-(int)(iOnBand*fGStep),255-(int)(iOnBand*fBStep)); break; default: return; } pDC->FillSolidRect(&r, col); } pDC->SetBkColor(OldCol); } #define SCROLLDC void CCreditStatic::MoveCredit(CDC* pDC, CRect& m_ScrollRect, CRect& m_ClientRect, BOOL bCheck) { CDC memDC,memDC2; //创建兼容的设备 memDC.CreateCompatibleDC(pDC); memDC2.CreateCompatibleDC(pDC); //决定背景颜色,如果初始设置为透明并且有背景位图,就选择系统色,否则选择设置的背景色 COLORREF BackColor = (m_bTransparent && m_bitmap.m_hObject != NULL)? RGB(192,192,192) : m_Colors[BACKGROUND_COLOR]; CBitmap *pOldMemDCBitmap = NULL; CBitmap *pOldMemDC2Bitmap = NULL; #ifdef SCROLLDC CRect r1; #endif //初始句柄为空 if(m_BmpMain.m_hObject == NULL) { //创建与设备兼容的位图 m_BmpMain.CreateCompatibleBitmap( pDC, m_ScrollRect.Width(), m_ScrollRect.Height() ); //将位图选入设备 pOldMemDCBitmap = (CBitmap*)memDC.SelectObject(&m_BmpMain); //选择是用梯度还是背景色填充设备memDC的背景 if(m_Gradient && m_bitmap.m_hObject == NULL) FillGradient(&memDC, &m_ScrollRect, &m_ScrollRect,m_Colors[BACKGROUND_COLOR]); else memDC.FillSolidRect(&m_ScrollRect,BackColor); } else pOldMemDCBitmap = (CBitmap*)memDC.SelectObject(&m_BmpMain); if(m_ClientRect.Width() > 0) { #ifndef SCROLLDC //如果不支持设备滚动 CBitmap bitmap; bitmap.CreateCompatibleBitmap( pDC, m_ClientRect.Width(), m_ClientRect.Height() ); pOldMemDC2Bitmap = memDC2.SelectObject(&bitmap); //memDC向上滚动一行,利用设备拷贝 memDC2.BitBlt( 0, 0, m_ClientRect.Width(), m_ClientRect.Height()-abs(m_ScrollAmount), &memDC, m_ClientRect.left, abs(m_ScrollAmount), SRCCOPY ); memDC.BitBlt( m_ClientRect.left, 0, m_ClientRect.Width(), m_ClientRect.Height(), &memDC2, 0, 0, SRCCOPY ); memDC2.SelectObject(pOldMemDC2Bitmap); pOldMemDC2Bitmap = NULL; #else//如果支持设备滚动 CRgn RgnUpdate; //memDC向上滚动一行,利用设备拷贝 memDC.ScrollDC(0,m_ScrollAmount,(LPCRECT)m_ScrollRect,(LPCRECT)m_ClientRect,&RgnUpdate, (LPRECT)r1); } else { //r1存储着要更新的区域位置 r1 = m_ScrollRect; r1.top = r1.bottom-abs(m_ScrollAmount); #endif } m_nClip = m_nClip + abs(m_ScrollAmount); //********************************************************************* // FONT SELECTION CFont m_fntArial; CFont* pOldFont = NULL; BOOL bSuccess = FALSE; BOOL bUnderline; BOOL bItalic; int rmcode = 0; //根据字符串性质决定操作 //更新的显示字符串不为空 if (!m_szWork.IsEmpty()) { //根据字符串最后一位决定类型 char c = m_szWork[m_szWork.GetLength()-1]; if(c == m_Escapes[TOP_LEVEL_GROUP]) //类型为最大群组标题 { rmcode = 1; bItalic = FALSE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[TOP_LEVEL_GROUP_HEIGHT]; //创建字体 bSuccess = m_fntArial.CreateFont(m_TextHeights[TOP_LEVEL_GROUP_HEIGHT], 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); //设置字体颜色 memDC.SetTextColor(m_Colors[TOP_LEVEL_GROUP_COLOR]); //选入设备 if (pOldFont != NULL) memDC.SelectObject(pOldFont); pOldFont = memDC.SelectObject(&m_fntArial); } else if(c == m_Escapes[GROUP_TITLE]) { //类型为组标题 rmcode = 1; bItalic = FALSE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[GROUP_TITLE_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[GROUP_TITLE_HEIGHT], 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[GROUP_TITLE_COLOR]); if (pOldFont != NULL) memDC.SelectObject(pOldFont); pOldFont = memDC.SelectObject(&m_fntArial); } else if(c == m_Escapes[TOP_LEVEL_TITLE]) { //类型为最大标题 rmcode = 1; bItalic = FALSE; // bUnderline = TRUE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[TOP_LEVEL_TITLE_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[TOP_LEVEL_TITLE_HEIGHT], 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[TOP_LEVEL_TITLE_COLOR]); if (pOldFont != NULL) memDC.SelectObject(pOldFont); pOldFont = memDC.SelectObject(&m_fntArial); } else if(c == m_Escapes[DISPLAY_BITMAP]) { //类型为位图 if (!m_bProcessingBitmap) { CString szBitmap = m_szWork.Left(m_szWork.GetLength()-1);//得到位图名字 if(m_bmpWork.LoadBitmap((const char *)szBitmap)) { //载入位图 BITMAP m_bmpInfo; m_bmpWork.GetObject(sizeof(BITMAP), &m_bmpInfo); m_size.cx = m_bmpInfo.bmWidth; // width of dest rect m_size.cy = m_bmpInfo.bmHeight; //得到要显示位图的左上角坐标 m_pt.x = (m_ClientRect.right - ((m_ClientRect.Width())/2) - (m_size.cx/2)); m_pt.y = m_ClientRect.bottom; m_bProcessingBitmap = TRUE; if (pOldMemDC2Bitmap != NULL) memDC2.SelectObject(pOldMemDC2Bitmap); pOldMemDC2Bitmap = memDC2.SelectObject(&m_bmpWork);//位图选入设备memDC2 } else c = ' '; } else { if (pOldMemDC2Bitmap != NULL) memDC2.SelectObject(pOldMemDC2Bitmap); pOldMemDC2Bitmap = memDC2.SelectObject(&m_bmpWork); } } else { bItalic = FALSE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[NORMAL_TEXT_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[NORMAL_TEXT_HEIGHT], 0, 0, 0, FW_THIN, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[NORMAL_TEXT_COLOR]); if (pOldFont != NULL) memDC.SelectObject(pOldFont); pOldFont = memDC.SelectObject(&m_fntArial); } } #ifndef SCROLLDC CRect r1(m_ScrollRect); r1.top = r1.bottom-abs(m_ScrollAmount); #endif //填充背景 if(m_Gradient && m_bitmap.m_hObject == NULL) FillGradient(&memDC, &m_ScrollRect, &r1, m_Colors[BACKGROUND_COLOR]); else memDC.FillSolidRect(&r1,BackColor); memDC.SetBkMode(TRANSPARENT); if (!m_bProcessingBitmap) //如果不是位图 { if(bCheck) { //对于单独一行字符的第一次滚动,需要先确定滚动区域范围 CSize size = memDC.GetTextExtent((LPCTSTR)m_szWork,m_szWork.GetLength()-rmcode); if(size.cx > n_MaxWidth) { n_MaxWidth = (size.cx > m_ScrollRect.Width())? m_ScrollRect.Width():size.cx; m_ClientRect.left = (m_ScrollRect.Width()-n_MaxWidth)/2; m_ClientRect.right = m_ClientRect.left + n_MaxWidth; } } CRect r(m_ClientRect); r.top = r.bottom-m_nClip; //在要更新的区域显示字符 int x = memDC.DrawText((const char *)m_szWork,m_szWork.GetLength()-rmcode,&r,DT_TOP|DT_CENTER| DT_NOPREFIX | DT_SINGLELINE); m_bDrawText=FALSE; } else { if(bCheck) { CSize size = memDC.GetTextExtent((LPCTSTR)m_szWork,m_szWork.GetLength()-rmcode); if(m_size.cx > n_MaxWidth) { n_MaxWidth = (m_size.cx > m_ScrollRect.Width())? m_ScrollRect.Width():m_size.cx; m_ClientRect.left = (m_ScrollRect.Width()-n_MaxWidth)/2; m_ClientRect.right = m_ClientRect.left + n_MaxWidth; } } CRect r( m_pt.x, m_pt.y-m_nClip, m_pt.x+ m_size.cx, m_pt.y); //如果是位图,根据背景memDC和位图设备memDC2,在更新区域显示部分位图 DrawBitmap(&memDC, &memDC2, &r); // memDC.BitBlt( m_pt.x, m_pt.y-m_nClip, m_size.cx, m_nClip, // &memDC2, 0, 0, SRCCOPY ); if (m_nClip >= m_size.cy) { m_bmpWork.DeleteObject(); m_bProcessingBitmap = FALSE; m_nClip=0; m_szWork.Empty(); m_nCounter=1; } } //恢复设备 if (pOldMemDC2Bitmap != NULL) memDC2.SelectObject(pOldMemDC2Bitmap); if (pOldFont != NULL) memDC.SelectObject(pOldFont); memDC.SelectObject(pOldMemDCBitmap); } void CCreditStatic::DrawCredit(CDC* pDC, CRect& m_ScrollRect) { if(m_BmpMain.m_hObject != NULL) return; CDC memDC,memDC2; memDC.CreateCompatibleDC(pDC); memDC2.CreateCompatibleDC(pDC); COLORREF BackColor = (m_bTransparent && m_bitmap.m_hObject != NULL)? RGB(192,192,192) : m_Colors[BACKGROUND_COLOR]; CBitmap *pOldMemDCBitmap = NULL; m_BmpMain.CreateCompatibleBitmap( pDC, m_ScrollRect.Width(), m_ScrollRect.Height() ); pOldMemDCBitmap = (CBitmap*)memDC.SelectObject(&m_BmpMain); if(m_Gradient && m_bitmap.m_hObject == NULL) FillGradient(&memDC, &m_ScrollRect, &m_ScrollRect, m_Colors[BACKGROUND_COLOR]); else memDC.FillSolidRect(&m_ScrollRect, BackColor); POSITION pos = m_ArrCredit.GetHeadPosition(); int height = 0; while(pos != NULL && height <= m_ScrollRect.Height()) { CString m_szWork = m_ArrCredit.GetNext(pos); CFont m_fntArial; CFont *pOldFont = NULL; CBitmap *pOldMemDC2Bitmap = NULL; CDC memDC2; memDC2.CreateCompatibleDC(pDC); //********************************************************************* // FONT SELECTION BOOL bSuccess = FALSE; BOOL bIsBitmap = FALSE; BOOL bUnderline; BOOL bItalic; int rmcode = 0; CBitmap bitmap; if (!m_szWork.IsEmpty()) { char c = m_szWork[m_szWork.GetLength()-1]; if(c == m_Escapes[TOP_LEVEL_GROUP]) { rmcode = 1; bItalic = FALSE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[TOP_LEVEL_GROUP_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[TOP_LEVEL_GROUP_HEIGHT], 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[TOP_LEVEL_GROUP_COLOR]); pOldFont = memDC.SelectObject(&m_fntArial); } else if(c == m_Escapes[GROUP_TITLE]) { rmcode = 1; bItalic = FALSE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[GROUP_TITLE_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[GROUP_TITLE_HEIGHT], 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[GROUP_TITLE_COLOR]); pOldFont = memDC.SelectObject(&m_fntArial); } else if(c == m_Escapes[TOP_LEVEL_TITLE]) { rmcode = 1; bItalic = FALSE; // bUnderline = TRUE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[TOP_LEVEL_TITLE_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[TOP_LEVEL_TITLE_HEIGHT], 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[TOP_LEVEL_TITLE_COLOR]); pOldFont = memDC.SelectObject(&m_fntArial); } else if(c == m_Escapes[DISPLAY_BITMAP]) { CString szBitmap = m_szWork.Left(m_szWork.GetLength()-1); if(bitmap.LoadBitmap((const char *)szBitmap)) { BITMAP m_bmpInfo; bitmap.GetObject(sizeof(BITMAP), &m_bmpInfo); m_size.cx = m_bmpInfo.bmWidth; // width of dest rect m_size.cy = m_bmpInfo.bmHeight; // upper left point of dest m_pt.x = (m_ScrollRect.right - ((m_ScrollRect.Width())/2) - (m_size.cx/2)); m_pt.y = height; pOldMemDC2Bitmap = memDC2.SelectObject(&bitmap); bIsBitmap = TRUE; } else c = ' '; } else { bItalic = FALSE; bUnderline = FALSE; m_nCurrentFontHeight = m_TextHeights[NORMAL_TEXT_HEIGHT]; bSuccess = m_fntArial.CreateFont(m_TextHeights[NORMAL_TEXT_HEIGHT], 0, 0, 0, FW_THIN, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPSTR)"Arial"); memDC.SetTextColor(m_Colors[NORMAL_TEXT_COLOR]); pOldFont = memDC.SelectObject(&m_fntArial); } } memDC.SetBkMode(TRANSPARENT); if (!bIsBitmap) { CRect r(m_ScrollRect); r.top = height; CSize size; if(m_szWork.GetLength()-rmcode != 0) { int x = memDC.DrawText((const char *)m_szWork,m_szWork.GetLength()-rmcode,&r,DT_TOP|DT_CENTER| DT_NOPREFIX | DT_SINGLELINE); size = memDC.GetTextExtent((LPCTSTR)m_szWork,m_szWork.GetLength()-rmcode); } else size = memDC.GetTextExtent((LPCTSTR)"W",1); height += size.cy; } else { CRect r( m_pt.x, m_pt.y, m_pt.x + m_size.cx, m_pt.y + m_size.cy); DrawBitmap(&memDC, &memDC2, &r); // memDC.BitBlt( m_pt.x, m_pt.y, m_size.cx, m_size.cy, &memDC2, 0, 0, SRCCOPY ); height += m_size.cy; } if (pOldMemDC2Bitmap != NULL) memDC2.SelectObject(pOldMemDC2Bitmap); if (pOldFont != NULL) memDC.SelectObject(pOldFont); } memDC.SelectObject(pOldMemDCBitmap); } void CCreditStatic::OnDestroy() { CStatic::OnDestroy(); m_ArrCredit.RemoveAll(); if(TimerOn) ASSERT(KillTimer(DISPLAY_TIMER_ID)); } BOOL CCreditStatic::SetBkImage(UINT nIDResource) { return SetBkImage( (LPCTSTR)nIDResource ); } //设置背景图片 BOOL CCreditStatic::SetBkImage(LPCTSTR lpszResourceName) { //删除以前的GDI对象 if( m_bitmap.m_hObject != NULL ) m_bitmap.DeleteObject(); if( m_pal.m_hObject != NULL ) m_pal.DeleteObject(); //载入位图 HBITMAP hBmp = (HBITMAP)::LoadImage( AfxGetInstanceHandle(), lpszResourceName, IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION ); if( hBmp == NULL ) return FALSE; m_bitmap.Attach( hBmp ); BITMAP bm; m_bitmap.GetBitmap( &bm ); m_cxBitmap = bm.bmWidth; m_cyBitmap = bm.bmHeight; // 为位图创建逻辑调色板 DIBSECTION ds; BITMAPINFOHEADER &bmInfo = ds.dsBmih; m_bitmap.GetObject( sizeof(ds), &ds ); int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << bmInfo.biBitCount; // 如果颜色大于> 256色,创建Halftone调色板 CClientDC dc(NULL); // Desktop DC if( nColors > 256 ) m_pal.CreateHalftonePalette( &dc ); else { //否则,创建调色板 RGBQUAD *pRGB = new RGBQUAD[nColors]; CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldMemDCBitmap = memDC.SelectObject( &m_bitmap ); ::GetDIBColorTable( memDC, 0, nColors, pRGB ); UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors); LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; pLP->palVersion = 0x300; pLP->palNumEntries = nColors; for( int i=0; i < nColors; i++) { pLP->palPalEntry[i].peRed = pRGB[i].rgbRed; pLP->palPalEntry[i].peGreen = pRGB[i].rgbGreen; pLP->palPalEntry[i].peBlue = pRGB[i].rgbBlue; pLP->palPalEntry[i].peFlags = 0; } m_pal.CreatePalette( pLP ); memDC.SelectObject(pOldMemDCBitmap); delete[] pLP; delete[] pRGB; } return TRUE; } 2.CreditStatic.h 的头文件代码 #if !defined(AFX_CREDITSTATIC_H__4ABD7701_49F5_11D1_9E3C_00A0245800CF__INCLUDED_) #define AFX_CREDITSTATIC_H__4ABD7701_49F5_11D1_9E3C_00A0245800CF__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // CreditStatic.h : header file // #define DISPLAY_SLOW 0 #define DISPLAY_MEDIUM 1 #define DISPLAY_FAST 2 #define BACKGROUND_COLOR 0 #define TOP_LEVEL_TITLE_COLOR 1 #define TOP_LEVEL_GROUP_COLOR 2 #define GROUP_TITLE_COLOR 3 #define NORMAL_TEXT_COLOR 4 #define TOP_LEVEL_TITLE_HEIGHT 0 #define TOP_LEVEL_GROUP_HEIGHT 1 #define GROUP_TITLE_HEIGHT 2 #define NORMAL_TEXT_HEIGHT 3 #define TOP_LEVEL_TITLE 0 // '\t' #define TOP_LEVEL_GROUP 1 // '\n' #define GROUP_TITLE 2 // '\r' #define DISPLAY_BITMAP 3 // '^' #define GRADIENT_NONE 0 #define GRADIENT_RIGHT_DARK 1 #define GRADIENT_RIGHT_LIGHT 2 #define GRADIENT_LEFT_DARK 3 #define GRADIENT_LEFT_LIGHT 4 class CCreditStatic : public CStatic { protected: COLORREF m_Colors[5]; int m_TextHeights[4]; TCHAR m_Escapes[4]; int m_DisplaySpeed[3],m_CurrentSpeed; // CRect m_ScrollRect; // rect of Static Text frame CStringList m_ArrCredit; CString m_szWork; int m_nCounter; // work ints POSITION m_ArrIndex; BOOL m_bFirstTime; BOOL m_bDrawText; int m_nClip,m_ScrollAmount; int m_nCurrentFontHeight; CBitmap m_bmpWork; // bitmap holder CBitmap m_BmpMain; // bitmap holder CSize m_size; // drawing helpers CPoint m_pt; BOOL m_bProcessingBitmap; CPalette m_pal; CBitmap m_bitmap; int m_cxBitmap, m_cyBitmap; BOOL m_bFirstTurn; UINT m_Gradient; BOOL m_bTransparent; int n_MaxWidth; UINT TimerOn; // Construction public: CCreditStatic(); // Attributes public: // Operations public: BOOL StartScrolling(); void EndScrolling(); void SetCredits(LPCTSTR credits, char delimiter = '|'); void SetCredits(UINT nID, char delimiter = '|'); void SetSpeed(UINT index, int speed = 0); void SetColor(UINT index, COLORREF col); void SetTextHeight(UINT index, int height); void SetEscape(UINT index, char escape); void SetGradient(UINT value = GRADIENT_RIGHT_DARK); BOOL SetBkImage(UINT nIDResource); BOOL SetBkImage(LPCTSTR lpszResourceName); void SetTransparent(BOOL bTransparent = TRUE); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCreditStatic) //}}AFX_VIRTUAL // Implementation public: virtual ~CCreditStatic(); // Generated message map functions protected: void MoveCredit(CDC *pDC, CRect& r, CRect& r2, BOOL bCheck); void AddBackGround(CDC* pDC, CRect& m_ScrollRect, CRect& m_ClientRect); void DrawCredit(CDC* pDC, CRect& m_ScrollRect); void FillGradient(CDC *pDC, CRect *m_ScrollRect, CRect *m_FillRect, COLORREF color); void DrawBitmap(CDC* pDC, CDC* pDC2, CRect *rBitmap); //{{AFX_MSG(CCreditStatic) afx_msg void OnPaint(); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnTimer(UINT nIDEvent); afx_msg void OnDestroy(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_CREDITSTATIC_H__4ABD7701_49F5_11D1_9E3C_00A0245800CF__INCLUDED_) |