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

使用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();
放在主程序的初始化函数中,使之一运行就跳过主对话框直接显示。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值