您的位置:首页 > 其它

使用ActiveMovie控件制作多媒体播放器(支持MP3,WAV,dat,wma,mpeg,avi等)

2013-09-15 09:09 411 查看

使用ActiveMovie控件制作多媒体播放器(支持MP3,WAV,dat,wma,mpeg,avi等)

ActiveMovieActiveMovie控件是微软公司推出的用于多媒体程序设计的控件,它提供了非常完善的音频和视频媒体文件的回放功能,能支持多种文件格式,从最常见的WAV文件和AVI文件到使用MPEG压缩格式的VCD视频文件,都可以正常的进行播放。控件能根据文件后缀进行自动判别设备类型,并完成相应的控制。因此,若正在编写的应用程序需要提供多媒体支持,那么使用ActiveMovie控件是一个很好的主意。事实上,很多优秀的多媒体应用程序,其内部的多媒体回放就是利用ActiveMovie控件来实现。只要精心地设计应用程序的用户界面,我们一样可以开发出功能齐全、外观漂亮、具有相当水准的多媒体播放器。而且,在Windows
95/98和Windows NT的最新版本中,ActiveMovie控件已作为操作系统的一部分来提供,即使用户系统中没有安装ActiveMovie控件,Microsoft的许可协议也允许在你的应用程序的发行包中发布ActiveMovie的运行时文件。
要点:本播放器包括

功能方面:文件打开,播放,暂停,停止,全屏显示,声音控制,播放进度,播放列表

外观方面:不规则外观(可根据位图任意绘制),不规则按钮,圆形,和XP风格

文末附加存在的问题。(成果物是样式贴图,可好像显示有点问题,还请见谅)

正文:

简易播放器

第一部分:功能

1打开文件

初始化一些变量值:

CObjectPlayerDlg::CObjectPlayerDlg(CWnd* pParent /*=NULL*/)

     : CDialog(CObjectPlayerDlg::IDD, pParent)

{

     //{{AFX_DATA_INIT(CObjectPlayerDlg)

     //}}AFX_DATA_INIT

     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32

     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

     m_Enable = false;

     ISPause=false;

}

利用ACTIVEMOVIECONTROL控件建立播放器,并逐步添加功能。

当点击“打开文件”时选择要播放的文件,该文件名会显示在播放列表中。原来显示的是全路经,我现在该位只显示文件名了。

void CObjectPlayerDlg::OnBtnOpen()

{

     // TODO: Add your control notification handler code here

     CString pathName,str1;

     bool bobtn = true;

     char szFileFilter[]=

         "Mp3 File(*.mp3)|*.mp3|"

         "Wma File(*.wma)|*.wma|"

         "Video File(*.dat)|*.dat|"

         "Wave File(*.wav)|*.wav|"

         "AVI File(*.avi)|*.avi|"

         "Movie File(*.mov)|*.mov|"

         "Media File(*.mmm)|*.mmm|"

         "Mid File(*.mid;*,rmi)|*.mid;*.rmi|"

         "MPEG File(*.mpeg)|*.mpeg|"

         "All File(*.*)|*.*||";

     CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,szFileFilter);

     if (dlg.DoModal()==IDOK) {

         pathName = dlg.GetPathName();

         pathName.MakeUpper();//大写

         m_ActiveMovie.SetFileName(pathName);//??????????似乎这样用友问题,可用下面这句代替实现相同功能)

          m_AcitveMove.InvokeHelper((DISPID)0xb,DISPATCH_PROPERTYPUT,VT_EMPTY,NULL,parms,FileName);
         int Istr;

         for (int i=0;i<pathName.GetLength();i++)

         {            

             Istr=pathName.Find(_T("\\"),i);

             if (Istr==-1)

             {    //但如果遇到路经中夹带中文就不好用了,比如“测”字中第一个字节信息会被误认为是“\”从而出错,所以路经中除了目标文件名外最后一个“\”前的字符最好都用英文

                 str1=pathName.Mid(i);

                 break;    

             }            

         }

     //     m_ListB.AddString(pathName);

         m_ListB.AddString(str1);

         UpdateData(FALSE);

         bobtn = false;

//如果有文件加载,使按钮有效

         m_Enable = true;

         if (m_Enable) {

             m_BtnRun.EnableWindow(TRUE);

             m_BtnUpRadio.EnableWindow(TRUE);

             m_BtnDownRadio.EnableWindow(TRUE);

             m_BtnShotStop.EnableWindow(TRUE);

             m_BtnStop.EnableWindow(TRUE);

             m_BtnAllShow.EnableWindow(TRUE);

             m_SliderRadion.EnableWindow(TRUE);        

             return;

         }

     }

     if (bobtn == true) {

         AfxMessageBox(_T("请选择要播放的文件!"));

         return;

     }

}

