最近刚刚看完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(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