MFC学习笔记之简单MP3播放器的设计

         首先对MCI(Media Control Interface)媒体控制接口作简单介绍,MCI是微软公司提供的一组多媒体设备和文件的标准接口,其优点是可以方便地控制绝大所数多媒体设备,包括音频、视频、影碟、录像等多媒体设备,而不需要知道它们的内部工作状况。接口所支持的媒体格式包括avi、wav、mpeg、Mp3、wma等。这里要做的就是通过公开的访问接口直接调用系统内置引擎实现MP3的播放。

        接口函数的声明如下:

        MCIERROR WINAPI mciSendCommand(MCIDEVICEID mciId,

UINT uMsg,

DWORD dwParam1,

DWORD dwParam2)

其中mciId指定了设备标识,这个标识会在程序员打开MCI设备时由系统提供。uMsg指定将如何控制设备,即MCI指令,最后两个参数一般是一个数据结构,标识程序在访问MCI时要的信息。MCI常用指令有MCI_OPEN、MCI_PAUSE、MCI_CLOSE、MCI_STOP、MCI_PLAY、MCI_STATUS等。

        制作流程如下:

        1.在对话框上分别添加一个滑动条和四个按钮,如图所示:

MFC学习笔记之简单MP3播放器的设计_第1张图片

播放进度、播放、暂停、停止、打开文件的ID号分别设置为IDC_PROCESS、IDC_PLAY_BUTTON、IDC_PAUSE_BUTTON、IDC_STOP_BUTTON、IDC_OPEN_BUTTON。

2.新建一个CMyPlayerControl类,其头文件和实现如下:

CMyPlayerControl.h:

#pragma once

#ifndef _MY_PLAYER_CONTROL_H_
#define _MY_PLAYER_CONTROL_H_

//插入多媒体头文件
#include

class CMyPlayerControl
{
public:
	CMyPlayerControl(void);
	~CMyPlayerControl(void);
public:
	BOOL Open(LPCWSTR lpFileName);//打开文件
	void Play();//播放
	void Close();//关闭
	void Stop();//停止
	void Pause();//暂停
	DWORD GetLength(DWORD dwItem);//获取歌曲长度
	void SetWindowHwnd(HWND hWnd);//设置主窗口句柄
private:
	MCI_OPEN_PARMS mciOpen;//打开设备参数
	HWND m_hWnd;//主窗口句柄
	DWORD dwFrom;//播放起始点
};

#endif

CMyPlayerControl.cpp:因为类中调用了系统的MCI接口的API函数,所以必须加入winmm.lib这个静态链接库文件。

#include "StdAfx.h"
#include "MyPlayerControl.h"


CMyPlayerControl::CMyPlayerControl(void)
{
}


CMyPlayerControl::~CMyPlayerControl(void)
{
	Close();
}

DWORD CMyPlayerControl::GetLength(DWORD dwItem)
{
	//得到当前文件状态
	MCI_STATUS_PARMS mcistatusparms;
	mcistatusparms.dwCallback=(DWORD)m_hWnd;
	mcistatusparms.dwItem=dwItem;
	mcistatusparms.dwReturn=0;
	mciSendCommand(mciOpen.wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)&mcistatusparms);
	return mcistatusparms.dwReturn;
}

BOOL CMyPlayerControl::Open(LPCWSTR lpFileName)
{
	//如果有打开的MCI设备就关闭
	if(mciOpen.wDeviceID)Close();
	//初始化MCI_OPEN_PARMS结构中的文件类型
	mciOpen.lpstrDeviceType=NULL;
	//播放文件路径
	mciOpen.lpstrElementName=lpFileName;
	//向MCI设备发送命令消息(在打开设备时,设备号为0)
	if(mciSendCommand(0,MCI_OPEN,MCI_DEVTYPE_WAVEFORM_AUDIO,(DWORD)&mciOpen))
	{
		return FALSE;
	}
	dwFrom=MCI_MAKE_HMS(0,0,0);
	return TRUE;
}

void CMyPlayerControl::Play()
{
	//播放参数结构
	MCI_PLAY_PARMS mciplayparms;
	//得到文件大小
	DWORD cdlen=GetLength(MCI_STATUS_LENGTH);
	DWORD cdto=MCI_MAKE_HMS(MCI_HMS_HOUR(cdlen),MCI_HMS_MINUTE(cdlen),MCI_HMS_SECOND(cdlen));//把文件中读出的大小转换为时间数量
	mciplayparms.dwCallback=NULL;
	mciplayparms.dwFrom=dwFrom;//设置起始位置
	mciplayparms.dwTo=cdto;//设置终止位置
	if(mciOpen.wDeviceID!=0)//判断是否打开文件
	{//播放音乐
		mciSendCommand(mciOpen.wDeviceID,MCI_PLAY,MCI_TO|MCI_FROM,(DWORD)(LPVOID)&mciplayparms);
	}
}

void CMyPlayerControl::Close()
{
	if(mciOpen.wDeviceID)
	{
		//执行MCI_CLOSE操作,关闭MCI设备
		mciSendCommand(mciOpen.wDeviceID,MCI_CLOSE,NULL,NULL);
	}
}

void CMyPlayerControl::Stop()
{
	if(mciOpen.wDeviceID)
	{//执行MCI_STOP操作,停止播放音乐
		mciSendCommand(mciOpen.wDeviceID,MCI_STOP,NULL,NULL);
		//把播放位置设定为音乐文件的开头(下一次播放操作从文件开头位置开始)
		mciSendCommand(mciOpen.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,NULL);
	}
	dwFrom=MCI_MAKE_HMS(0,0,0);
}

void CMyPlayerControl::Pause()
{
	if(mciOpen.wDeviceID)
	{//执行MCI_PAUSE操作,暂停播放音乐
		DWORD dwsf=GetLength(MCI_STATUS_POSITION);
		dwFrom=MCI_MAKE_MSF(MCI_MSF_MINUTE(dwsf),MCI_MSF_SECOND(dwsf),MCI_MSF_FRAME(dwsf));
	//执行MCI_PAUSE操作,暂停播放音乐
		mciSendCommand(mciOpen.wDeviceID,MCI_PAUSE,NULL,NULL);
	}
}

void CMyPlayerControl::SetWindowHwnd(HWND hWnd)
{
	m_hWnd=hWnd;
}
使用类的定义方法,可以使这个类具有更高的重用性。

CMp3PlayerDlg.h的声明中为各个按钮添加单击事件响应函数,并添加OnOk、OnCancel虚函数,并对WM_TIMER添加响应函数,对滑动条添加私有变量CSliderControl m_process以及。其具体代码如下:

// Mp3PlayerDlg.h : 头文件
//

#if !defined(AFX_MP3PLAYERDLG_H__)
#define AFX_MP3PLAYERDLG_H__
#if _MSG_VER > 1000
#pragma once
#endif

#include"MyPlayerControl.h"
#include "afxcmn.h"

// CMp3PlayerDlg 对话框
class CMp3PlayerDlg : public CDialogEx
{
// 构造
public:
	CMp3PlayerDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_MP3PLAYER_DIALOG };

	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:
	afx_msg void OnBnClickedPlayButton();
	afx_msg void OnBnClickedPauseButton();
	afx_msg void OnBnClickedStopButton();
	afx_msg void OnBnClickedOpenButton();
	CSliderCtrl m_process;
private:
	CMyPlayerControl m_myPlayerControl;
	CString m_strFileName;
	virtual void OnCancel();
	virtual void OnOK();
public:
	afx_msg void OnTimer(UINT_PTR nIDEvent);
};
#endif
在声明过函数之后,在源文件CMp3PlayerDlg.cpp中进行具体实现:

// Mp3PlayerDlg.cpp : 实现文件
//


#include "stdafx.h"
#include "Mp3Player.h"
#include "Mp3PlayerDlg.h"
#include "afxdialogex.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif




// 用于应用程序“关于”菜单项的 CAboutDlg 对话框


class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();


// 对话框数据
	enum { IDD = IDD_ABOUTBOX };


	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
	DECLARE_MESSAGE_MAP()
};


CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}


void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()




// CMp3PlayerDlg 对话框








CMp3PlayerDlg::CMp3PlayerDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMp3PlayerDlg::IDD, pParent)
	, m_strFileName(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}


void CMp3PlayerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_PROCESS, m_process);
}


BEGIN_MESSAGE_MAP(CMp3PlayerDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_PLAY_BUTTON, &CMp3PlayerDlg::OnBnClickedPlayButton)
	ON_BN_CLICKED(IDC_PAUSE_BUTTON, &CMp3PlayerDlg::OnBnClickedPauseButton)
	ON_BN_CLICKED(IDC_STOP_BUTTON, &CMp3PlayerDlg::OnBnClickedStopButton)
	ON_BN_CLICKED(IDC_OPEN_BUTTON, &CMp3PlayerDlg::OnBnClickedOpenButton)
	ON_WM_TIMER()
END_MESSAGE_MAP()




// CMp3PlayerDlg 消息处理程序


BOOL CMp3PlayerDlg::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: 在此添加额外的初始化代码


	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}


void CMp3PlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}


// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。


void CMp3PlayerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文


		SendMessage(WM_ICONERASEBKGND, reinterpret_cast(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 CMp3PlayerDlg::OnQueryDragIcon()
{
	return static_cast(m_hIcon);
}






void CMp3PlayerDlg::OnBnClickedPlayButton()
{
	// TODO: 在此添加控件通知处理程序代码
	DWORD cdlen=m_myPlayerControl.GetLength(MCI_STATUS_LENGTH);
	m_myPlayerControl.Play();
	m_process.SetRange(0,cdlen);
	SetTimer(0,1000,NULL);
}




void CMp3PlayerDlg::OnBnClickedPauseButton()
{
	// TODO: 在此添加控件通知处理程序代码
	m_myPlayerControl.Pause();//调用暂停
}




void CMp3PlayerDlg::OnBnClickedStopButton()
{
	// TODO: 在此添加控件通知处理程序代码
	m_myPlayerControl.Stop();
	m_process.SetPos(0);
	KillTimer(0);
}




void CMp3PlayerDlg::OnBnClickedOpenButton()
{
	// TODO: 在此添加控件通知处理程序代码
	CString strFilter(_T("MP3 Files(*.mp3)|*.mp3||"));
	CFileDialog OpenDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,strFilter);
	int nFlags=OpenDlg.DoModal();//通过打开对话框选择MP3文件
	if(nFlags==IDOK)
	{//用户单击的是“打开”按钮,将文件路径名赋给成员变量m_strFileName备用
		m_strFileName=OpenDlg.GetPathName();
		//打开MCI设备,并将设备分配给选中的文件使用
		m_myPlayerControl.Open(m_strFileName);
	}
}




void CMp3PlayerDlg::OnCancel()
{
	// TODO: 在此添加专用代码和/或调用基类


	CDialogEx::OnCancel();
}




void CMp3PlayerDlg::OnOK()
{
	// TODO: 在此添加专用代码和/或调用基类


	CDialogEx::OnOK();
}




void CMp3PlayerDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	//每秒钟得到的当前播放进度
	DWORD cdf=m_myPlayerControl.GetLength(MCI_STATUS_POSITION);
	m_process.SetPos(cdf);//设置进度条位置
	CDialogEx::OnTimer(nIDEvent);//调用其他Timer
}
测试程序效果。操作方法为:单击“打开文件”按钮,弹出“打开”对话框。指定文件,并单击对话框中的“打开”按钮,打开指定文件后,单击“播放”按钮,这时进度条会自动向右增加,并且可以听到音乐开始播放了。这个例子只支持MP3格式的音乐。

至此,完成。

你可能感兴趣的:(学习笔记)