更新时间:2017-03-18 21:11:12浏览次数:1+次
本节目录:
1. 前几节内容回顾与总结
2. 添加进度及音量跳转功能
3. 添加音乐列表清空、保存及还原功能
4. 完整功能代码实现
5. 演示
1. 前几节内容回顾与总结
从第一节到现在,功能在不断完善,代码在不断地增加,同时难免会出现不同的BUG.
第一节的API函数是支撑起整个播放器的核心:MCIERROR mciSendString(LPCTSTR lpszCommand, LPTSTR lpszReturnString, UINT cchReturn, HANDLE hwndCallback )。在后面的内容中,有疑问或者记不清的可翻阅到第一节去查看。
(第一节链接:MFC学习实践之简易音乐播放器(一)主界面演示及基本原理说明)
第二节开始,重写音乐播放器,从一个最简单的,只有播放停止功能开始,逐步完善添加!
(第二节链接:MFC学习实践之简易音乐播放器(二)完整主界面控件说明及编写最简音乐播放器)
第三节,功能比上一节稍有增加,多个音乐文件列表,上一曲及下一曲等功能,代码也进行了一定的重构与封装,方便后面功能扩展!很多时候,功能越多函数封装就越重要,对于经常用到的子功能,写入不同的函数中,可以省去很多时间及重复性的代码!
(第三节链接:MFC学习实践之简易音乐播放器(三)添加音乐列表文件及功能菜单选项)
现在,第四节开始了,在本节中一个简单的音乐播放器大致成型!音乐文件列表,自动备份及还原,上一曲,下一曲,进度、音量设置调整,列表添加与情况!(全盘音乐文件扫描功能待添加 及播放模式设置待添加)
2. 添加进度及音量跳转功能
利用VS2017的即拖即放功能,对上一节的界面重新布局,增加2个滑块控件,第一个控制进度条,第二个控制音量!本节完整界面控件设计图如下:
进度条控件ID: IDC_SLIDERSTEP
音量控件ID: IDC_SLIDERVOLUME
添加对应的消息相应函数:
滑块控件常用成员函数:
① GetRange,SetRange
用于查询和设置滑动条的取值范围,默认为0~100。函数定义形式如下:
void GetRange(int &nMin,int &nMax) const; //查询滑块取值范围
void SetRange(int nMin,int nMax,BOOL bRedrGETaw=FALSE);//设置滑块取值范围
② GetPos,SetPos
用于查询和设置滑动条的当前值。函数定义形式如下:
int GetPos() const;//获取滑动条当前值
int SetPos(int nPos);//设置滑块当前值
③ SetTicFreq函数
用于设置滑动条刻度的频度。默认为一个单位一个函数。函数定义形式如下:
void SetTicFreq(int nFreq);
进度跳转响应函数:
void CMusicPlayerDlg::OnNMCustomdrawSliderstep(NMHDR *pNMHDR, LRESULT *pResult) //进度条滑块响应函数
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
if (m_PlayStatus == 2) //判断是否
{
int pos = m_ctrStep.GetPos();
if (abs(pos - m_nowPlayStep) > 2) //误差判定 若变化值大于2 视为人工改变进度条
{
m_nowPlayStep = pos;
TCHAR cmd[MAX_PATH] = L"play";
TCHAR cmdParam[MAX_PATH] = L"";
wsprintf(cmdParam, L"%d", m_nowPlayStep * 1000);
StatusMessageDistribution(cmd, cmdParam, MAX_PATH);//自定义音乐控制消息分配函数
}
}
*pResult = 0;
}
音量设置响应函数:
void CMusicPlayerDlg::OnNMCustomdrawSlidervolume(NMHDR *pNMHDR, LRESULT *pResult) //声音滑块响应函数
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = m_ctrVolume.GetPos();
if (m_PlayStatus == 2) //判断是否出于播放状态
{
if (abs(pos - m_nowPlayVolume) > 2) //误差判定 若变化值大于2 视为人工改变进度条
{
m_nowPlayVolume = pos;
SetVolume(); //自定义的音量设置函数
}
}
else
{
m_nowPlayVolume = pos;
}
m_strVolume.Format(L"%d/100", m_nowPlayVolume);
UpdateData(FALSE);
*pResult = 0;
}
3.添加音乐列表清空、保存及还原功能
⑴ 音乐文件列表清空
在文件主菜单下添加子菜单功能:
清空列表菜单ID设置为:ID_MENUCLEAR
如上图,添加事件处理处理程序代码:
void CMusicPlayerDlg::OnMenuclear() //情况列表
{
// TODO: 在此添加命令处理程序代码
if (m_PlayStatus>0)
StatusMessageDistribution(_T("close"));
m_ctrMusicList.DeleteAllItems();
int count = m_MusicPathList.GetCount();
for (int i = 0; i < count; i++)
{
m_MusicPathList.RemoveTail();
}
}
⑵ 音乐文件列表备份
遍历列表控件中保存的数据,再程序关闭之时自动存储至本地磁盘文件中!
代码为:
nt CMusicPlayerDlg::SaveListToFile() //音乐文件列表保存
{
char* old_locale = _strdup(setlocale(LC_CTYPE, NULL));
setlocale(LC_CTYPE, "chs");//设定为中文环境,解决UNICODE环境下中文字符储存问题
CStdioFile file;
BOOL r=file.Open(_T("musiclist.dat"), CStdioFile::modeCreate | CStdioFile::modeWrite);
if (r == FALSE)
{
MessageBox(L"文件写入失败!");
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
return -1;
}
TCHAR wtBuffer[1024]=L"";
int count = m_ctrMusicList.GetItemCount();
for (int i = 0; i < count; i++)
{
//CString name=m_ctrMusicList.GetItemText(i, 0);
CString *path =(CString*)m_ctrMusicList.GetItemData(i);
ASSERT(path != NULL);
wsprintf(wtBuffer, L"%s\n", path->GetString());
//MessageBox(wtBuffer);
file.WriteString(wtBuffer);
}
file.Close();
//文件操作结束后,还原
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
return 0;
}
⑶ 音乐文件列表还原
读取备份的文件,添加至文件列表中。
代码为:
int CMusicPlayerDlg::ReadFileToList() //音乐文件列表还原
{
//设定为中文环境,解决UNICODE环境下中文字符储存问题
char* old_locale = _strdup(setlocale(LC_CTYPE, NULL));
setlocale(LC_CTYPE, "chs");
CStdioFile file;
BOOL r = file.Open(_T("musiclist.dat"), CStdioFile::modeRead);
if (r == FALSE)
{
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
MessageBox(L"文件读取失败!");
return -1;
}
TCHAR rdBuffer[1024] = L"";
TCHAR name[MAX_PATH] = L"";
TCHAR *path = NULL;
while (file.ReadString(rdBuffer,1024))
{
int size = lstrlen(rdBuffer);
rdBuffer[size - 1] = '\0';
AddMusicToList(rdBuffer);
}
file.Close();
//文件操作结束后,还原
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
return 0;
}
对于文件列表备份与还原功能,这里有一个缺陷,无法保护储存的数据。一个简单的解决方法是:可在储存时采用异或进行加密,读取时异或进行解密,达到保护数据的目的!这里可自行添加!
4. 完整功能代码实现
(1)MusicPlayerDlg.h : 头文件
// MusicPlayerDlg.h : 头文件
//
#pragma once
#include "afxwin.h"
#include "afxcmn.h"
// CMusicPlayerDlg 对话框
class CMusicPlayerDlg : public CDialogEx
{
// 构造
public:
CMusicPlayerDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MUSICPLAYER_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CString m_strPath;
CString m_strNowPlayPath;
afx_msg void OnClickedButtonsel();
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedCancel();
private:
int m_PlayStatus;// 音乐播放状态 0 初始状态 1 音乐文件打开或停止状态 2 音乐文件播放状态 3 音乐文件暂停状态
int m_nowPlayIndex=-1;
long m_nowPlayStep = 0;
int m_nowPlayLength = 0;
int m_nowPlayVolume = 50;
CList<CString, CString&> m_MusicPathList;
int SaveListToFile();
int ReadFileToList();
int SetVolume();
int GetInfo();
void AddMusicToList(CString FilePath);
int StatusMessageDistribution(CString cmd, TCHAR* cmdParam = NULL, int ParamLen = 0);
public:
CButton m_btnPlay;
CString m_strVolume;
CString m_strStep;
CSliderCtrl m_ctrStep;
CSliderCtrl m_ctrVolume;
CListCtrl m_ctrMusicList;
afx_msg void OnDestroy();
afx_msg void OnClickedIdplay();
afx_msg void OnClickedIdstop();
afx_msg void OnMenuaddfile();
afx_msg void OnAppAbout();
afx_msg void OnMenuexit();
afx_msg void OnLvnItemchangedListmusic(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnDblclkListmusic(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnRclickListmusic(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnBnClickedButtonnext();
afx_msg void OnBnClickedButtonlast();
afx_msg void OnMenuclear();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnNMCustomdrawSliderstep(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnNMCustomdrawSlidervolume(NMHDR *pNMHDR, LRESULT *pResult);
};
(2)MusicPlayerDlg.cpp : 实现文件
// MusicPlayerDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "MusicPlayer.h"
#include "MusicPlayerDlg.h"
#include "afxdialogex.h"
#include <mmsystem.h>
#include <locale.h>
#pragma comment(lib,"winmm.lib")
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define TIMERPLAYSTEP 1
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMusicPlayerDlg 对话框
CMusicPlayerDlg::CMusicPlayerDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_MUSICPLAYER_DIALOG, pParent)
, m_strPath(_T(""))
, m_strNowPlayPath(_T(""))
, m_strVolume(_T("50/100"))
, m_strStep(_T("0:0/0:0"))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMusicPlayerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_STATICNOWPLAYPATH, m_strNowPlayPath);
DDX_Control(pDX, IDPLAY, m_btnPlay);
DDX_Control(pDX, IDC_LISTMUSIC, m_ctrMusicList);
DDX_Text(pDX, IDC_STATICVOLUME, m_strVolume);
DDX_Text(pDX, IDC_STATICSTEP, m_strStep);
DDX_Control(pDX, IDC_SLIDERSTEP, m_ctrStep);
DDX_Control(pDX, IDC_SLIDERVOLUME, m_ctrVolume);
}
BEGIN_MESSAGE_MAP(CMusicPlayerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
// ON_BN_CLICKED(IDCANCEL, &CMusicPlayerDlg::OnBnClickedCancel)
ON_WM_DESTROY()
ON_BN_CLICKED(IDPLAY, &CMusicPlayerDlg::OnClickedIdplay)
ON_BN_CLICKED(IDSTOP, &CMusicPlayerDlg::OnClickedIdstop)
ON_COMMAND(ID_MENUADDFILE, &CMusicPlayerDlg::OnMenuaddfile)
ON_COMMAND(ID_APP_ABOUT, &CMusicPlayerDlg::OnAppAbout)
ON_COMMAND(ID_MENUEXIT, &CMusicPlayerDlg::OnMenuexit)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTMUSIC, &CMusicPlayerDlg::OnLvnItemchangedListmusic)
ON_NOTIFY(NM_DBLCLK, IDC_LISTMUSIC, &CMusicPlayerDlg::OnDblclkListmusic)
ON_NOTIFY(NM_RCLICK, IDC_LISTMUSIC, &CMusicPlayerDlg::OnRclickListmusic)
ON_BN_CLICKED(IDC_BUTTONNEXT, &CMusicPlayerDlg::OnBnClickedButtonnext)
ON_BN_CLICKED(IDC_BUTTONLAST, &CMusicPlayerDlg::OnBnClickedButtonlast)
ON_COMMAND(ID_MENUCLEAR, &CMusicPlayerDlg::OnMenuclear)
ON_WM_TIMER()
ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDERSTEP, &CMusicPlayerDlg::OnNMCustomdrawSliderstep)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDERVOLUME, &CMusicPlayerDlg::OnNMCustomdrawSlidervolume)
END_MESSAGE_MAP()
// CMusicPlayerDlg 消息处理程序
BOOL CMusicPlayerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
m_PlayStatus = 0;
this->SetBackgroundColor(RGB(175,238,238));
ReadFileToList();
m_ctrVolume.SetRange(0, 100);
m_ctrVolume.SetPos(m_nowPlayVolume);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CMusicPlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CMusicPlayerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMusicPlayerDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMusicPlayerDlg::OnClickedButtonsel()
{
// TODO: 在此添加控件通知处理程序代码
/*
CFileDialog MFC中的文件打开保存对话框,CFileDialog的构造函数原型为:
*/
//OFN_ALLOWMULTISELECT 允许多选标志
CFileDialog fdlg(TRUE,_T(".mp3"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT , _T("歌曲(.mp3)|*.mp3||"), NULL);
if(fdlg.DoModal()==IDOK)
{
POSITION pos = fdlg.GetStartPosition();
while (pos != NULL)//遍历多选文件列表
{
//在这里 GetNextPathName()函数有个BUG,当列表数目过多时,文件路径会获取错误,最终失败
CString FilePath = fdlg.GetNextPathName(pos);//获取文件对话框选择的文件全路径
// MessageBox(FilePath);
AddMusicToList(FilePath);
}
}
}
void CMusicPlayerDlg::AddMusicToList(CString FilePath)//封装函数 添加音乐文件至列表框以及链表数据中
{
CString *path = new CString(FilePath);
CString name;
int index = FilePath.ReverseFind('\\');
if (index > 0)
{
name = FilePath.Right(FilePath.GetLength() - index - 1);//截取文件名称
POSITION pos = m_MusicPathList.AddTail(*path);//音乐全路径添加至数据连表中
int count = m_ctrMusicList.GetItemCount();
m_ctrMusicList.InsertItem(count, name);//将音乐名称插入列表项中
BOOL r = m_ctrMusicList.SetItemData(count, (DWORD_PTR)path);//绑定音乐全路径列表控件中
}
// MessageBox(name);
}
int CMusicPlayerDlg::StatusMessageDistribution(CString cmd, TCHAR* cmdParam,int ParamLen)//封装函数 音乐播放命令消息分配函数
{
//int result = -1;
if (cmd.IsEmpty())
return -1;
if (cmdParam==NULL)
{
cmd += _T(" music");
}
else
{
if (cmd.Compare(_T("open")) == 0)//打开文件
{
cmd.Format(_T("open \"%s\" alias music"),cmdParam);
}
else if (cmd.Compare(_T("seek")) == 0)//文件定位
{
cmd.Format(_T("seek music to %s"),cmdParam);
}
else if (cmd.Compare(_T("setaudio volume")) == 0)//设置声音
{
cmd.Format(_T("setaudio music volume to %s"), cmdParam);
}
else if (cmd.Compare(_T("play")) == 0)//定位播放
{
cmd.Format(_T("play music from %s"), cmdParam);
}
else if (cmd.Compare(_T("status")) == 0)//获取文件长度
{
cmd.Format(_T("status music length"));
memset(cmdParam, 0, MAX_PATH);
}
else
{
MessageBox(cmd + "命令无法识别");
}
}
//MessageBox(cmd);
MCIERROR r = mciSendString(cmd, cmdParam, ParamLen, NULL);
if (r == 0)
{
return 0;
}
else
{
//出错判断提示
#if _DEBUG
TCHAR erStr[MAX_PATH] = _T("");
mciGetErrorString(r, erStr, MAX_PATH);//如果文件打开遇到错误,输出错误提示语句
MessageBox(cmd+erStr);
#endif
return -1;
}
return -1;
}
void CMusicPlayerDlg::OnDestroy()//程序退出 内存清理
{
SaveListToFile();
OnMenuclear();
CDialogEx::OnDestroy();
// TODO: 在此处添加消息处理程序代码
}
void CMusicPlayerDlg::OnClickedIdplay()//音乐播放暂停
{
// TODO: 在此添加控件通知处理程序代码
int index=m_ctrMusicList.GetNextItem(-1, LVIS_SELECTED);//列表选项判断
if (index >= 0)
{
if (index != m_nowPlayIndex && m_PlayStatus>0)//判断是否播放新的音乐文件
{
OnClickedIdstop();//停止当前播放音乐
}
m_nowPlayIndex = index;
}
if (m_nowPlayIndex < 0) return;
CString *path=NULL;
TCHAR cmdPath[MAX_PATH] = _T("");
switch (m_PlayStatus)//播放状态判断
{
case 0://打开音乐文件
path=(CString*)m_ctrMusicList.GetItemData(m_nowPlayIndex);
wsprintf(cmdPath, _T("%s"), path->GetString());
ASSERT(path != NULL);
//MessageBox(*path);
if (StatusMessageDistribution(_T("open"),cmdPath) == 0)
{
m_PlayStatus = 1;
m_nowPlayStep = 0;
GetInfo();
SetVolume();
}
case 1://文件打开状态播放音乐
if (StatusMessageDistribution(_T("play")) == 0)
{
m_PlayStatus = 2;
m_strNowPlayPath = m_ctrMusicList.GetItemText(m_nowPlayIndex, 0);
m_btnPlay.SetWindowTextW(_T("暂停"));//设置按钮文本显示为暂停
UpdateData(FALSE);
SetTimer(TIMERPLAYSTEP, 1000,NULL);
}
break;
case 2://文件播放状态暂停音乐
if (StatusMessageDistribution(_T("pause")) == 0)
{
m_PlayStatus = 3;
//m_strNowPlayPath = _T("正在暂停歌曲!");
m_btnPlay.SetWindowTextW(_T("播放"));//设置按钮文本显示为暂停
//UpdateData(FALSE);
}
break;
case 3:
if (StatusMessageDistribution(_T("resume")) == 0)
{
m_PlayStatus = 2;
//m_strNowPlayPath = _T("正在播放歌曲!");
m_btnPlay.SetWindowTextW(_T("暂停"));//设置按钮文本显示为暂停
//UpdateData(FALSE);
}
break;
}
}
void CMusicPlayerDlg::OnClickedIdstop()//音乐停止
{
if (StatusMessageDistribution(_T("close")) == 0)
{
KillTimer(TIMERPLAYSTEP);
m_PlayStatus = 0;//播放状态初始化
m_nowPlayIndex = -1;//播放序号初始化
m_strNowPlayPath.Empty();//字符串提示情况
m_btnPlay.SetWindowTextW(_T("播放"));//设置按钮文本显示为暂停
UpdateData(FALSE);
}
// TODO: 在此添加控件通知处理程序代码
}
void CMusicPlayerDlg::OnMenuaddfile()//添加音乐文件菜单响应函数
{
// TODO: 在此添加命令处理程序代码
OnClickedButtonsel();
}
void CMusicPlayerDlg::OnAppAbout()//关于菜单响应函数
{
// TODO: 在此添加命令处理程序代码
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
void CMusicPlayerDlg::OnMenuexit()//程序退出菜单响应函数
{
// TODO: 在此添加命令处理程序代码
PostQuitMessage(0);
}
void CMusicPlayerDlg::OnLvnItemchangedListmusic(NMHDR *pNMHDR, LRESULT *pResult)//列表选中项改变时触发的响应消息函数
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
if (m_nowPlayIndex == pNMLV->iItem)
{
m_btnPlay.SetWindowText(_T("暂停"));
}
else
{
m_btnPlay.SetWindowText(_T("播放"));
}
*pResult = 0;
}
void CMusicPlayerDlg::OnDblclkListmusic(NMHDR *pNMHDR, LRESULT *pResult)//鼠标左键双击响应函数
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
OnClickedIdplay();
*pResult = 0;
}
void CMusicPlayerDlg::OnRclickListmusic(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
void CMusicPlayerDlg::OnBnClickedButtonnext()//下一曲功能响应函数
{
// TODO: 在此添加控件通知处理程序代码
int count = m_ctrMusicList.GetItemCount();
if (m_nowPlayIndex < (count - 1))//音乐边界判断
{
//m_nowPlayIndex += 1;
m_ctrMusicList.SetItemState(m_nowPlayIndex+1, LVIS_SELECTED, LVIS_SELECTED);
OnClickedIdplay();
}
else
{
MessageBox(_T("当前已是最后一首音乐!"));
}
}
void CMusicPlayerDlg::OnBnClickedButtonlast()
{
// TODO: 在此添加控件通知处理程序代码
if (m_nowPlayIndex >0)//音乐边界判断
{
//m_nowPlayIndex -= 1;
m_ctrMusicList.SetItemState(m_nowPlayIndex-1, LVIS_SELECTED, LVIS_SELECTED);
OnClickedIdplay();
}
else
{
MessageBox(_T("当前已处于第一首音乐!"));
}
}
void CMusicPlayerDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
// CDialogEx::OnOK();
}
void CMusicPlayerDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
//CDialogEx::OnCancel();
}
int CMusicPlayerDlg::SaveListToFile() //音乐文件列表保存
{
char* old_locale = _strdup(setlocale(LC_CTYPE, NULL));
setlocale(LC_CTYPE, "chs");//设定为中文环境,解决UNICODE环境下中文字符储存问题
CStdioFile file;
BOOL r=file.Open(_T("musiclist.dat"), CStdioFile::modeCreate | CStdioFile::modeWrite);
if (r == FALSE)
{
MessageBox(L"文件写入失败!");
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
return -1;
}
TCHAR wtBuffer[1024]=L"";
int count = m_ctrMusicList.GetItemCount();
for (int i = 0; i < count; i++)
{
//CString name=m_ctrMusicList.GetItemText(i, 0);
CString *path =(CString*)m_ctrMusicList.GetItemData(i);
ASSERT(path != NULL);
wsprintf(wtBuffer, L"%s\n", path->GetString());
//MessageBox(wtBuffer);
file.WriteString(wtBuffer);
}
file.Close();
//文件操作结束后,还原
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
return 0;
}
int CMusicPlayerDlg::ReadFileToList() //音乐文件列表还原
{
//设定为中文环境,解决UNICODE环境下中文字符储存问题
char* old_locale = _strdup(setlocale(LC_CTYPE, NULL));
setlocale(LC_CTYPE, "chs");
CStdioFile file;
BOOL r = file.Open(_T("musiclist.dat"), CStdioFile::modeRead);
if (r == FALSE)
{
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
MessageBox(L"文件读取失败!");
return -1;
}
TCHAR rdBuffer[1024] = L"";
TCHAR name[MAX_PATH] = L"";
TCHAR *path = NULL;
while (file.ReadString(rdBuffer,1024))
{
int size = lstrlen(rdBuffer);
rdBuffer[size - 1] = '\0';
AddMusicToList(rdBuffer);
}
file.Close();
//文件操作结束后,还原
setlocale(LC_CTYPE, old_locale);
free(old_locale);//还原区域设定
return 0;
}
void CMusicPlayerDlg::OnMenuclear() //情况列表
{
// TODO: 在此添加命令处理程序代码
if (m_PlayStatus>0)
StatusMessageDistribution(_T("close"));
m_ctrMusicList.DeleteAllItems();
int count = m_MusicPathList.GetCount();
for (int i = 0; i < count; i++)
{
m_MusicPathList.RemoveTail();
}
}
int CMusicPlayerDlg::GetInfo() //获取音乐文件信息
{
TCHAR cmd[MAX_PATH] = L"status";
TCHAR szlen[MAX_PATH] = L"";
StatusMessageDistribution(cmd, szlen, MAX_PATH);
m_nowPlayLength =_wtoi(szlen);
m_nowPlayLength /= 1000;
m_ctrStep.SetRange(0, m_nowPlayLength);
m_ctrStep.SetPos(0);
m_strStep.Format(L"%2d:%2d/%2d:%2d",m_nowPlayStep/60,m_nowPlayStep%60, m_nowPlayLength /60, m_nowPlayLength %60);
UpdateData(FALSE);
return 0;
}
void CMusicPlayerDlg::OnTimer(UINT_PTR nIDEvent) //定时器响应函数
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
switch (nIDEvent)
{
case TIMERPLAYSTEP: //进度条变化
if (m_PlayStatus == 2)
{
if (m_nowPlayStep < m_nowPlayLength)
{
m_nowPlayStep += 1;
m_strStep.Format(L"%2d:%2d/%2d:%2d", m_nowPlayStep / 60, m_nowPlayStep % 60, m_nowPlayLength / 60, m_nowPlayLength % 60);
m_ctrStep.SetPos(m_nowPlayStep);
UpdateData(FALSE);
}
else //若播放完毕 自动跳转下一曲
{
OnBnClickedButtonnext();
}
}
break;
default:
break;
}
CDialogEx::OnTimer(nIDEvent);
}
void CMusicPlayerDlg::OnNMCustomdrawSliderstep(NMHDR *pNMHDR, LRESULT *pResult) //进度条滑块响应函数
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
if (m_PlayStatus == 2) //判断是否
{
int pos = m_ctrStep.GetPos();
if (abs(pos - m_nowPlayStep) > 2) //误差判定 若变化值大于2 视为人工改变进度条
{
m_nowPlayStep = pos;
TCHAR cmd[MAX_PATH] = L"play";
TCHAR cmdParam[MAX_PATH] = L"";
wsprintf(cmdParam, L"%d", m_nowPlayStep * 1000);
StatusMessageDistribution(cmd, cmdParam, MAX_PATH);//自定义音乐控制消息分配函数
}
}
*pResult = 0;
}
void CMusicPlayerDlg::OnNMCustomdrawSlidervolume(NMHDR *pNMHDR, LRESULT *pResult) //声音滑块响应函数
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = m_ctrVolume.GetPos();
if (m_PlayStatus == 2) //判断是否出于播放状态
{
if (abs(pos - m_nowPlayVolume) > 2) //误差判定 若变化值大于2 视为人工改变进度条
{
m_nowPlayVolume = pos;
SetVolume(); //自定义的音量设置函数
}
}
else
{
m_nowPlayVolume = pos;
}
m_strVolume.Format(L"%d/100", m_nowPlayVolume);
UpdateData(FALSE);
*pResult = 0;
}
int CMusicPlayerDlg::SetVolume() //设置声音
{
TCHAR cmd[MAX_PATH] = L"setaudio volume";
TCHAR cmdParam[MAX_PATH] = L"";
wsprintf(cmdParam, L"%d", m_nowPlayVolume * 10);
StatusMessageDistribution(cmd, cmdParam, MAX_PATH);
return 0;
}
5.演示
本节结束语:
从开始着手到现在,中间磕磕碰碰,所谓学如逆水行舟,不进则退!虽然以前用VC6.0写过一遍,但现在利用VS2017重写一遍,完全是一种全新的体验,很多功能,很多函数,不去温故,很容易就忘记了!
从第一节开始到现如今,功能基本完善了!或者下一节就是终点,又或者将一直更新下去,弥补之前写的旧版本所遗留下的一些遗憾!
下一节,会把计划会添加全盘扫描音乐文件功能,播放模式设置功能!或者再加一些小的功能,暂时未想到,待定!
(没进行太多测试,中间难免有BUG或遗漏错误之处!)
相关资讯