2全屏显示:

void CObjectPlayerDlg::OnBtnAllShow()

{

     // TODO: Add your control notification handler code here

     m_ActiveMovie.Pause();

     m_ActiveMovie.SetFullScreenMode(true);

     m_ActiveMovie.SetMovieWindowSize(SW_SHOWMAXIMIZED);

     m_ActiveMovie.Run();

}

3暂停

void CObjectPlayerDlg::OnBtnShotStop()

{

     // TODO: Add your control notification handler code here

     if (ISPause)

     {

         m_ActiveMovie.Run();

         ISPause=false;

     }

     else

     {

         m_ActiveMovie.Pause();

         ISPause=true;

     }

}

4停止

void CObjectPlayerDlg::OnBtnStop()

{

     // TODO: Add your control notification handler code here

     m_ActiveMovie.Stop();

     KillTimer(0);    

}

5增加音量

void CObjectPlayerDlg::OnBtnUpRadio()

{

     // TODO: Add your control notification handler code here

     long m_volume = m_ActiveMovie.GetVolume();

     m_ActiveMovie.Pause();

     m_ActiveMovie.SetVolume(m_volume+100);

     m_ActiveMovie.Run();    

}

6减小音量

void CObjectPlayerDlg::OnBtnDownRadio()

{

     // TODO: Add your control notification handler code here

     long m_Reduce = m_ActiveMovie.GetVolume();

     m_ActiveMovie.Pause();

     m_ActiveMovie.SetVolume(m_Reduce-100);

     m_ActiveMovie.Run();    

}

7 刚开始显示窗口时如果不加载要播放的文件就让这些按钮都失效

void CObjectPlayerDlg::OnShowWindow(BOOL bShow, UINT nStatus)

{

     CDialog::OnShowWindow(bShow, nStatus);

    

     // TODO: Add your message handler code here

     if (m_Enable==false)

     {

         m_BtnRun.EnableWindow(FALSE);

         m_BtnUpRadio.EnableWindow(FALSE);

         m_BtnDownRadio.EnableWindow(FALSE);

         m_BtnShotStop.EnableWindow(FALSE);

         m_BtnStop.EnableWindow(FALSE);

         m_BtnAllShow.EnableWindow(FALSE);

         m_SliderRadion.EnableWindow(FALSE);

     }

}

8 播放进度条。

其响应消息是

void MyPlayDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)

{

     CSliderCtrl *pSliderRun = (CSliderCtrl*)pScrollBar;

     int nRunTime = pSliderRun->GetPos();

     m_ActiveMovie.SetCurrentPosition(nRunTime);

     int MaxRange = m_ActiveMovie.GetCurrentPosition();

     m_SliderRun.SetRange(0,53);//需要得到文件长度

     m_SliderRun.SetTicFreq(10);

     m_SliderRun.SetLineSize(100);

     m_SliderRun.SetPageSize(10);

     CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

}

如果有多个进度条都可以在这里响应,它的执行先于控件事件。

第二部分:不规则窗体

利用CRgn类实现,真是很麻烦。

