如何在VC5下定制多媒体真彩封页
 在自己的应用程序定制多媒体真彩封页,可以使应用程序在显示名称和版权特性时丰富程序界面,避免由于应用程序启动前进行大量数据初始化时用户进行较长时间的空等待过程,在给应用程序增加了生动特性和专业特性的同时,也起到了宣传和广告的作用。虽然VC5中具有特定的类来实现这一功能,但通过定制自己的应用程序多媒体启动封页,还可使自己的应用程序别具一格。VC5中的实现步骤:
1.制作封页位图:制作应用程序多媒体启动封页真彩位图,记录位图的高度和宽度,建立所需要的其它多媒体声音等文件;
2.建立应用程序:利用FILE->NEW菜单建立名为START的多文档应用程序框架,并利用类向导AppWizard增加基类为generic CWnd 的新类CSplashWnd,将新类的文件改名为splash.h和splash.cpp,并增加WM_CREATE和WM_PAINT的消息映射函数;
3.定义变量和函数:在splash.h中定义如下成员变量和函数:
public:
BOOL Create(CWnd* pParentWnd=NULL);
HANDLE hBitsSrc;
LPSTR pBitsSrc;
UINT iW,iH; 

4.建立启动封页窗口:在splash.cpp中增加Create函数,建立显示位图的弹出窗口:
#include "windowsx.h"//增加扩展窗口建立
......
struct{//位图文件头结构
BITMAPINFOHEADER Header;
}Info;
BOOL CSplashWnd::Create(CWnd* pParentWnd)
{ //建立显示位图的弹出窗口
return CreateEx(0,AfxRegisterWndClass(0,
AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
NULL,WS_POPUP|WS_VISIBLE,0,0,672,480,
pParentWnd->GetSafeHwnd(),NULL);
}
int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ ......
// TODO: Add your specialized creation code here
CenterWindow();//使弹出窗口居中
return 0;


5.完善析构函数:在splash.cpp中完善析构函数,为显示位图作准备:
CSplashWnd::CSplashWnd()//完善析构函数
{ iW=672;iH=480;//位图的宽度和高度
Info.Header.biSize=sizeof(BITMAPINFOHEADER);
Info.Header.biWidth=iW;
Info.Header.biHeight=iH;
Info.Header.biPlanes=1L;
Info.Header.biBitCount=24L;
hBitsSrc=::GlobalAlloc(GHND,(long)(iW*iH*3));//分配内存
pBitsSrc=(LPSTR)::GlobalLock(hBitsSrc);//加锁内存
}
CSplashWnd::~CSplashWnd()
{ ::GlobalUnlock(hBitsSrc);//解锁内存
::GlobalFree(hBitsSrc);//释放内存


6.显示真彩位图:在splash.cpp中完善Onpaint函数,实现真彩位图的显示:
void CSplashWnd::OnPaint()
{......// TODO: Add your message handler code here
CFile fbmp;
fbmp.Open("c:\\windows\\EMC1.BMP",CFile::modeRead|
CFile::typeBinary|CFile::shareExclusive);//打开文件
fbmp.Seek(54,CFile::begin);//位图文件头为54字节
fbmp.ReadHuge(pBitsSrc,(long)(iW*iH*3));//读文件
fbmp.Close();//关闭文件
HBITMAP hBitmap=::CreateDIBitmap(dc.m_hDC,
(BITMAPINFOHEADER FAR*)&(Info.Header),CBM_INIT,
pBitsSrc,(LPBITMAPINFO)&Info,DIB_RGB_COLORS);//建立位图
HDC hMemDC=::CreateCompatibleDC(dc.m_hDC);//建立内存
HBITMAP hBitmapOld=SelectBitmap(hMemDC,hBitmap);//选择对象
::StretchBlt(dc.m_hDC,0,0,iW,iH,hMemDC,
0,0,iW,iH,SRCCOPY);//显示真彩位图
::DeleteObject(SelectObject(hMemDC,hBitmapOld));//删除位图


7.弹出窗口类声明:在Mainfrm.h中增加代码,为显示和撤销弹出窗口作准备:
class CsplashWnd;//闪烁窗口类
......
class CMainFrame : public CMDIFrameWnd
{......
public:
CSplashWnd SplashWnd;//声明类 

8.真彩封页的实现:在Mainfrm.cpp中增加显示弹出窗口、播放音乐、延时功能和撤销弹出窗口的代码,以实现真彩封页的整个处理过程:
#include "splash.h" //新类支持
#include "mmsystem.h"//多媒体支持
#pragma comment(lib,"WINMM.LIB")//多媒体支持
......
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
SplashWnd.Create(this);//创建弹出窗口
SplashWnd.ShowWindow(SW_SHOW);//显示弹出窗口
SplashWnd.UpdateWindow();//更新弹出窗口
int dd=sndPlaySound("c:\\windows\\reminder.wav",
SND_ASYNC|SND_LOOP);//异步播放WAV文件
if (dd==FALSE){//参数SND_ASYNC|SND_LOOP可循环播放
AfxMessageBox("播放WAV文件错误~");
}
::Sleep(2000);//进程休眠2秒
......//应用程序初始化工作
dd=sndPlaySound("",SND_ASYNC);//终止播放.WAV文件
SplashWnd.DestroyWindow();//撤消弹出窗口
return 0;


经过上述八个步骤的处理,整个多媒体真彩启动封页制作完毕。

在VC程序中加载GIF动画
PictureEx图片显示类支持以下格式的图片:GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR等,我特别推崇的是可以做出动画,而且轻而易举,确实很COOL。 
下面是详细的编程过程:

1. 新建项目:在VC6中用MFC新建一个基于对话框的GifDemo应用程序,接受所有缺省选项即可;

2.在项目中插入文件:把PictureEx.h,PictureEx.cpp文件copy 到项目文件夹下,Project->Add to Project->Files中选上PictureEx.h,PictureEx.cpp, Insert;

3.加入图片控件:从对话框控件中把Picture Control(图片控件)拖入主对话框中,修改其属性:ID:IDC_GIF,TYPE:Rectangle,其余接受缺省选项。再在ClassWiard中为IDF_GIF加入CSatic控制变量m_GifPic, 注意看一下,GifDemoDlg.h中是否加上了#include "PictureEx.h"(由ClassWiard加入)。然后将CSatic m_GifPic;更改成CPictureEx m_GifPic;

4.加载动画文件:先将要加载的动画文件放到 res 资源文件夹下,再将其Import进项目中,由于MFC只支持256BMP文件的图片,因此,我们要新建一个图片类型:"GIF",我在这里将我网站的宣传图片roaring.gif放进去 ,并将其ID修改成:IDR_GIFROARING。

import(导入)gif动画的详细过程:
在resourceview窗口中,单击鼠标右键,在出现的环境菜单中选择“import...”命令,会出现“import resource”选择文件对话框,文件类型选择“所有文件(*.*)”,open as 选项为"auto",再选择动画文件所在目录,选上要载入的动画文件 roaring.gif,再单击 import,由于gif动画类型不是vc默认的文件类型,这时会出现"custom resource type"对话框,键入“"gif"”,再单击ok,然后再修改其id。


5.在程序的适当位置添入加载代码: 这里,我们在CGifDemoDlg::OnInitDialog()函数中加入如下代码:
// TODO: Add extra initialization here
if (m_GifPic.Load(MAKEINTRESOURCE(IDR_GIFROARING),_T("Gif")))
m_GifPic.Draw();


如果仅仅把动画载入,到这就可以了,运行一下,应该看看您的的成果了。

下面附带说说如何将这幅动画制作成超链接,以后,咱们也可以宣传自已的公司、网站或产品了。

6.利用ClassWiard加入一个LButtonDown鼠标左键消息处理函数CGifDemoDlg::OnLButtonDown(UINT nFlags, CPoint point), 添入如下代码:
void CGifDemoDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
CRect rect;
m_GifPic.GetWindowRect(&rect);
ScreenToClient(&rect);

if (rect.PtInRect(point))
ShellExecute(AfxGetMainWnd() ->m_hWnd,_T("open"),
_T("http://roaringwind.best.163.com"),_T(""),NULL,0);


CDialog::OnLButtonDown(nFlags, point);



我在这儿将我主页的地址放上了,运行,点击动画图片就能进入我的站点的了。当然要是能象所有的超链接一样,能将鼠标变成手形,就更好了。

7.改变鼠标形状:将一个鼠标文件放在res文件夹中,IMPORT,ID:IDC_CURSOR1,利用ClassWiard加入一个WM_SETCURSOR消息处理函数CGifDemoDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message), 添入如下代码:
BOOL CGifDemoDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
// TODO: Add your message handler code here and/or call default
CRect rect;
m_GifPic.GetWindowRect(&rect);
ScreenToClient(&rect);

CPoint point;
GetCursorPos(&point);
ScreenToClient(&point);

if (rect.PtInRect(point) && m_hCursor)
{
SetCursor(m_hCursor);
return TRUE;
};


return CDialog::OnSetCursor(pWnd, nHitTest, message);



不错吧。

VC++ 6.0下自制媒体播放器

可视动画控件ActiveMovie是Microsoft公司开发的ActiveX控件,从开始的1.0版、1.2版到现在的2.0版,功能上已经有了很大的改进。由于该控件内嵌了Microsoft MPEG音频解码器和Microsoft MPEG视频解码器,所以能够很好地支持音频文件和视频文件,用其播放的VCD效果就很好。

  另外,播放时若用鼠标右键单击画面,可以直接对画面的播放、暂停、停止等进行控制,读者还可以自行在“属性”栏中对影片播放进行控制设置,用起来非常方便。

  在Microsoft公司去年推出的VC++6.0中已经包含了ActiveMovie控件的2.0版,笔者 在VC++6.0下利用这个控件自制了一个简易的媒体播放器,除了满屏功能外,还可以对音量进行控制。下面把具体做法介绍给读者。

  一 建立工程 

  利用 VC++6.0的AppWizard生成一个基于对话框的工程Player,去掉对话框上的确定和取消按钮,并加入ActiveMovie控件(通常情况下ActiveMovie控件并不出现在控件面板中,可在菜单中依次选择“project—Add To Project— >Components And Controls”,在出现的“Components And Controls Gallery”对话框中打开“Registered Active Controls”文件夹,选中“ActiveMovie Control Object”选项,按“Insert”后关闭该对话框,ActiveMovie控件便出现在控件面板中),调整好控件在对话框中的位置。为了能够控制控件的操作,应为对话框设计一个菜单,菜单的项目可以定为文件、屏幕控制和音量控制。

  二 添加代码 

  首先利用ClassWizard为ActiveMovie控件声明一个变量m_ActiveMovie。然后为菜单文件添加两个菜单项打开文件和退出,并分别添加函数OnOpen()和OnExit(),代码如下:
void Cplayer::OnOpen()

{ // TODO: Add your command handler code here char szFilter[] =

" 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 (*.*)∣*.* ";

//用于设置FileDialog的文件类型

CFileDialog FileDlg( TRUE, NULL, NULL, OFN_HIDEREADONLY, szFilter ); 

if( FileDlg.DoModal() == IDOK ) { CString PathName = FileDlg.GetPathName(); 

PathName.MakeUpper();

        m_ActiveMovie.SetFileName(PathName);

   }




  OnOpen()函数的作用是显示“打开”对话框,通过该对话框选择要执行的文件。 

利用Visual C++实现AVI文件的图像截取

AVI文件就是我们所说的多媒体文件,所谓的AVI图像就是视频图像,该文件是一个RIFF说明文件,它用于获取、编辑、演示音频、视频序列。一般的AVI文件包含音频流和视频流,有的特殊的AVI还包含一个控制路径或MIDI路径作为附加的数据流。

  现在播放AVI文件的软件很多,但大多无法从AVI视频文件中读取一帧图像并生成BMP格式的文件。笔者在使用AVI文件开发项目过程中对AVI文件的操作积累了一些经验,对于如何实现从AVI视频流中获取任意帧的图像数据并存储成BMP文件,其中最关键的是要从AVI文件中获取具体某一帧的图像数据,为此我利用Windows提供的API函数实现了自定义的CAvi类,用于操作AVI文件。

  在使用API函数操作AVI文件时,一定要注意用AVIFileInit()来初始化AVI库,程序结束时用AVIFileExit()释放AVI库,否则API函数无法使用。现以操作包含真彩色图像的AVI文件为例,给出Cavi类的部分函数的具体实现,其中CaviCreate()函数用于读取AVI文件信息并初始化Cavi类的成员,例如根据AVI文件信息定义每帧图像的宽、高、每帧图像的信息头结构等等;函数AviRead(int mFrame)用于从AVI文件中读取第mFrame帧。实现代码显示如下:

//Cavi类头文件定义;
class CAvi file://AVI类,处理AVI文件
{
 public:
 int cy;//图象高
 int cx;//图象宽
 file://long m_maxFrame;
 BYTE *pData;//寸储图象数据
 BITMAPINFO *m_pBMI;//位图文件信息头
 PAVISTREAM pavi;//AVI流
 PAVIFILE pfile;//AVI文件指针
 AVIFILEINFO * pfi; file://AVI信息
 BOOL AviRead(int mFrame);//读AVI文件的第mFrame帧
 CAvi();//标准构造函数
 CAviCreate(CString &string);//用文件名初始化AVI类的成员
 virtual ~CAvi();
}; 
//Cavi类文件实现部分;
CAvi::CAvi()
{ AVIFileInit();//初始化AVI库
 cx=0;//定义图象宽、高、等成员
 cy=0;
 m_pBMI=NULL;
 pData=NULL;
 file://m_maxFrame=0;
 pfi=NULL;
}
CAvi::~CAvi()//析构、释放指针
{
 // AVIFileClose(pfile);
 AVIFileExit();
 if(pData!=NULL)
  delete pData;
  pData=NULL;

 if(m_pBMI!=NULL)
  delete m_pBMI;
  m_pBMI=NULL;
  if(pfi!=NULL)
   delete pfi;
   pfi=NULL;
}
CAvi::CAviCreate(CString &string)//读文件初始化该类

 HRESULT hr;
 pfi=new AVIFILEINFO;
 hr = AVIFileOpen(&pfile, // returned file pointer
 string, // file name
 OF_READ, // mode to open file with
 NULL);
 hr= AVIFileInfo(pfile, file://获取AVI信息,放入pfi中
 pfi, 
 sizeof(AVIFILEINFO) 
);
cx=pfi->dwWidth;//图象宽、高
cy=pfi->dwHeight;
hr=AVIFileGetStream(//将AVI变成视频流
pfile, 
&pavi, 
streamtypeVIDEO, 
0//LONG lParam 
);
m_pBMI=new BITMAPINFO;//定义BMP信息头
m_pBMI->bmiHeader.biBitCount=24;
m_pBMI->bmiHeader.biClrImportant=0;
m_pBMI->bmiHeader.biClrUsed=0;
m_pBMI->bmiHeader.biCompression=BI_RGB;
m_pBMI->bmiHeader.biHeight=cy;
m_pBMI->bmiHeader.biWidth=cx;
m_pBMI->bmiHeader.biPlanes=1;
m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
m_pBMI->bmiHeader.biXPelsPerMeter=0;
m_pBMI->bmiHeader.biYPelsPerMeter=0;
m_pBMI->bmiHeader.biSizeImage=cx*cy*3;
pData=(BYTE*)new char[cx*cy*3];//根据AVI中BMP图象的信息定义缓冲区
}
BOOL CAvi::AviRead(int mFrame)//将AVI文件的M帧数据读入PData缓冲区
{
HRESULT hr;
hr= AVIStreamRead( pavi, 
mFrame, 
1, 
pData, 
cx*cy*3, 
NULL, 
NULL
);
if(hr==0)
return TRUE;
else
return FALSE;
}


  上述Cavi类实现部分所涉及到的API函数可以参考微软提供的MSDN。Cavi类中的pData缓冲区存放AVI文件中的具体某一帧图像数据,同时Cavi类的m_pBMI为BMP图像文件信息结构,这时可以根据图像的大小定义BMP图像文件头结构,关于BMP文件的存储,由于篇幅的原因,我不在多讲了,有兴趣的读者可以参见笔者的拙作"Visual C++6.0开发灰度位图处理"(天极网软件栏目2001.9.10发表),该文里面讲述了如何存取BMP文件。以上程序在Windows2000、Visual C++6.0环境下顺利编译通过,运行正常。

图像平滑滚动效果的VC实现

前言:

  在图像的编程中,经常会遇到这样一种情况,在有限的区域中显示了一幅大图,这时要浏览图像的各个部分,这就需要用到图像的滚动。关于它的实现,许多书都有提及,但其中的关键点和难点,即拖动中的刷新和闪烁问题,却讲述的不多,这也是我写本文的目的所在,下面我将详细分析实现方法。

  实现效果及实现方法:

  在图像区域中按下鼠标左键,可拖动图像在某一有限区域中任意滚动。

  方法为 :拖动时计算上次与本次的偏移,然后将图像显示的起始点进行变化并刷新图像区域。

  实现部分

  第一步:响应WM_LBUTTONDOWN 消息,记录按下开始拖动的起始位置。

  void CWingImgDlg::OnLButtonDown(UINT nFlags, CPoint point) 

  {

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

   m_lPicOldLeft = point.x;

   m_lPicOldTop = point.y;

   CDialog::OnLButtonDown(nFlags, point);

  }

  第二步:响应WM_MOUSEMOVE 消息,实现滚动。

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

  {

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

   file://如果鼠标按下 

   if( (nFlags & MK_LBUTTON) == MK_LBUTTON )

   {

    m_lPicNewLeft = point.x;

    m_lPicNewTop = point.y;

    DWORD dwLRShift = m_lPicNewLeft - m_lPicOldLeft;

    DWORD dwTBShift = m_lPicNewTop - m_lPicOldTop;

    file://改变图像显示的起始点

    m_lPicLeft = m_lPicLeft - dwLRShift;

    m_lPicTop = m_lPicTop - dwTBShift;

    file://判断边界的语句,省去。

    m_lPicOldLeft = m_lPicNewLeft;

    m_lPicOldTop = m_lPicNewTop;

    file://进行刷新的语句,见第四步。

   }

   CDialog::OnMouseMove(nFlags, point);

  }

  第三步:在OnPaint中显示,显示的其他部分,如图像的得来等,省去。

  void CWingImgDlg::OnPaint() 

   {

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

    file://其他的显示内容,省去。

    if(m_pImgInfo != NULL)

     dc.BitBlt(m_wShowAdjLeft,m_wShowAdjTop,m_lWidth,m_lHeight,&m_AdjDC,

     m_lPicLeft,m_lPicTop,SRCCOPY);

     CDialog::OnPaint();

    }

  第四步:刷新处理。

   最常想到的方法,当然是使用Invalidate(TRUE);//刷新整个无效区

   UpdateWindow();

   这时,会刷新整个程序区域的无效区,闪烁非常严重,改正如下:

    InvalidateRect(&m_rtPic,TRUE); file://仅刷新图像显示区域

    UpdateWindow();

   此时,仅会刷新图像所在区域,闪烁有所缓解,再进一步,可使用

    InvalidateRect(&m_rtPic,TRUE); file://使用快速重画

    ReDrawWindow(&m_rtPic,NULL,RDW_INTERNALPAINT| RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

进行处理,此时闪烁更进一步减小,考虑到,其他部分可能影响刷新区域,干脆将OnPaint()直接使用在此处,即变为:

  OnPaint(); 

  但如果在OnPaint()中有大量的绘图语句,这种方法仍旧不可行,考虑到不能激发OnPaint()这一因素及控制刷新范围,我采用了如下非标准的方法解决,代码如下:

  CDC *pDC;

  pDC = GetDC();

  if(m_pImgInfo != NULL)

   pDC->BitBlt(m_wShowLeft,m_wShowTop,m_lWidth,m_lHeight,&m_AdjDC,m_lPicLeft,m_lPicTop,SRCCOPY);

   ReleaseDC(pDC);

  这种方法很好地解决了刷新闪烁的问题,图像拖动时很平稳且无闪烁。

  这是我在实践中遇到的一个问题,写出来,与大家共享。如果有问题,或者有更好的建议和做法,欢迎和我联系探讨,如需要整个程序的源文件,请Mail联系(DavidZheng@Acercm.com.cn)。
posted on 2010-05-20 15:46  一个人的天空@  阅读(408)  评论(0编辑  收藏  举报