23|VS2017 基于MFC 做一个音乐播放器,带音量调节,切换歌曲

最近接到个小任务,用MFC做一个音乐播放器,不过这也是一直想尝试的,于是今天早上9点到下午16:00,总算是完成了需要的功能

开门见山,先展示一下整体界面
在这里插入图片描述

下面按照功能模块介绍我做这个播放器的过程

预加载歌曲

我是在一个txt文件里面记录了我的本地音乐的路径,然后程序启动的时候就读取这个txt,根据路径去查找音乐
在这里插入图片描述

vector<CString>preLoadMusicPath;
vector<CString>preLoadMusicName;
CListBox listBox;//这个变量是在自己在listctrl控件上面绑定的

在这里插入图片描述

BOOL CMyMusicPlayerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。
	CString strFileName = _T("musicPath.txt");
	if (!PathFileExists(strFileName))
	{
		return FALSE;
	}
	CStdioFile file;
	if (!file.Open(strFileName, CFile::modeRead))
	{
		return FALSE;
	}

	CString temp;
	CString strValue = _T("");

	while (file.ReadString(strValue))
	{
		int pos = strValue.ReverseFind(_T('\\'));
		preLoadMusicPath.push_back(strValue);
		preLoadMusicName.push_back(strValue.Mid(pos+1, strValue.GetLength()));		
	//	preLoadBook.push_back(v1);
	}
	file.Close();

	for (int i = 0; i < preLoadMusicPath.size(); i++)
	{
		listBox.AddString(preLoadMusicName[i]);
	}	
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

下图就是预加载的结果,
在这里插入图片描述

添加歌曲

首先,先来做添加歌曲的部分

第一步自然需要点击按钮然后打开文件框选项选择音乐文件

#include "stdafx.h"
#include "MyMusicPlayer.h"
#include "MyMusicPlayerDlg.h"
#include "afxdialogex.h"
#include "mmsystem.h"

HWND m_hWnd;//记录当前窗口的句柄  
//DWORD DeviceID;//指定播放音乐的设备  
MCI_OPEN_PARMS mciopenparms;//指定打开音乐文件的参数  
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
CString fullPath;
MCIDEVICEID m_IDdevice;

注意我包含了头文件"mmsystem.h"

void CMyMusicPlayerDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	CString musicName;
	//CString fullPath;	
	CString m_strLilePath;
	CFileDialog dlgFile(TRUE, NULL, NULL,
		OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT | OFN_EXPLORER,
		_T("All files|*.mp3;*.wma;*.wav|MP3 (*.MP3)|*.mp3|WMA (*.wma)|*.wma||"),
		NULL);
	if (dlgFile.DoModal() == IDOK)
	{
		//CString img_select;
		fullPath = dlgFile.GetPathName();
		musicName = dlgFile.GetFileName();

		preLoadMusicPath.push_back(fullPath);
		int pos = fullPath.ReverseFind(_T('\\'));
		
		preLoadMusicName.push_back(fullPath.Mid(pos + 1, fullPath.GetLength()));	
		listBox.AddString(musicName);
		//Load(this->m_hWnd, fullPath);
		SetDlgItemText(IDC_EDIT1, fullPath);//img_select为选择的文件的路径,IDC_IMGSELECTEDIT为edit控件名称
		mciSendCommand(m_IDdevice, MCI_CLOSE, 0, 0);
		//打开一首歌曲

		MCI_OPEN_PARMS mciOpenParms;
		mciOpenParms.lpstrElementName = fullPath;
		//MessageBox(0strFilePath);
		curPlayPos = preLoadMusicName.size() + 1;//当前的播放位置,播放第几首歌曲,这的意思就是播放刚添加的歌曲
		mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_WAIT, (DWORD)&mciOpenParms);
		m_IDdevice = mciOpenParms.wDeviceID;
	}
}

这里会报错

这是因为mciSendCommand这个函数需要一个lib来链接,这个lib就是winmm.lib

所以我们还需要如下代码放在最前面

#pragma comment(lib,"winmm.lib")

当然,你也可以找到这个lib文件,然后 ,在 项目->属性->VC++目录->库目录

在这里插入图片描述

我把winmm.lib放在下面的文件夹的,所以我在库目录包含了这个文件夹
在这里插入图片描述
之后我们需要在 链接器->输入->附加依赖项加上这个lib的名字
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

播放歌曲

void CMyMusicPlayerDlg::OnBnClickedButton2()
{
	SetDlgItemText(IDC_EDIT2,preLoadMusicName[curPlayPos]);
	MCI_PLAY_PARMS mciPlayParms;
	mciPlayParms.dwCallback = NULL;
	mciPlayParms.dwFrom = 0;
	mciSendCommand(m_IDdevice, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD)&mciPlayParms);

}

暂停播放

void CMyMusicPlayerDlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_BUTTON3, str);
	if (str == _T("暂停"))
	{
		mciSendCommand(m_IDdevice, MCI_PAUSE, 0, 0);
		SetDlgItemText(IDC_BUTTON3, _T("继续"));
	}
	else {
		mciSendCommand(m_IDdevice, MCI_RESUME, 0, 0);
		SetDlgItemText(IDC_BUTTON3, _T("暂停"));
	}
}

停止播放

void CMyMusicPlayerDlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	//SetDlgItemText(IDC_EDIT2, "");
	mciSendCommand(m_IDdevice, MCI_STOP, 0, 0);
	mciSendCommand(m_IDdevice, MCI_CLOSE, 0, 0);
}

删除歌曲

大概思路就是先获取Listbox上光标的位置,然后去定位选择的需要删除的歌曲在preloadMusicName中的位置,去vector容器里面先把这首歌删了,然后重新写入listBox展示,最后退出软件时,也会把操作后的结果写入txt保存,以便重新打开软件时进行预加载

void CMyMusicPlayerDlg::OnBnClickedButton7()
{
	// TODO: 在此添加控件通知处理程序代码
	curPlayPos = 0;
	int pos = listBox.GetCurSel();
	listBox.ResetContent();
	
	int count = 0;
	for (vector<CString>::iterator iter = preLoadMusicPath.begin(); iter != preLoadMusicPath.end(); iter++)
	{
		
		if (count == pos)
		{
			preLoadMusicPath.erase(iter);
			break;
		}	
		count++;
	}

	int count2 = 0;
	for (vector<CString>::iterator iter = preLoadMusicName.begin(); iter != preLoadMusicName.end(); iter++)
	{
		//std::cout << iter->a << iter->b << iter->c << std::endl;
		if (count2 == pos)
		{
			preLoadMusicName.erase(iter);
			break;
		}
		count2++;
	}

	for (int i = 0; i < preLoadMusicName.size(); i++)
	{
		listBox.AddString(preLoadMusicName[i]);
	}

}

上一曲

void CMyMusicPlayerDlg::OnBnClickedButton5()
{
	// TODO: 在此添加控件通知处理程序代码
	if (curPlayPos ==0)
	{
		MessageBox(_T("已经到达第一首歌曲"));
	}
	if (curPlayPos > 0)
	{
		curPlayPos = curPlayPos - 1;
		listBox.SetCurSel(curPlayPos);
		mciSendCommand(m_IDdevice, MCI_CLOSE, 0, 0);
		//打开一首歌曲		
		MCI_OPEN_PARMS mciOpenParms;
		mciOpenParms.lpstrElementName = preLoadMusicPath[curPlayPos];
		//MessageBox(preLoadMusicPath[pos]);
		mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_WAIT, (DWORD)&mciOpenParms);
		m_IDdevice = mciOpenParms.wDeviceID;
		OnBnClickedButton2();//就是调用播放函数
	}

}

下一曲

void CMyMusicPlayerDlg::OnBnClickedButton6()
{
	// TODO: 在此添加控件通知处理程序代码
	if (curPlayPos == preLoadMusicName.size()-1)
	{
		MessageBox(_T("已经到达最后一首歌曲"));
	}
	if (curPlayPos < preLoadMusicName.size() - 1)
	{
		curPlayPos = curPlayPos + 1;
		listBox.SetCurSel(curPlayPos);
		mciSendCommand(m_IDdevice, MCI_CLOSE, 0, 0);
		//打开一首歌曲		
		MCI_OPEN_PARMS mciOpenParms;
		mciOpenParms.lpstrElementName = preLoadMusicPath[curPlayPos];
		//MessageBox(preLoadMusicPath[pos]);
		mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_WAIT, (DWORD)&mciOpenParms);
		m_IDdevice = mciOpenParms.wDeviceID;
		OnBnClickedButton2();
	}
}

音量调节

这一部分是耗我时间最久的了,主要参考别人的,别人的可以,放在我的程序上面就不行了

音量调节的思路是通过滑块调节系统声音

找到 类视图->属性
在这里插入图片描述在这里插入图片描述

会生成下面的函数

void CMyMusicPlayerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	UpdateData(TRUE);
	volume = slide.GetPos();
	CoInitialize(0);
	nVolume = SetVolum(volume);
	CoUninitialize();
	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
	UpdateData(FALSE);
}

然后我们看看SetVolum函数的定义

#include <Digitalv.h>
#include <mmdeviceapi.h> 
#include <endpointvolume.h>
#include <audioclient.h>
bool SetVolum(int volume)
{
	HRESULT hr;
	IMMDeviceEnumerator* pDeviceEnumerator = 0;
	IMMDevice* pDevice = 0;
	IAudioEndpointVolume* pAudioEndpointVolume = 0;
	IAudioClient* pAudioClient = 0;

	try {
		hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pDeviceEnumerator);
		if (FAILED(hr)) throw "CoCreateInstance";
		hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
		if (FAILED(hr)) throw "GetDefaultAudioEndpoint";
		hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioEndpointVolume);
		if (FAILED(hr)) throw "pDevice->Active";
		hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
		if (FAILED(hr)) throw "pDevice->Active";

		float fVolume;
		fVolume = volume / 100.0f;
		hr = pAudioEndpointVolume->SetMasterVolumeLevelScalar(fVolume, &GUID_NULL);
		if (FAILED(hr)) throw "SetMasterVolumeLevelScalar";

		pAudioClient->Release();
		pAudioEndpointVolume->Release();
		pDevice->Release();
		pDeviceEnumerator->Release();
		return true;
	}

	catch (...) {
		if (pAudioClient) pAudioClient->Release();
		if (pAudioEndpointVolume) pAudioEndpointVolume->Release();
		if (pDevice) pDevice->Release();
		if (pDeviceEnumerator) pDeviceEnumerator->Release();
		throw;
	}
	return false;
}

同时我们需要在OnInitDialog()函数进行初始化

    slide.SetRange(0, 100);//设置滑动范围为1到20
	slide.SetTicFreq(1);//每1个单位画一刻度

	CoInitialize(0);
	nVolume = GetVolume();
	CoUninitialize();
	slide.SetPos(nVolume);//设置滑块初始位置为1
	volume = nVolume;
	UpdateData(FALSE);
int  GetVolume()
{
	HRESULT hr;
	IMMDeviceEnumerator* pDeviceEnumerator = 0;
	IMMDevice* pDevice = 0;
	IAudioEndpointVolume* pAudioEndpointVolume = 0;
	IAudioClient* pAudioClient = 0;

	try {
		hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pDeviceEnumerator);
		if (FAILED(hr)) throw "CoCreateInstance";
		hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
		if (FAILED(hr)) throw "GetDefaultAudioEndpoint";
		hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioEndpointVolume);
		if (FAILED(hr)) throw "pDevice->Active";
		hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
		if (FAILED(hr)) throw "pDevice->Active";


		float fVolume;


		hr = pAudioEndpointVolume->GetMasterVolumeLevelScalar(&fVolume);

		if (FAILED(hr)) throw "SetMasterVolumeLevelScalar";


		pAudioClient->Release();
		pAudioEndpointVolume->Release();
		pDevice->Release();
		pDeviceEnumerator->Release();


		int  intVolume = fVolume * 100;
		if (fVolume > 100)
		{
			fVolume = 100;
		}
		return intVolume;

	}
	catch (...) {
		if (pAudioClient) pAudioClient->Release();
		if (pAudioEndpointVolume) pAudioEndpointVolume->Release();
		if (pDevice) pDevice->Release();
		if (pDeviceEnumerator) pDeviceEnumerator->Release();
		throw;
	}
}

在这里插入图片描述

退出软件时把最新结果写入txt文件

需要注意的是,由于txt中有中文,所以需要把项目的字符集改成多字节字符集
在这里插入图片描述
同时需要包含头文件

#include <locale>//为了使用setlocale(LC_CTYPE, "chs");便于输入中文到txt中
void CMyMusicPlayerDlg::OnBnClickedCancel()
{
	// TODO: 在此添加控件通知处理程序代码
	CString filename = _T("musicPath.txt");
	CString strWriteData;
	

	//strWriteData.Format(_T("测试写入中文和Endlish¥\n"));
	CStdioFile csFile;
	CFileException cfException;
	if (csFile.Open(filename, CFile::typeText | CFile::modeCreate | CFile::modeReadWrite, &cfException))//以txt方式读取|若没有文件则创建该文件|文件打开时不清除
	{
		csFile.SeekToEnd();
		setlocale(LC_CTYPE, "chs");//为了能用csFile.WriteString(strWriteData)写入中文
		
	
		for (int i = 0; i < preLoadMusicPath.size(); i++)
		{
			strWriteData = preLoadMusicPath[i]+_T("\n");
			csFile.WriteString(strWriteData);
		}
	}
	csFile.Close();



	CDialogEx::OnCancel();
}

注意事项

这个播放器某些mp3音乐是不能播放的,我也不知道为什么,但是大部分还是可以播放的,比较抱歉的是代码不是很规范,比如控件的名字没改,导致生成的响应函数可读性比较差

好了,终于介绍完了,有很多细节是需要自己探索,百度的

附件

完整源代码及参考资料
https://download.csdn.net/download/ningmengshuxiawo/19224419

  • 3
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
MFC音乐播放器是一款基于Microsoft Foundation Class(MFC)框架开发的音乐播放器软件。它支持显示播放列表,为用户提供了便利的音乐管理和播放功能。 在MFC音乐播放器,显示播放列表的功能主要由两个部分组成:播放列表窗口和歌曲项。 首先,播放列表窗口是用于显示当前播放列表歌曲信息的主要窗口。它通常位于软件界面的一侧或底部,用户可以通过拖拽调整窗口大小或关闭窗口。在该窗口,用户可以看到当前播放列表的所有歌曲,包括歌曲名称、歌手、专辑等信息。用户可以通过单击、双击、拖拽等方式对歌曲进行操作,如播放、暂停、删除、添加等。 其次,歌曲项是显示在播放列表窗口的每一首歌曲的独立项。每一个歌曲项通常包含歌曲封面、歌曲名称、歌手名等元素,用户可以通过点击歌曲项来选择和操作歌曲。用户也可以通过拖拽歌曲项的顺序来调整播放列表歌曲的播放顺序。 在MFC音乐播放器,用户可以通过选择导入本地音乐文件或通过网络加载歌曲来创建播放列表。用户可以随时对播放列表进行编辑,添加新的歌曲或删除已有的歌曲。播放列表歌曲会按照添加的顺序进行播放,用户可以通过点击歌曲项或使用播放器提供的控制按钮来控制音乐的播放。 总结起来,MFC音乐播放器通过显示播放列表的方式,为用户提供了方便的音乐管理和播放功能。用户可以在播放列表查看和管理已添加的歌曲,通过简单的操作就能实现音乐的播放、暂停、删除、添加等功能,让用户能够轻松地享受音乐。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值