首先理清思路,我们想实现一个不规则窗体例如程序的应用界面,最好是可以按照位图形装任意创建窗体,这样更改窗体时,只要重新制作位图就可以了无需改动代码。

其次,在工程的主对话框实现该方法是不行的,因为那时整个对话框尚未生成,无法加载位图到一个不存在的区域中,

所以确定了这样的方案:

1设主对话框为A,让A调用对话框B(这时对话框以生成可以加载位图)。

2制作一个类DLGBase让B继承,原因是:要先画出图形在依图创建窗体,但是如果都写在一个对话框中会在调用Paint重绘之前先调用创建对话框的init初始化方法,无法正确实现(此处尚在讨论中)

3在DLGBase中实现位图加载,

4在B中实现CRgn创建窗体。

具体步骤:

1建立对话框B我的是IDD_MyPlayerDlg,文件名:MyPlayDlg把头文件引入主对话框中,在初始化方法中     MyPlayDlg dlg;

             dlg.DoModal();

加载位图。

2建立基于Dialog的空类DLGBase。定义一个位图对象CBitmap m_bmp;

一下需要手动该

。H

     DLGBase(UINT nID,CWnd* pParent = NULL);   // standard constructor

。Cpp

DLGBase::DLGBase(UINT nID,CWnd* pParent /*=NULL*/)

     : CDialog(nID, pParent)

{

     //{{AFX_DATA_INIT(DLGBase)

         // NOTE: the ClassWizard will add member initialization here

     //}}AFX_DATA_INIT

}

BOOL DLGBase::OnInitDialog()

{

     CDialog::OnInitDialog();

    

     // TODO: Add extra initialization here

         /*将窗体大小调整到位图大小一样*/

     m_bmp.LoadBitmap(IDB_BITMAP1);

     BITMAP bm;

     m_bmp.GetBitmap(&bm);

     CRect rtWindow;

     GetWindowRect(&rtWindow);

     rtWindow.right = rtWindow.left+bm.bmWidth;

     rtWindow.bottom =rtWindow.top +bm.bmHeight;

     MoveWindow(&rtWindow);

    

     return TRUE;   // return TRUE unless you set the focus to a control

                   // EXCEPTION: OCX Property Pages should return FALSE

}

void DLGBase::OnPaint()

{

     CPaintDC dc(this); // device context for painting

    

     // TODO: Add your message handler code here

     CDC picDC;    

     picDC.CreateCompatibleDC (&dc);

    

     CBitmap *pOldBmp;

     pOldBmp = picDC.SelectObject (&m_bmp);

    

     BITMAP bm;

     m_bmp.GetBitmap(&bm);

     //加载

       dc.BitBlt (0,0,bm.bmWidth ,bm.bmHeight,&picDC,0,0,SRCCOPY);

     dc.SelectObject(pOldBmp);        

     // Do not call CDialog::OnPaint() for painting messages

}

UINT DLGBase::OnNcHitTest(CPoint point)

{

     // TODO: Add your message handler code here and/or call default

     //鼠标可以点击任意处移动窗体

     UINT nResult = CDialog::OnNcHitTest(point);    

     return nResult == HTCLIENT ? HTCAPTION : nResult;

}

3让MyPlayDlg继承DLGBase,注意MyPlayDlg::MyPlayDlg(CWnd* pParent /*=NULL*/)

     : DLGBase(MyPlayDlg::IDD, pParent)

void MyPlayDlg::DoDataExchange(CDataExchange* pDX)

{

     DLGBase::DoDataExchange(pDX);

}

BEGIN_MESSAGE_MAP(MyPlayDlg, DLGBase)

尤其是:DLGBase::OnInitDialog();//如果不把CDialog改掉仍然会先访问这里

代码:

BOOL MyPlayDlg::OnInitDialog()

{

     DLGBase::OnInitDialog();

    

     // TODO: Add extra initialization here

     CClientDC dc(this);

SetupRegion(&dc,m_bmp,RGB(255,255,255));

Return Ture;

}

