标题:[原创]使用ActiveMovie控件自制播放器心得(新手第一帖,请支持,谢谢)--> ...
只看楼主
赵博闻
Rank: 1
等 级:新手上路
帖 子:47
专家分:0
注 册:2007-9-20
 问题点数:0 回复次数:2 
[原创]使用ActiveMovie控件自制播放器心得(新手第一帖,请支持,谢谢)-->Eastsun

*/ --------------------------------------------------------------------------------------
*/ 出自: 编程中国 http://www.bc-cn.net
*/ 作者: 赵博闻
*/ 时间: 2007-10-29 编程论坛首发
*/ 声明: 尊重作者劳动,转载请保留本段文字
*/ --------------------------------------------------------------------------------------
我是一个VC++初学者,并没有什么了不起的建树。只是根据我一段时期的学习,和禅悦的资料自己设计了一个播放器。
想把其中的一些技术要点与各位分享。理由是,现在网络中关于这方面的事例多半残缺不全,我设计的这个虽谈不上新意,但相对全面,相信有一定的借鉴价值。另外,还有部分功能没有及时实现,还望高手们看后能给与指教,丰富其功能。在此一并谢过了。
要点:本播放器包括
功能方面:文件打开,播放,暂停,停止,全屏显示,声音控制,播放进度,播放列表
外观方面:不规则外观(可根据位图任意绘制),不规则按钮,圆形,和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);
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();
放在主程序的初始化函数中,使之一运行就跳过主对话框直接显示。
成果物:

第三部分 遗留问题和总结
1播放器中还希望加入截屏功能,可控件ActiveMovie在选择播放区域的问题上表现得并不好,没能找到很好的区域选择函数。实现后的效果是截下了整个屏幕。
2提高不规则按钮的设计。主要方向要放在鼠标响应事件的选取上。使之完善。
综上:是本次设计项目的简要概括和技术要点。不足之处还很多。
请大家发表意见,帮我提高,谢谢。

搜索更多相关主题的帖子: ActiveMovie Eastsun 控件 心得 
2007-10-29 14:21
jj0321109
Rank: 1
等 级:新手上路
威 望:1
帖 子:58
专家分:0
注 册:2007-9-15
得分:0 

厉害,你知道怎么实现逐帧播放吗?

2007-11-08 10:50
netstriker
Rank: 1
等 级:新手上路
威 望:1
帖 子:257
专家分:0
注 册:2007-3-24
得分:0 
  厉害。学习中。。。。
2007-11-08 11:28



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-181665-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.395331 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved