100个vc小项目开发:二、一步一点设计音乐播放器[源码解读]
文章作者:July
软件来源:开源
==================
1.有不正之处,恳请指正。
2.本文贴出的是关键实现代码部分,只做粗略展示。
3.转载,请注明出处。谢谢。
---------
一、先画对话框,IDD_MYPLAYER_DIALOG,界面如图:
二、然后,对话框相关处理完成后,在CMyPlayerApp里头,编写如下代码:
设置几个全局变量:
CMyPlayerApp theApp;
CStringArray m_strPlayListArray;
int m_nPlayOrder[2000];
int m_nNowPlaying;
UINT m_nPlayMode;
HWND hAudio;
FILELIST fileList[10];
int nCurrentList;
CString strCurrentDir;
而后,编写InitInstance()的代码:
BOOL CMyPlayerApp::InitInstance()
{
AfxEnableControlContainer();
m_hMutex=CreateMutex(NULL,FALSE,"星空物语");
if (GetLastError()==ERROR_ALREADY_EXISTS )
{
HWND hwnd=FindWindow(NULL,"星空物语");
if(hwnd!=NULL);{
if(IsWindowVisible(hwnd))
return FALSE;
SendMessage(hwnd,MYWM_NOTIFYICON,NULL,(LPARAM)WM_LBUTTONDOWN);
}
return FALSE ;
}
hAudio=NULL;
TCHAR szCurDir[MAX_PATH];
GetCurrentDirectory(MAX_PATH,szCurDir);
strCurrentDir=szCurDir;
m_nPlayMode=MODE_RAND;
CMyPlayerDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
return FALSE;
}
三、// MyPlayerDlg.h : header file 头文件里头:
class CMyPlayerDlg : public CDialog
{
// Construction
public:
CString m_strLyricPath;
void DeleteNotifyIcon();
void CreateNotifyIcon();
BOOL fPlay;
void DestroyMenuDlg();
CMenuDlg* m_pMenuDlg;
int m_nVolume;
void WriteConfig();
BOOL ReadConfig();
BOOL IsFileExist(CString strFileName);
BOOL GetFileList(CString strLine,int nIndex);
void InitFileList();
int nRollTextCounter;
void CirculatePlay();
void DropFilesInPlayList(HDROP hDrop);
void DropFilesInMain(HDROP hDrop);
BOOL IsSupportFile(CString strFileName);
void GetDropFiles(HDROP hDrop);
void FormatTitle(CString strFile);
BOOL fPlaying;
UINT m_nTime;
void Play(int nIndex);
CString GetFileTitle(CString strFileName);
BOOL IsLyricDlgAttach();
BOOL IsPlayListAttach();
void MoveLyricWindow();
void MovePlayListWindow();
BOOL fInited;
void CreateLyric();
CLyricDlg* m_pLyricDlg;
void CreatePlayList();
CPlayListDlg* m_pPlayListDlg;
void InitSize();
void ExitPlayer();
void MoveSlide();
void InitText();
void CountTime();
CString strTime;
void InitRect();
CRect rectTitle;
CRect rectTime;
void DrawTime(CDC*pDC);
void RollText();
CString strOutText;
CString strTitle;
void DrawText(CDC*pDC);
void DrawMainPicture(CDC*pDC);
void InitButtons();
CMyPlayerDlg(CWnd* pParent = NULL);// standard constructor
// Dialog Data
//{{AFX_DATA(CMyPlayerDlg)
enum { IDD = IDD_MYPLAYER_DIALOG };
CSkinButtonm_btnShowMenu;
CSkinButtonm_btnLyric;
CVolumeButtonm_volume;
CSlideButtonm_slide;
CTransparentStaticm_stcMode;
CTransparentStaticm_stcPlay;
CSkinButtonm_btnStop;
CSkinButtonm_btnPrev;
CSkinButtonm_btnPLShow;
CSkinButtonm_btnPlay;
CSkinButtonm_btnOpen;
CSkinButtonm_btnNext;
CSkinButtonm_btnMin;
CSkinButtonm_btnHide;
CSkinButtonm_btnExit;
CButtonm_buttonOK;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyPlayerDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV support
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CMyPlayerDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnBtnExit();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnStaticMode();
afx_msg void OnStaticPlay();
afx_msg void OnBtnVolume();
afx_msg void OnBtnSlide();
virtual void OnCancel();
virtual void OnOK();
afx_msg void OnBtnPlaylistShow();
afx_msg void OnMove(int x, int y);
afx_msg void OnBtnLyric();
afx_msg void OnBtnOpen();
afx_msg void OnBtnNext();
afx_msg void OnBtnPlay();
afx_msg void OnBtnPrev();
afx_msg void OnBtnStop();
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnBtnShowmenu();
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnMenuNext();
afx_msg void OnMenuOpen();
afx_msg void OnMenuPlay();
afx_msg void OnMenuPrev();
afx_msg void OnMenuRand();
afx_msg void OnMenuSeq();
afx_msg void OnMenuSingle();
afx_msg void OnMenuStop();
afx_msg void OnMenuVoldown();
afx_msg void OnMenuPause();
afx_msg void OnMenuVolslc();
afx_msg void OnMenuVolup();
afx_msg void OnAboutStar();
afx_msg void OnNotifyIcon(WPARAM wParam,LPARAM lParam);
afx_msg void OnBtnHide();
afx_msg void OnBtnMin();
afx_msg void OnSetLyricpath();
afx_msg void OnMenuOpenLyricpath();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
四、对应的// MyPlayerDlg.cpp : implementation file 实现文件里头:
void CMyPlayerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyPlayerDlg)
DDX_Control(pDX, IDC_BTN_SHOWMENU, m_btnShowMenu);
DDX_Control(pDX, IDC_BTN_LYRIC, m_btnLyric);
DDX_Control(pDX, IDC_BTN_VOLUME, m_volume);
DDX_Control(pDX, IDC_BTN_SLIDE, m_slide);
DDX_Control(pDX, IDC_STATIC_MODE, m_stcMode);
DDX_Control(pDX, IDC_STATIC_PLAY, m_stcPlay);
DDX_Control(pDX, IDC_BTN_STOP, m_btnStop);
DDX_Control(pDX, IDC_BTN_PREV, m_btnPrev);
DDX_Control(pDX, IDC_BTN_PLAYLIST_SHOW, m_btnPLShow);
DDX_Control(pDX, IDC_BTN_PLAY, m_btnPlay);
DDX_Control(pDX, IDC_BTN_OPEN, m_btnOpen);
DDX_Control(pDX, IDC_BTN_NEXT, m_btnNext);
DDX_Control(pDX, IDC_BTN_MIN, m_btnMin);
DDX_Control(pDX, IDC_BTN_HIDE, m_btnHide);
DDX_Control(pDX, IDC_BTN_EXIT, m_btnExit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyPlayerDlg, CDialog)
//{{AFX_MSG_MAP(CMyPlayerDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
ON_BN_CLICKED(IDC_BTN_EXIT, OnBtnExit)
ON_WM_CREATE()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_STATIC_MODE, OnStaticMode)
ON_BN_CLICKED(IDC_STATIC_PLAY, OnStaticPlay)
ON_BN_CLICKED(IDC_BTN_VOLUME, OnBtnVolume)
ON_BN_CLICKED(IDC_BTN_SLIDE, OnBtnSlide)
ON_BN_CLICKED(IDC_BTN_PLAYLIST_SHOW, OnBtnPlaylistShow)
ON_WM_MOVE()
ON_BN_CLICKED(IDC_BTN_LYRIC, OnBtnLyric)
ON_BN_CLICKED(IDC_BTN_OPEN, OnBtnOpen)
ON_BN_CLICKED(IDC_BTN_NEXT, OnBtnNext)
ON_BN_CLICKED(IDC_BTN_PLAY, OnBtnPlay)
ON_BN_CLICKED(IDC_BTN_PREV, OnBtnPrev)
ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)
ON_WM_RBUTTONDOWN()
ON_BN_CLICKED(IDC_BTN_SHOWMENU, OnBtnShowmenu)
ON_WM_KILLFOCUS()
ON_COMMAND(IDC_MENU_NEXT, OnMenuNext)
ON_COMMAND(IDC_MENU_OPEN, OnMenuOpen)
ON_COMMAND(IDC_MENU_PLAY, OnMenuPlay)
ON_COMMAND(IDC_MENU_PREV, OnMenuPrev)
ON_COMMAND(IDC_MENU_RAND, OnMenuRand)
ON_COMMAND(IDC_MENU_SEQ, OnMenuSeq)
ON_COMMAND(IDC_MENU_SINGLE, OnMenuSingle)
ON_COMMAND(IDC_MENU_STOP, OnMenuStop)
ON_COMMAND(IDC_MENU_VOLDOWN, OnMenuVoldown)
ON_COMMAND(IDC_MENU_PAUSE, OnMenuPause)
ON_COMMAND(IDC_MENU_VOLSLC, OnMenuVolslc)
ON_COMMAND(IDC_MENU_VOLUP, OnMenuVolup)
ON_COMMAND(IDC_ABOUT_STAR, OnAboutStar)
ON_MESSAGE(MYWM_NOTIFYICON,OnNotifyIcon)
ON_BN_CLICKED(IDC_BTN_HIDE, OnBtnHide)
ON_BN_CLICKED(IDC_BTN_MIN, OnBtnMin)
ON_COMMAND(IDC_SET_LYRICPATH, OnSetLyricpath)
ON_COMMAND(IDC_MENU_OPEN_LYRICPATH, OnMenuOpenLyricpath)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
五、以下是MyPlayerDlg对话框的初始化代码:
BOOL CMyPlayerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);// Set big icon
SetIcon(m_hIcon, FALSE);// Set small icon
// TODO: Add extra initialization here
InitButtons();
InitRect();
InitText();
InitSize();
CreateLyric();
CreatePlayList();
m_pMenuDlg=NULL;
InitFileList();
strTitle=" 星空物语 ";
strTime="00:00";
m_nTime=0;
fInited=TRUE;
fPlaying=FALSE;
fPlay=TRUE;
nRollTextCounter=0;
SetWindowText("星空物语");
m_strLyricPath="";
if(ReadConfig()){
m_pPlayListDlg->OpenList(nCurrentList);
m_volume.SetPos(m_nVolume);
if(m_nPlayMode==MODE_SEQ)
OnStaticMode();
if(m_nPlayMode==MODE_SINGLE){
OnStaticMode();
OnStaticMode();
}
}else{
m_nPlayMode=MODE_RAND;
nCurrentList=0;
m_pPlayListDlg->OpenList(nCurrentList);
m_nVolume=8;
m_volume.SetPos(m_nVolume);
}
CreateNotifyIcon();
SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
m_pLyricDlg->SetPlayListWnd(m_pPlayListDlg);
return TRUE; // return TRUE unless you set the focus to a control
}
//字幕的画法
void CMyPlayerDlg::DrawText(CDC *pDC)
{
pDC->SetBkMode(TRANSPARENT);
CFont font,*pOldFont;
LOGFONT logFont;
pDC->GetCurrentFont()->GetLogFont(&logFont);
logFont.lfCharSet=134;
logFont.lfWidth=6;
logFont.lfWeight=10;
lstrcpy(logFont.lfFaceName,"华文彩云");
font.CreateFontIndirect(&logFont);
pOldFont=pDC->SelectObject(&font);
pDC->SetTextColor(RGB(255,255,0));
pDC->TextOut(21,48,"Love You Forever");
font.DeleteObject();
logFont.lfWidth=6;
logFont.lfHeight=12;
logFont.lfWeight=0;
lstrcpy(logFont.lfFaceName,"宋体");
font.CreateFontIndirect(&logFont);
pDC->SelectObject(&font);
pDC->SetTextColor(RGB(0,255,0));
pDC->TextOut(22,35,strOutText);
pDC->TextOut(22,66,"状态:");
pDC->TextOut(75,90,"☆For My Lover☆");
pDC->SetTextColor(RGB(0,150,0));
pDC->TextOut(60,103,"★星空物语 MADE BY July★");
font.DeleteObject();
pDC->SelectObject(pOldFont);
}
六、计时器部分,OnTimer、RollText、CountTime、MoveSlide等4个函数:
int CMyPlayerDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetTimer(1,1000,NULL);
fInited=FALSE;
DragAcceptFiles(TRUE);
return 0;
}
void CMyPlayerDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
RollText();
if(fPlaying){
CountTime();
MoveSlide();
CirculatePlay();
}
CDialog::OnTimer(nIDEvent);
}
void CMyPlayerDlg::RollText()
{
TCHAR ch;
strOutText="";
for(UINT i=0;i<16;){
ch=strTitle.GetAt(nRollTextCounter+i);
strOutText+=ch;
i++;
}
nRollTextCounter+=2;
if(nRollTextCounter>=strTitle.GetLength()-16)
nRollTextCounter=0;
InvalidateRect(&rectTitle,TRUE);
}
//计时
void CMyPlayerDlg::CountTime()
{
m_nTime=MCIWndGetPosition(hAudio)/MCIWndGetSpeed(hAudio);
int nMinute=m_nTime/60;
int nSecond=m_nTime%60;
if(nMinute<10){
if(nSecond<10)
strTime.Format("0%d:0%d",nMinute,nSecond);
else
strTime.Format("0%d:%d",nMinute,nSecond);
}else{
if(nSecond<10)
strTime.Format("%d:0%d",nMinute,nSecond);
else
strTime.Format("%d:%d",nMinute,nSecond);
}
InvalidateRect(&rectTime,TRUE);
}
//滚动条设置
void CMyPlayerDlg::MoveSlide()
{
if(hAudio!=NULL)
m_slide.SetSlidePos(MCIWndGetPosition(hAudio));
}
七、关键的播放代码,Play
void CMyPlayerDlg::Play(int nIndex)
{
if(nIndex>=m_strPlayListArray.GetSize())
return;
CString strFileName=m_strPlayListArray.GetAt(nIndex);
if(!IsFileExist(strFileName)){
m_pPlayListDlg->m_playlist.DeleteString(nIndex);
m_strPlayListArray.RemoveAt(nIndex,1);
return;
}
if(hAudio!=NULL){
MCIWndDestroy(hAudio);
hAudio=NULL;
}
try{
hAudio=MCIWndCreate(GetSafeHwnd(),AfxGetInstanceHandle(),
WS_CHILD|MCIWNDF_NOMENU,strFileName);
}catch(...)
{
if(nIndex>=0){
m_pPlayListDlg->m_playlist.DeleteString(nIndex);
m_strPlayListArray.RemoveAt(nIndex,1);
}
return;
}
if(hAudio!=NULL){
MCIWndPlay(hAudio);
if(!m_strLyricPath.IsEmpty()){
if(!m_pLyricDlg->OpenLyric(m_strLyricPath,nIndex))
m_pLyricDlg->OpenLyric(nIndex);
}else
m_pLyricDlg->OpenLyric(nIndex);
strTitle=GetFileTitle(strFileName);
FormatTitle(strTitle);
nRollTextCounter=0;
m_nTime=0;
fPlaying=TRUE;
m_slide.SetRange(0,MCIWndGetLength(hAudio));
m_slide.SetSlidePos(0);
m_pPlayListDlg->m_playlist.SetCurSel(nIndex);
int nSetVol=63*m_nVolume;
if(nSetVol>1000)
nSetVol=1000;
MCIWndSetVolume(hAudio,nSetVol);
}
}
void CMyPlayerDlg::OnBtnPlay()
{
// TODO: Add your control notification handler code here
int n=m_pPlayListDlg->m_playlist.GetCurSel();
if(n<0){
if(m_strPlayListArray.GetSize()>0){
Play(m_nPlayOrder[0]);
m_nNowPlaying=0;
}
return;
}
Play(n);
if(m_nPlayMode==MODE_RAND){
for(int i=0;i<m_strPlayListArray.GetSize();i++){
if(m_nPlayOrder[i]==n){
m_nNowPlaying=i;
break;
}
}
}else{
m_nNowPlaying=n;
}
}
八、打开文件
void CMyPlayerDlg::OnBtnOpen()
{
// TODO: Add your control notification handler code here
CString strFilter="所有支持文件(*.mp3,*.wav,*.wma)|*.mp3;*.wav;*.wma||";
CFileDialog fdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,strFilter);
if(fdlg.DoModal()==IDOK){
CString strFileName=fdlg.GetPathName();
m_strPlayListArray.RemoveAll();
m_strPlayListArray.Add(strFileName);
CString strList,strFile;
strFile=GetFileTitle(strFileName);
strList.Format("01 %s",strFile);
m_pPlayListDlg->m_playlist.ResetContent();
m_pPlayListDlg->m_playlist.AddString(strList);
Play(0);
}
}
九、获取文件名
CString CMyPlayerDlg::GetFileTitle(CString strFileName)
{
CString str;
int nPos=-1;
int nOldPos=-1;
while((nPos=strFileName.Find("\\",nPos+1))>0)
nOldPos=nPos;
str=strFileName.Right(strFileName.GetLength()-nOldPos-1);
strFileName=str.Left(str.GetLength()-4);
return strFileName;
}
十、停止播放
void CMyPlayerDlg::OnBtnStop()
{
// TODO: Add your control notification handler code here
if(hAudio!=NULL){
MCIWndStop(hAudio);
m_nTime=0;
fPlaying=FALSE;
strTime="00:00";
m_slide.SetSlidePos(0);
InvalidateRect(&rectTime,TRUE);
}
}
//日后做详细解剖。待续。
July、二零一零年十二月二十四日。祝各位,平安夜快乐。:D。