void MyPlayDlg::SetupRegion(CDC *pDC, CBitmap &cBitmap, COLORREF TransColor)

{

     CDC memDC;

     //创建与传入DC兼容的临时DC

     memDC.CreateCompatibleDC(pDC);

    

     CBitmap *pOldMemBmp=NULL;

     //将位图选入临时DC

     pOldMemBmp=memDC.SelectObject(&cBitmap);

    

     CRgn wndRgn;

     //创建总的窗体区域,初始region为0

     wndRgn.CreateRectRgn(0,0,0,0);

    

    

     BITMAP bit;  

     cBitmap.GetBitmap (&bit);//取得位图参数,这里要用到位图的长和宽    

    

     int y;

     for(y=0;y<=bit.bmHeight   ;y++)

     {

         CRgn rgnTemp; //保存临时region

        

         int iX = 0;

         do

         {

             //跳过透明色找到下一个非透明色的点.

             while (iX <= bit.bmWidth   && memDC.GetPixel(iX, y) == TransColor)

                 iX++;

            

             //记住这个起始点

             int iLeftX = iX;

            

             //寻找下个透明色的点

             while (iX <= bit.bmWidth   && memDC.GetPixel(iX, y) != TransColor)

                 ++iX;

            

             //创建一个包含起点与重点间高为1像素的临时“region”

             rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1);

            

             //合并到主"region".

             wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);

            

             //删除临时"region",否则下次创建时和出错

             rgnTemp.DeleteObject();

         }while(iX <bit.bmWidth );

         iX = 0;

     }

    

     if(pOldMemBmp)

         memDC.SelectObject(pOldMemBmp);

    

     CWnd * pWnd = pDC->GetWindow();

     pWnd->SetWindowRgn(wndRgn,TRUE);    

     pWnd->SetForegroundWindow();    

        

}

效果图:

第二部分:其它

一 退出界面设计

软件要退出时应该有个退出界面,让用户确认是否真的要退出

效果图

步骤:

1在主干文件中定义退出变量,就是和工程同名的那个文件我的是ObjectPlayer。Cpp

Public:

BOOL ExitFlag;//退出标志符

2建立基于退出对话框的相关类,因为要用到程序对象App,所以在程序开始处引用对象extern CObjectPlayerApp theApp;

填写相应方法

void ExitDlg::OnOK()

{

     // TODO: Add extra validation here

     theApp.ExitFlag = TRUE;

     CDialog::OnOK();

}

void ExitDlg::OnCancel()

{

     // TODO: Add extra cleanup here

     theApp.ExitFlag = false;

     CDialog::OnCancel();

}

3在需要调用该对话框的文件中(.cpp)引入#include "ExitDlg.h"

extern CObjectPlayerApp theApp;

调用WM_Close消息

void CObjectPlayerDlg::OnClose()

{

     // TODO: Add your message handler code here and/or call default

     ExitDlg dlgExit;

     dlgExit.DoModal();//调用对话框

     if (theApp.ExitFlag) //判断标志位

     {

         CDialog::OnClose();

     }

}

二屏幕缩放

主要使用了SetMovieWindowSize();函数

属性:MovieWindowSize

说明:获得或设置电影窗口尺寸。取值为:

0 amvOriginalSize

1 amvadaoubleaoariginaSize

2 amvOneSixteenthSreen

3 amvOneFourthScreen

4 amvOneHalfScreen

三不规则按钮

查了很多资料,做得还是不理想,现在把一些重要资料节录:

二、实现原理及难点

下面我们开始类的创建,在Workspace的ClassView页中右击列表树的根结点,选择New Class…

在弹出窗口中进行派生类的定义,如下图所示,注意,你需要填写的只有Name和Base class两项,其余的选项保持默认值就可以了。

按OK按钮退出之后,我们可以在ClassView里面看到新创建的类的名字。接下来我们可以为CXPButton类添加各种成员变量。因为自绘控件说穿了就是画图,所以在成员变量中可以看到各种与画图有关的数据类型,一般来说成员变量会在类的构造函数中初始化,在类的析构函数中销毁。详细代码请参见本篇附带的源程序。

下面简要叙述一下按钮的实现原理:

1. 在控件初始化时为按钮添加Owner Draw的属性。这是因为在MFC中,要想激活控件的自绘功能,要求该控件的属性中必须包含属性值BS_OWNERDRAW,这一步我们可以通过类向导为CXPButton类添加PreSubclassWindow()函数,在该函数中完成属性值的设置。当激活控件的自绘功能之后,每次控件状态改变的时候都会运行函数DrawItem(),该函数的作用就是绘制控件在各种状态下的外观。

2. 添加WM_MOUSELEAVE消息函数,当鼠标指针离开按钮时,触发该消息函数,我们在函数中添加代码,通知DrawItem函数鼠标指针已经离开了,让按钮重绘。

3. 添加WM_MOUSEHOVER消息函数,当鼠标指针位于按钮之上时,触发该消息函数,我们在函数重添加代码,通知DrawItem函数鼠标指针现在正在按钮的上面,让按钮重绘。

4. 添加DrawItem函数。在DrawItem中根据按钮当前的状态绘制按钮的外观。可以说自绘控件的大部分功能都是在这个函数中实现的。DrawItem函数包含了一个LPDRAWITEMSTRUCT的指针,本篇会在稍后予以讲解。

了解了基本的设计思路之后,剩下就看我们怎么去实现了。我本人觉得这里有两个难点,首先是WM_MOUSELEAVE和WM_MOUSEHOVER不是标准的Windows消息函数,它们不能通过类向导来添加,所有的添加工作都需要通过手工输入代码来完成。另一个难点是DrawItem中的LPDRAWITEMSTRUCT指针,它指向了一个DRAWITEMSTRUCT的结构,这个结构中包含了控件的各种细节,为我们提供了实现自绘功能的必要信息。

难点一:

事实上WM_MOUSELEAVE和WM_MOUSEHOVER两个Windows消息是通过WM_MOUSEMOVE消息触发的,而WM_MOUSEMOVE是标准的Windows消息,因此我们可以通过类向导来为CXPButton类添加WM_MOUSEMOVE消息函数。

函数的代码见如下,这段代码非常有用,在其它的自绘控件中,如果想触发WM_MOUSELEAVE和WM_MOUSEHOVER消息,也是使用类似的方法实现的。

void CXPButton::OnMouseMove(UINT nFlags, CPoint point)

{

       // TODO: Add your message handler code here and/or call default

       if (!m_bTracking)

       {

               TRACKMOUSEEVENT tme;

               tme.cbSize = sizeof(tme);

               tme.hwndTrack = m_hWnd;

               tme.dwFlags = TME_LEAVE | TME_HOVER;

               tme.dwHoverTime = 1;

               m_bTracking = _TrackMouseEvent(&tme);

       }

       CButton::OnMouseMove(nFlags, point);

}

我们接着添加WM_MOUSELEAVE和WM_MOUSEHOVER消息消息函数。在CXPButton类的声明中(即在XPButton.h文件中)找到afx_msg void OnMouseMove(UINT nFlags, CPoint point);的函数声明,紧接其下输入

afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);

afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);

然后在XPButton.cpp文件中找到ON_WM_MOUSEMOVE(),紧接其后输入

ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)

ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)

当然最后还有函数的实现了,详细代码可见本篇提供的源程序,这里就不再重复了。

难点二:

下面我们看看DRAWITEMSTRUCE结构为我们提供了哪些有用信息呢?

DRAWITEMSTRUCT结构的定义如下:

