zoukankan      html  css  js  c++  java
  • MFC制作的简单音乐播放器总结

    最近刚刚看完MFC中各种控件的重绘,试着模仿QQ音乐做了个界面,不过没有播放音乐的功能。最近为了C++大作业,把功能加了上去,不过界面是临时重写的,十分粗糙,很多图片没有处理,直接放上去了,不过对于我们新手来说,一步步来,过一段时间一定能再填完整的。

    好了,直接总结。

    核心:播放代码(直接使用Bass库,不过只是小小的用了下,不知道的可以到http://www.un4seen.com/files/bass24.zip去下载,很强大的库)

    BOOL CTestBassDlg::OnInitDialog()
    {
            //初始化代码
    	BASS_Init(-1,44100,0,this->m_hWnd,NULL); 
    	m_volum.SetRange(0,100);
    	m_volum.SetPos(20);
    	//设置音量
    	float pp=10/100.0f; 
    	BASS_SetVolume(pp);
    	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
    }
    void CTestBassDlg::OnBnClickedButton1()
    {
    	//打开文件
        m_play=BASS_StreamCreateFile(FALSE, "E:\\歌曲\\:北极雪 ....mp3",0,0,BASS_SAMPLE_MONO);
    	//开始播放
    	BASS_ChannelPlay(m_play,FALSE);
    }
    void CTestBassDlg::OnBnClickedButton2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	CFileDialog read(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR,
    		_T("媒体文件(*.avi,*.mp3,*.wma)|*.avi;*.mp3;*.wma||"));
    	POSITION pos=read.GetStartPosition();
    	if (IDOK==read.DoModal())
    	{ 
    		int count=m_list.GetCount();
    	  while(pos!=NULL)
           {   
    		   CString path;
    		   path=read.GetNextPathName(pos);
    		   m_list.AddString(path);
    		   count++;
    	   }
    	}
    }
    void CTestBassDlg::OnLbnDblclkList1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	int nIndex=m_list.GetCurSel();
    	CString path;
    	if (nIndex!=-1)
    		m_list.GetText(nIndex,path); 
    	//释放 
    	if (m_play!=NULL) BASS_StreamFree(m_play);
    	m_play=BASS_StreamCreateFile(FALSE, path,0,0,BASS_SAMPLE_MONO);
    	initpro();
    	//播放
    	BASS_ChannelPlay(m_play,FALSE);
    	//设置回调函数
    	BASS_ChannelSetSync(m_play, BASS_SYNC_END, (QWORD)MAKELONG(10,0), &CTestBassDlg::MySyncProc, 0);
    
    }
    void CTestBassDlg::OnBnClickedButton3()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	//停止
    	 BASS_ChannelStop(m_play);
    }
    void CTestBassDlg::OnBnClickedButton4()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	//播放
    	if (m_play!=NULL) BASS_ChannelPlay(m_play,FALSE);
    }
    void CTestBassDlg::OnBnClickedButton5()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	//暂停
    	BASS_ChannelPause(m_play);
    }
    
    void CTestBassDlg::OnTRBNThumbPosChangingSlider1(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	NMTRBTHUMBPOSCHANGING *pNMTPC = reinterpret_cast<NMTRBTHUMBPOSCHANGING *>(pNMHDR);
    	// TODO: 在此添加控件通知处理程序代码
    	int pos=m_volum.GetPos();
    	BASS_SetVolume(pos/100.0f);
    	*pResult = 0;
    }
    void CTestBassDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	int pos=m_volum.GetPos();
    	BASS_SetVolume(pos/100.0f);
    	pos=m_progress.GetPos();
    
    	//获取播放的位置
    	QWORD post=BASS_ChannelSeconds2Bytes(m_play,pos);
    	//重新设置
    	BASS_ChannelSetPosition(m_play,post,BASS_POS_BYTE);
    	
    	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    
    void CTestBassDlg::initpro()
    {
    	double time=BASS_ChannelBytes2Seconds(m_play, BASS_ChannelGetLength(m_play, BASS_POS_BYTE));
    //这里获取歌曲的相关信息 具体的结构可以去看帮助文档的内容 TAG_ID3 *pTag = (TAG_ID3 *)BASS_ChannelGetTags(m_play,BASS_TAG_ID3); CString show; show.Format(("%lf %s %s %s"),time,pTag->title,pTag->artist,pTag->album); GetDlgItem(IDC_SHOW)->SetWindowText(show); m_progress.SetRange(0,(int)time); m_progress.SetPos(0); KillTimer(1); SetTimer(1,1000,NULL); } void CTestBassDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //获取时间 以秒计算 double time=BASS_ChannelBytes2Seconds(m_play, BASS_ChannelGetPosition(m_play, BASS_POS_BYTE)); m_progress.SetPos((int)time); CDialogEx::OnTimer(nIDEvent); }
    //回调函数 可以用来设置 播放的模式 void CALLBACK CTestBassDlg::MySyncProc(HSYNC handle, DWORD channel, DWORD data, void *user) { DWORD dwActive = BASS_ChannelIsActive(channel); if( dwActive == BASS_ACTIVE_STOPPED ) { AfxMessageBox("111"); } }

     上面是Bass的使用 详细的大家可以直接去http://www.cnblogs.com/del/archive/2008/08/17/1269958.html 虽然是VB的方法,但是看函数用法就行了

    2.界面的绘制

    先看下效果图(图怎么传不上去啊,算了)

    很垃圾的界面,我只说下大概的思路(刚学的新手看看,应该会有帮助吧)

    1.滚动条(重绘都是在OnPaint中,其实麻烦的是轨道区,滑块的坐标计算)

    我只给出部分代码(新手写的,有错误请直接留言)

    CPaintDC dc(this); 
        CRect rc;
        GetClientRect(&rc);
    	CRect bkrect;
    	bkrect.SetRect(rc.left,rc.top,rc.right,rc.bottom);
    	CPoint tmp(0,0);
    	if (!m_back.IsNull())
    		m_back.StretchBlt(dc.m_hDC,bkrect,SRCCOPY);
    	if (!m_tunner.IsNull())
    		  m_tunner.BitBlt(dc.m_hDC,m_ctunner,tmp,SRCCOPY);
    	if (isdown)
    		m_dowbutton.StretchBlt(dc.m_hDC,m_cbutton,SRCCOPY);
    	else
    		if (ishover)
             m_hovbutton.StretchBlt(dc.m_hDC,m_cbutton,SRCCOPY);
    		else
    		 m_norbutton.StretchBlt(dc.m_hDC,m_cbutton,SRCCOPY);
    	
    

     说白了,就是计算坐标,然后贴图片,整个的代码下面给出,主要用这个实现进度变化,音量设置,以及一个小小的功能(设置透明,不过我不会裁剪区,做不到像QQ音乐那样)

    2.CButton的绘制(这个就简单了,就是设置自绘属性,所有的变量在DrawItem这个虚函数中都有)

    CDC *pdc=CDC::FromHandle(lpDrawItemStruct->hDC);
    	SetStretchBltMode(pdc->m_hDC,STRETCH_HALFTONE);
    	if (!m_pic.IsNull())
    	{   
    	    CRect rc=lpDrawItemStruct->rcItem;
    		BOOL issel=(lpDrawItemStruct->itemState&ODS_SELECTED?TRUE:FALSE);
    		int nIndex=0;
    		if (issel) nIndex=2;
    		else
    			if (ishover) nIndex=1;
    		CRect picrect;
    		picrect.SetRect(nIndex*GetWidth(),0,(nIndex+1)*GetWidth(),GetHeight());
    		//设置去背景
    		m_pic.TransDrawImage(pdc,rc.left,rc.top,rc.right,rc.bottom,picrect.left,picrect.top,RGB(255,255,255));
    	}
    

     至于鼠标移进,离开的图片变换就是几个BOOL变量的判断,请看具体代码。

    3CListBox的重绘(这个重绘不怎么成功,我想实现透明,但是一直出错,没办法只能先写个简单的了)

    if (GetCount()<=0) return;
    	CRect rcItem=lpDrawItemStruct->rcItem;
    	CDC * pDCControl=CDC::FromHandle(lpDrawItemStruct->hDC);
     	CDC BufferDC;
     	CBitmap ImageBuffer;
     	BufferDC.CreateCompatibleDC(pDCControl);
     	ImageBuffer.CreateCompatibleBitmap(pDCControl,rcItem.Width(),rcItem.Height());
     	BufferDC.SelectObject(&ImageBuffer);
    	CString strString;
    	GetText(lpDrawItemStruct->itemID,strString);
    	CRect rcString;
    	rcString.SetRect(4,0,rcItem.Width()-8,rcItem.Height());
    	COLORREF crTextColor=RGB(84,84,84);
    	BufferDC.FillSolidRect(0,0,rcItem.Width(),rcItem.Height(),RGB(251,243,235));
    	BOOL isselect=(lpDrawItemStruct->itemState&ODS_SELECTED?TRUE:FALSE);
    	CRect tmprect(0,0,rcItem.Width(),rcItem.Height());
    	if (isselect)
    		{  
    			m_sel.StretchBlt(BufferDC.m_hDC,tmprect,SRCCOPY);
    	     }
    	else
    	 if ( hovenindex==lpDrawItemStruct->itemID )
    	 { 
    		if ( m_sel!= NULL && !m_sel.IsNull())
    		{  
    			m_sel.StretchBlt(BufferDC.m_hDC,tmprect,SRCCOPY);
    		}
    	}
        BufferDC.SetBkMode(TRANSPARENT);
    	BufferDC.SetTextColor(crTextColor);
    	BufferDC.DrawText(strString,&rcString,DT_VCENTER|DT_SINGLELINE);
    	pDCControl->BitBlt(rcItem.left,rcItem.top,rcItem.Width(),rcItem.Height(),&BufferDC,0,0,SRCCOPY);
     	BufferDC.DeleteDC();
     	ImageBuffer.DeleteObject();
    

    上面使用双缓冲来是为了减少闪屏(让我头痛啊,有时候还是会闪屏,看来我还是要再学学这方面啊)

    4抛开重绘,主界面就是播放的代码。大家可以直接去看代码

    上面可能写的简单了,不过大家可以直接去下代码,但是写的比较急(给别人交作业),代码重复的很多,不过我会加上注释,希望能对新手有所帮助,当然有错误或者不懂得的可

    以给我留言,大家一起讨论,解决这些问题,一起加油!!!

    http://download.csdn.net/detail/zhoupeng39/6688075

  • 相关阅读:
    2.java基础语法(上)
    1.java概述
    Qt layout透明的问题
    Duilib 关于ChildLayout崩溃的问题
    关于注册表使用的几个问题
    win32接口获取ping值
    Web开发中遇到的问题
    DuiLib 窗口透明方法
    通过进程名杀死进程的方法--WIN32
    关于在Qt的MainWindow窗口中添加Layout的问题
  • 原文地址:https://www.cnblogs.com/fightfuture/p/3466678.html
Copyright © 2011-2022 走看看