用WTL实现播放器的控制窗口

  

我们在WINDOWS下用C++进行界面编程,常用的界面库有两个,MFCWTLMFC也是我们最常用的一个,通常为了满足功能和界面美观的需要,大家在用时都会对其中一些控件进行再次的封装,这样的封装也有很多朋友把它放在了网上共享,以便大家可以直接拿过来用,省力省时。因为常用,所以MFC库支持下的控件显的很多,大家只要想得到的到网上基本上就能找到。有时我们为了写一些特殊的东东不能使用MFC,比如用ATL写一个控件,这时可能我们就会用到WTL

WTL由于用的人比较少,而且也没有系统的书籍进行讲解,刚开始使用时比较不爽。在网上更是难以找到已进行封装的控件。我在学习时走了不少的弯路,但好在最终还是略懂一二了,所以现在就以播放器控制窗口为例讲解一下实现方法,同时把我写的几个控件类也贡献一下。

  

控制窗口

 

在此讲例子可以从http://download.csdn.net/source/1428561下载。

在工程目录下WTL文件夹下是WTL头文件,为了让大家能在进行时不会缺少文件我就把其拷到了此处。

 

UIBmpBtn.h文件中有我已经封装的控件类。有以下几个模板类:

 

 

CBitmapButtonImpl    这个类在WTL中也能找到,我仅将其复制到此

CBitmapBtnImpl     这个类和上面的类差不多,我仅对其作了一点扩展,它能支持5种状态。比上面的更好用一些。下面是五种状态的说明

         _nImageNormal        平时没有操作时的状态

         _nImagePushed,         当点鼠标按下时的状态

         _nImageFocusOrHover,   当鼠标放在按钮上或经过时的状态

         _nImageDisabled,       当按钮被禁用时的状态

    _nImageClicked,        当按钮被点击之后放开鼠标后的状态,在下面的录像和静音按钮都有这一种状态。

CBmpBtnFive       这个类是对五种状态的进一步继承,加入手弄光标

CBmpBtn                 这个类是对CBitmapButtonImpl的进一步继承,加入手弄光标

CVideoSliderCtrl        这是视频进度条类

     CAudioSliderCtrl        音频控制SLIDER

 

  我们的这个例子就只有一个对话框,主对话框就是的我们要实现的播放器控制窗口。所以就来讲一下这个窗口的实现。

  首先在stdafx.h中我们已经包含了我们要用的头WTL头文件和STL中的的头文件。这里不再详细说明。

先看一下我们要在控制窗口中实现的控件变量在MainDlg.h中如下

     CBmpBtn                m_cBtnPlay;             // 开始按钮

     CBmpBtn                m_cBtnPause;           // 暂停按钮

     CBmpBtn                m_cBtnStop;             // 停止按钮

     CBmpBtn                m_cUpRate;              // 加速按钮

     CBmpBtn                m_cDownRate;           // 减速按钮

     CBmpBtnFive            m_cBtnRec;              // 录像按钮

     CBmpBtnFive            m_cSilence;             // 静音按钮

     CVideoSliderCtrl   m_cSliderVideo;             // 视频滑动条

     CAudioSliderCtrl   m_cSliderAudio;             // 音频滑动条

  这些控件变量都是手工添加的。但是在我们要先在窗口资源中加入对应的控件,但是不需添加控件变量。因为我们将会用上面声明的变量进行子类化关联。加入按钮的情况如下图:

 

 

在构造中我们看到如下:

     CMainDlg()

         : m_cSliderAudio(IDB_BMP_AUDIO_BK, IDB_BMP_SLIDER_THUM)

          , m_cSliderVideo(IDB_BMP_VIDEO_BK, IDB_BMP_VIDEO_CHAL, IDB_BMP_VIDEO_THUM, IDB_BMP_VIDEO_LEFT, IDB_BMP_VIDEO_RIGHT)

     {

     }

Slider构造函数要求我们必须传入控件内部要用的位图,所以我们一定要以初始化列表的形式进行初始。对于CVideoSliderCtrl它的背景图切分方法可能比较烦索,但这是为了满足在拉伸时不会变形的要求。如果你要实现你自己的样式可以按照例子中方法去切分替换即可。

我们再来看LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)的实现。这里面主要就是控件的初始。

头两个是SLIDER的实现

m_cSliderVideo.SubclassWindow(this->GetDlgItem(IDC_SLIDER_VIDEO));//与界面资源进行子类化关联

         m_cSliderVideo.SetParent(this->m_hWnd);

         m_cSliderVideo.SetPageSize(0);

         m_cSliderVideo.SetIdentiID(this->m_hWnd, IDC_SLIDER_VIDEO);//这里是设置你要接收控件消息的窗口,和控件的分辨的ID(在本例中没有什么用,后面我们讲Slider分段时就会用到)

         m_cSliderVideo.ShowWindow(SW_SHOW);

        

         m_cSliderAudio.SubclassWindow(this->GetDlgItem(IDC_SLIDER_AUDIO));

         m_cSliderAudio.SetParent(this->m_hWnd);

         m_cSliderAudio.SetPageSize(0);

         m_cSliderAudio.SetIdentiID(this->m_hWnd, IDC_SLIDER_AUDIO);

         m_cSliderAudio.ShowWindow(SW_SHOW);

 

         m_cSliderAudio.SetRange( 0, 100 );   //设置音量的范围

     m_cSliderAudio.SetPos( 50 );         //设置音量的默认值

 

之后就是各个按钮的实现,我只看一个播放(4个状态)和一个录像(5个状态)按钮的初始:

     播放按钮4种状态

         DWORD    dwStyle = BMPBTN_AUTOSIZE | BMPBTN_HOVER;//让按钮支持自动大小和HOVER状态

         CBitmap theBitTemp;

         theBitTemp.LoadBitmap(IDB_PLAY); //加载按钮的图像,

         m_cBtnPlay.SetBitmapButtonExtendedStyle(dwStyle);//设置类型

         m_cBtnPlay.m_ImageList.Create(30, 18, ILC_COLOR8|ILC_MASK, 4, 1);//把位图按指定大小个数进行切分

         m_cBtnPlay.m_ImageList.Add(theBitTemp.m_hBitmap, RGB(0, 255, 0));//添加图像列表

         // 下面是设置4种状态对应列表中的位图set normal, pressed, hover, disabled images

         m_cBtnPlay.SetImages(0, 1, 2, 3);

         m_cBtnPlay.SetToolTipText(_T("播放"));//设置HOVER状态时显示的文本

         m_cBtnPlay.SubclassWindow(this->GetDlgItem(IDC_BTN_PLAY));//与窗口资源进行子类化关联

     theBitTemp.DeleteObject();//释放位图资源

 

  录像按钮5种状态,和4种状态按钮的不同在于多一个nImageClicked状态,如下设置

         theBitTemp.LoadBitmap(IDB_BMP_RECORD);

         m_cBtnRec.SetBitmapButtonExtendedStyle(dwStyle);

         m_cBtnRec.m_ImageList.Create(30, 18, ILC_COLOR8|ILC_MASK, 4, 1);

         m_cBtnRec.m_ImageList.Add(theBitTemp.m_hBitmap, RGB(0, 255, 0));

    // 下面是设置4种状态对应列表中的位图set normal, pressed, hover, disabled Clicked images

         m_cBtnRec.SetImages(0, 1, 2, 3, 2);

         m_cBtnRec.SetToolTipText(_T("录像"));

         m_cBtnRec.SubclassWindow(this->GetDlgItem(IDC_BTN_RECORD));

         m_cBtnRec.EnableWindow(false);

     theBitTemp.DeleteObject();

由上面可以看出它们的初始也很简单,搞不明白就复制几个就可以了,HOHO 

 

我再来看MainDlg.CPP中的实现部分;

     整个控制窗口若没有背景那么可能是一种很不美观的事,所以我们要给其加一个背景,那就在

LRESULT CMainDlg::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)中画一个背景,这个是很Easy的事情一看就Know了。

 

我们能看到在窗口资源中各个控件的位置是随意放置,这是因为我们就是摆放了也没有什么用,因为当窗口拉伸时就可能就会变了,所以我们必须在OnSize()里面进行布局设置,只要窗口有变化就会根据我们的要求自动摆放,这里也不再多说了。

 

接下来是对两个Slider的点击和拖动的消息响应

LRESULT CMainDlg::OnMsgSliderPos(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

{

     switch( wParam )//这个参数就是指明了是来自于哪一个SLIDER

     {

     case IDC_SLIDER_VIDEO: //视频SLIDER的操作

         {

              //this->OnVideoSliderPos(lParam);

//lParam指明了当前点击或拖动到的位置,

              break;

         }

     case IDC_SLIDER_AUDIO://音频SLIDER的操作

         {

              //this->OnAudioSliderPos(lParam);

              break;

         }

     default:              /*-- do nothing --*/ break;

     }

     return S_OK;

}

这个消息是手式添加的,是一个自定义消息,你只需在消息映射中加入下面的一行就可以了

MESSAGE_HANDLER(WM_SLIDER_POS_MSG, OnMsgSliderPos)

这样你的SLIDER就可以使用了,是不是很Easy呀!

为了更好的演示,我们再加上OnTimer(),以及开始和停止按钮的响应函数:

 

LRESULT CMainDlg::OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)

{

     hash_map<__int64,__int64> MapArea;  

     if( m_iEndPos == 101 )

         return S_OK;

//在此可以画多个区域,当在网络播放器上用时要显示下载的进度,这里就可根据下载的情况进行下//载的区域填充。如果是播放器进行了SEEK操作,那么就可能会出现多个不连续的数据块,此时可能//根据已有下载数据进行分区域填充,以示当前下载的情况

m_cSliderVideo.SetPos(m_iEndPos);

     //MapArea[ 区域开始 ] = 区域结束位置; 100是指在MapArea中的最大值,这样内部会用这个值去计算所画的位置。也就是说我们外面可以用任何一个范围值,而不必和我们给SLIDER设的范围一致。

     MapArea[ 0 ] = m_iEndPos++;

     m_cSliderVideo.DrawChannelBarBack( MapArea, 100 );//

     return S_OK;

}

 

LRESULT CMainDlg::OnBnClickedBtnPlay(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)

{

     //MessageBox("开始播放了!");

     SetTimer(1,1000,NULL);

     m_cBtnPlay.EnableWindow(FALSE);

     m_cBtnPause.EnableWindow();

     m_cBtnStop.EnableWindow();

     m_cBtnRec.EnableWindow();

 

     return S_OK;

}

LRESULT CMainDlg::OnBnClickedBtnStop(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)

{

     KillTimer(1);

     m_cBtnPlay.EnableWindow(TRUE);

     m_cBtnPause.EnableWindow(FALSE);

     m_cBtnStop.EnableWindow(FALSE);

     m_cBtnRec.EnableWindow(FALSE);

     m_cSliderVideo.Reset();

     m_iEndPos = 0;

 

     return S_OK;

}

这一些好明白吧,很好懂,至此我们可以编译了。就能看到运行结果了,你点一下播放按钮看看有什么现象,点一下录像按钮看看,再点一点停止看看,是不是有点像个播放器的控制窗口了。哈哈

我在此写这点东东,只是为了给初学者一点启发。老手就见笑了。后面我们会再讲一下ATL控件的编写,最终我们会做出一个播放器的控件来。这是要一步步来的了。

猜你喜欢

转载自blog.csdn.net/wanghaisheng/article/details/4281221