typedef struct tagDRAWITEMSTRUCT {

     UINT   CtlType;                       //控件类型

     UINT   CtlID;                           //控件ID

     UINT   itemID;                         //菜单项、列表框或组合框中某一项的索引值

     UINT   itemAction;                   //控件行为

     UINT   itemState;                     //控件状态

     HWND   hwndItem;                 //父窗口句柄或菜单句柄

     HDC     hDC;                           //控件对应的绘图设备句柄

     RECT   rcItem;                         //控件所占据的矩形区域

     DWORD   itemData;                   //列表框或组合框中某一项的值

} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;

其实不仅是按钮控件,其它控件,如ComboBox、ListBox、StaticText等都是通过DRAWITEMSTRUCT来记录控件信息的。关于这个结构的详细文档可参考本篇的附录。

也许你早已看到许多自绘按钮的例子,实际上自绘按钮本身的函数结构都是差不多的,它们显示效果的区别主要取决于代码编写者对GDI作图函数的运用与掌握程度。有兴趣的朋友可以研究一下CXPButton类中DrawItem函数的数据结构,其实只要修改一下其中GDI绘图函数的部分代码,马上又能做出另一个自绘按钮控件了。

下面是我实现的代码:

在头文件里定义变量,在主干文件里为其赋初值

.H

Public:

     BOOL m_bTracking;     //在鼠标按下没有释放时该值为true

     BOOL m_bOver;     //鼠标位于按钮之上时该值为true,反之为flase

     BOOL m_bFocus;     //按钮为当前焦点所在时该值为true

     BOOL m_bSelected;     //按钮被按下是该值为true

.Cpp

DremBtn::DremBtn()

{

     m_bOver = m_bSelected   = m_bFocus = FALSE;

     m_bTracking = FALSE;

}

//调用BS_OWNERDRAW通知按钮自绘

void DremBtn::PreSubclassWindow()

{

     // TODO: Add your specialized code here and/or call the base class

    

     CButton::PreSubclassWindow();

     ModifyStyle(0, BS_OWNERDRAW);

}

//鼠标移动事件消息

void DremBtn::OnMouseMove(UINT nFlags, CPoint point)

{

     // TODO: Add your message handler code here and/or call default

     if (!m_bTracking) {

             TRACKMOUSEEVENT tme;

             tme.cbSize = sizeof(tme);

             tme.hwndTrack = m_hWnd;

             tme.dwFlags = TME_HOVER|TME_LEAVE;

             tme.dwHoverTime = 1;

             m_bTracking = _TrackMouseEvent(&tme);

         }

     CButton::OnMouseMove(nFlags, point);

}

LRESULT DremBtn::OnMouseLeave(WPARAM wParam, LPARAM lParam)

{

     m_bOver = FALSE;

     m_bTracking = FALSE;

//     m_bSelected = FALSE;

     InvalidateRect(NULL, FALSE);//更新region

     return 0;

}

LRESULT DremBtn::OnMouseHover(WPARAM wParam, LPARAM lParam)

{

     m_bOver = TRUE;

    

//     m_bSelected = TRUE;

     m_bTracking = TRUE;

     InvalidateRect(NULL);

     return 0;

}

//绘图

void DremBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

     // TODO: Add your code to draw the specified item

         CDC BtnDC;

     CDC MemDC;

     CBitmap bmp;

     BITMAP bm;

     CRect rect;

     CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);

     UINT state = lpDrawItemStruct->itemState;

     rect =   lpDrawItemStruct->rcItem;

     int nSaveDC=pDC->SaveDC();

         TCHAR strText[MAX_PATH + 1];

     ::GetWindowText(m_hWnd, strText, MAX_PATH);

//圆形区域

//     CRgn rgn;

//     rgn.CreateEllipticRgnIndirect(rect);

//     SetWindowRgn(rgn,TRUE);

     //获取按钮的状态

     if (state & ODS_FOCUS)

     {

         m_bFocus = TRUE;

         m_bSelected = TRUE;

     }

     else

     {

         m_bFocus = FALSE;

         m_bSelected = FALSE;

     }    

     if (state & ODS_SELECTED || state & ODS_DEFAULT)

     {

         m_bFocus = TRUE;

     }

