100个vc小项目开发:二、一步一点设计音乐播放器 [I]

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 };
 CSkinButton m_btnShowMenu;
 CSkinButton m_btnLyric;
 CVolumeButton m_volume;
 CSlideButton m_slide;
 CTransparentStatic m_stcMode;
 CTransparentStatic m_stcPlay;
 CSkinButton m_btnStop;
 CSkinButton m_btnPrev;
 CSkinButton m_btnPLShow;
 CSkinButton m_btnPlay;
 CSkinButton m_btnOpen;
 CSkinButton m_btnNext;
 CSkinButton m_btnMin;
 CSkinButton m_btnHide;
 CSkinButton m_btnExit;
 CButton m_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。

posted on 2010-12-24 00:27  July_  阅读(1771)  评论(0)    收藏  举报