Visual C++ 開發環境為控件提供的自繪制功能使程序員能夠充分發揮自己的創造性來設計比較漂亮的程序界面。所謂AVI按鈕是指每當鼠標從按鈕上經過時就播放一段按鈕提示的AVI,在許多的游戲程序以及三維動畫軟件中(如摩托英豪、Cool 3D等)都廣泛的采用了這種AVI按鈕。它使得程序的用戶界面很具有動感,也使得我們的程序至少看上去更專業,本實例借助Visual C++強大的控件自繪制功能來實現這種AVI按鈕的原理及實現。 程序編譯運行后的界面效果如圖一所示:
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID ); |
風格 | 含義 |
ACS_CENTER | 使動畫片居于控件中央,并使動畫片打開后控件窗口的尺寸和位置保持不變。如果不指定該風格,則控件的尺寸會自動調整來適應動畫片的大小。 |
ACS_TRANSPARENT | 使動畫片的背景透明(不輸出動畫片的背景色)。 |
ACS_AUTOPLAY | 一旦打開動畫片后就一直重復播放。 |
表一、動畫控件的風格
除表中的風格外,一般還要為動畫控件指定WS_CHILD、WS_VISIBLE和WS_BORDER窗口風格。例如,要創建一個能自動播放的動畫控件,應該指定其風格為WS_CHILD|WS_VISIBLE|WS_BORDER|ACS_AUTOPLAY。
CAnimateCtrl類主要的成員函數包括:BOOL Open( LPCTSTR lpszFileName )、BOOL Open( UINT nID ) 、BOOL Play( UINT nFrom, UINT nTo, UINT nRep ) 、BOOL Seek( UINT nTo )、BOOL Stop( )、BOOL Close( )等。
上述的Open()函數從AVI文件或資源中打開視頻流,如果參數lpszFileName或nID為NULL,則系統將關閉以前打開的視頻流。Play()函數用來播放選定的視頻流,參數nFrom指定了播放的開始幀的索引,索引值必須小于65536,若為0則從頭開始播放。nTo指定了結束幀的索引,它的值必須小于65536,若為-1則表示播放到視頻流的末尾。nRep是播放的重復次數,若為-1則無限重復播放。Seek()函數用來靜態地顯示視頻流的某一幀。參數nTo是幀的索引,其值必須小于65536,若為0則顯示第一幀,若為-1則顯示最后一幀,若成功則函數返回TRUE。Stop()函數用來停止動畫片的播放。Close()函數用來關閉并從內存中清除視頻流。上述所有函數都是調用成功返回TRUE,否則返回FALSE。
讀者朋友們在學習的過程中要注意,動畫控件并不能播放所有的AVI文件,只有滿足下列條件的AVI文件才能被播放:1)AVI文件必須是無聲的,不能有聲道;2)AVI文件必須是未壓縮的,或是用RLE算法壓縮的;3)AVI的調色板必須保持不變。另外,動畫控件最大的一個局限性在于它只能顯示系統調色板中缺省的顏色,因此如果用動畫控件來播放一個256色的AVI文件,那么播放效果看起來就象一個16色的動畫一樣,很不理想??傊?,動畫控件只能播放一些簡單的,顏色數較少的AVI動畫。如果要較滿意地播放256色的AVI文件,就要利用MCI接口,這部分內容請讀者朋友參閱有關資料。
二、編程步驟
1、啟動Visual C++6.0,生成一個基于對話框的應用程序,取其項目名為 TestAviButton, 然后按下 Finish 按鈕來完成工程的創建;
2、使用Class Wizard菜單命令以CButton 為基類創建CAviButton 類,生成類的頭文件 AviButton.h 和實現文件 AviButton.cpp,同時在類中重載 Create()、DrawItem()函數和 WM_MOUSEMOVE的消息映射;
3、打開工程中ID值為IDD_TESTAVIBUTTON_DIALOG 的對話框進行編輯,該對話框的提示文本為"將鼠標移至按鈕上:"刪除"取消"按鈕,將"確定"按鈕的屬性 Styles 改為 OwnerDraw ,并去掉其提示文本 "確定";另外執行 Insert | Resource… 命令,在彈出的對話框中按下 Custom… 按鈕,然后輸入"AVI",向程序中添加"AVI"格式的資源,然后選擇AVI類型的文件向項目中添加"AVI"格式的資源IDR_AVI;
4、添加代碼,編譯運行程序,此時每當我們的鼠標經過按鈕時,一個漂亮的AVI按鈕就產生了。
三、實現代碼
/////////////////////////////// AviButton.h : header file #if !defined(AFX_AVIBUTTON_H__5E20D4EF_864E_11D7_886E_F16C81CD642B__INCLUDED_) #define AFX_AVIBUTTON_H__5E20D4EF_864E_11D7_886E_F16C81CD642B__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CAviButton : public CButton { // Construction public: CAviButton(); public: UINT m_nAviID; CAnimateCtrl AnimateCtrl; BOOL bPlaying; void LoadAvi(UINT nAviID); void DrawButton(CDC* pDC, UINT nState, CRect rect); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAviButton) public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); //}}AFX_VIRTUAL // Implementation public: virtual ~CAviButton(); // Generated message map functions protected: //{{AFX_MSG(CAviButton) afx_msg void OnMouseMove(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif ////////////////////////////CAviButton.CPP文件; #include "stdafx.h" #include "TestAviButton.h" #include "AviButton.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CAviButton::CAviButton() { m_nAviID = 0; bPlaying = FALSE; } CAviButton::~CAviButton() {} void CAviButton::LoadAvi(UINT nAviID) { m_nAviID =nAviID; } BEGIN_MESSAGE_MAP(CAviButton, CButton) //{{AFX_MSG_MAP(CAviButton) ON_WM_MOUSEMOVE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////// CAviButton message handlers void CAviButton::DrawButton(CDC *pDC, UINT nState, CRect rect) { COLORREF upCol,downCol,edgeCol; edgeCol=RGB(0,0,0); //設置按鈕邊緣的初始化顏色; if ((nState & ODS_SELECTED) == ODS_SELECTED) { //設置按鈕被按下時按鈕的顏色 upCol=RGB(0,0,0); edgeCol=RGB(128,128,128); downCol=RGB(0,0,0); } else { //設置按鈕正常時按鈕的顏色 upCol=RGB(255,255,255); downCol=RGB(128,128,128); } CPen* pOldPen = NULL; BOOL pen1Created; CPen pen1; BOOL pen2Created; CPen pen2; if (pen1Created = pen1.CreatePen(PS_SOLID, 1, upCol)) pOldPen = pDC->SelectObject( &pen1 ); //畫左上邊緣 pDC->MoveTo(1,rect.Height()-1); pDC->LineTo(1,1); pDC->LineTo(rect.Width()-1,1); pDC->MoveTo(0,rect.Height()-1); pDC->LineTo(0,0); pDC->LineTo(rect.Width()-1,0); if (pen2Created = pen2.CreatePen(PS_SOLID, 1, downCol)) pDC->SelectObject( &pen2 ); if (pen1Created) { pen1.DeleteObject(); pen1Created = FALSE; } //畫右下邊緣 pDC->MoveTo(rect.Width()-1,0); pDC->LineTo(rect.Width()-1,rect.Height()-1); pDC->LineTo(0,rect.Height()-1); pDC->MoveTo(rect.Width()-2,1); pDC->LineTo(rect.Width()-2,rect.Height()-2); pDC->LineTo(0,rect.Height()-2); if (pen2Created)//刪除"pen2"畫筆對象 { pen2.DeleteObject(); pen2Created = FALSE; } if (pen1Created = pen1.CreatePen(PS_SOLID, 1, edgeCol)) pOldPen = pDC->SelectObject( &pen1 ); if (pen1Created) { pen1.DeleteObject(); pen1Created = FALSE; } if (pOldPen != NULL) pDC->SelectObject( pOldPen ); } void CAviButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // TODO: Add your code to draw the specified item CRect rect; GetClientRect(rect); if (!::IsWindow(AnimateCtrl)) { //在按鈕上生成一個動畫控件 AnimateCtrl.Create(WS_CHILD |WS_VISIBLE,rect,this,0); //打開avi文件并顯示第一幀 AnimateCtrl.Open(m_nAviID); AnimateCtrl.GetClientRect(rect); } CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); UINT nState = lpDrawItemStruct->itemState; CRect buttonRect; GetClientRect(buttonRect); //繪制按鈕 DrawButton(pDC, nState, buttonRect); } BOOL CAviButton::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { // TODO: Add your specialized code here and/or call the base class return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); } void CAviButton::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default ClientToScreen(&point); CRect rcWindow; GetWindowRect(rcWindow); //判斷鼠標是否經過按鈕 BOOL bNewMouseOverButton = rcWindow.PtInRect(point); if (bNewMouseOverButton && IsWindowEnabled() ) { if (::IsWindow(AnimateCtrl) && !bPlaying) { AnimateCtrl.Play(0,-1,1); bPlaying = TRUE; SetCapture(); } } else { bPlaying = FALSE; ReleaseCapture(); } CButton::OnMouseMove(nFlags, point); } ///////////////////////////////// BOOL CTestAviButtonDlg::OnInitDialog() { CDialog::OnInitDialog(); …………………//此處代碼省略; m_AviButton.LoadAvi(IDR_AVI); return TRUE; // return TRUE unless you set the focus to a control } |