//     pDC->SelectObject(hOldPen);

    

     rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));

    

     if (m_bTracking) //m_bOver

     {

         BtnDC.Attach(lpDrawItemStruct->hDC);

         MemDC.CreateCompatibleDC(&BtnDC);

         bmp.LoadBitmap(IDB_BITRun1);

        

         bmp.GetBitmap(&bm);

         CBitmap *pOld = MemDC.SelectObject(&bmp);

         //在按钮DC中绘制

         BtnDC.StretchBlt(rect.left,rect.top,rect.right,rect.bottom,

             &MemDC,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);

         //LoadTransBitmap(&MemDC,bmp,RGB(255,255,255));

         //还原旧GDI对象

         MemDC.SelectObject(pOld);

         bmp.DeleteObject();

     }

     else

     {

         BtnDC.Attach(lpDrawItemStruct->hDC);

         MemDC.CreateCompatibleDC(&BtnDC);

         bmp.LoadBitmap(IDB_BITRun2);

         bmp.GetBitmap(&bm);

         CBitmap *pOld = MemDC.SelectObject(&bmp);

         //在按钮DC中绘制

         BtnDC.StretchBlt(rect.left,rect.top,rect.right,rect.bottom,

             &MemDC,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);

         //LoadTransBitmap(&MemDC,bmp,RGB(255,255,255));

         //还原旧GDI对象

         MemDC.SelectObject(pOld);

         bmp.DeleteObject();

     }

//显示按钮的文本

     if (strText!=NULL)

     {

         CFont* hFont = GetFont();//获取字体

         CFont* hOldFont = pDC->SelectObject(hFont);

         CSize szExtent = pDC->GetTextExtent(strText, lstrlen(strText));

         CPoint pt( rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2);

         //移动

         if (state & ODS_SELECTED)

             pt.Offset(1, 1);

         int nMode = pDC->SetBkMode(TRANSPARENT);

         if (state & ODS_DISABLED)//被禁用时

             pDC->DrawState(pt, szExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);

         else

             pDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);

         pDC->SelectObject(hOldFont);

         pDC->SetBkMode(nMode);

     }

     pDC->RestoreDC(nSaveDC);

    

}

//擦除背景

BOOL DremBtn::OnEraseBkgnd(CDC* pDC)

{

     // TODO: Add your message handler code here and/or call default

    

     //return CButton::OnEraseBkgnd(pDC);

     return TRUE;

}

如果要实现以下效果需要对位图进行透明处理,否则会有边缘残留!

成果物:

    

四消除屏幕闪烁

ActiveMovie控件关心的只是起始点和拖拽大小无关,即控件左上角那点。

做法:我先得到一个区域,然后得到该区域的长和宽,最后在指定的区域内绘图。这样就不会因为重绘背景时在原来的控件寓于内闪烁了

BOOL MyPlayDlg::OnEraseBkgnd(CDC* pDC)

{

//椭圆形窗体

     CRgn m_rgn;

     m_rgn.CreateEllipticRgn(55,70,455,330);

     m_ActiveMovie.SetWindowRgn(m_rgn,TRUE);

     int nWindth,nHeight;

     nWindth = 405;

     nHeight = 260;

     CDC MenDC;

MenDC.CreateCompatibleDC(NULL);//背景画刷为空

     MenDC.FillSolidRect(0,0,nWindth,nHeight,RGB(0,222,0));//用绿色填充整片区域,但由于背景画刷已经射为空,其实是没用的

     MenDC.DeleteDC();

     return TRUE;

}

//初步解决得了闪烁问题但灵活性很差。

最后效果:

把播放器的启动函数

CMyPlayer dlg;

dlg.DoModal();

放在主程序的初始化函数中,使之一运行就跳过主对话框直接显示。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: