用基本C#知识实现制作一个音乐播放器
前言
写这个博客并不是说我的作品多么高级或完美,只是希望能在一些功能方面给你们一些启发,能帮助到你们做出真正好的程序,这就足够了
话不多说,让我们开始吧~~~
截图示意
总体思路
首先呢,选择这种无边框窗口,我们会发现移动窗口成了问题,所以呢,就需要特意对主窗口写事件,即按下时,移动时,松开时等各是怎样,这个应该不难。
···
Point downpoint;
Point movepoint;
bool ismoving;
//实现鼠标控制窗口移动
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
downpoint = e.Location;
ismoving = true;
}
private void timermove_Tick(object sender, EventArgs e)
{
}
//实现鼠标控制窗口移动(2)
private void mainForm_MouseMove(object sender, MouseEventArgs e)
{
if (ismoving == true)
{
movepoint = e.Location;
this.Location = new Point(
this.Location.X + (movepoint.X - downpoint.X),
this.Location.Y + (movepoint.Y - downpoint.Y)
);
}
}
//鼠标按键抬起窗口停止移动
private void mainForm_MouseUp(object sender, MouseEventArgs e)
{
ismoving = false;
}
····
然后就是引入WindowsMediaPlayer后我们需要实现音频文件资源的打开,这里我设置了文件过滤器,只能打开“.MP3”“.MP4”“.flac”三种文件,同时实现了基本功能,例如点击播放器的播放(暂停)键时图标的变化、歌曲继续、暂停等(所以我们用到一个bool型变量方便判断)
···
bool isplaying = true;
string a;//歌曲总时间(字符串)
//点击播放:加载歌词
private void start_Click(object sender, EventArgs e)
{
if (tick == 0)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "mp3音乐|*.mp3|mp4音乐|*.mp4|flac文件|*.flac";//设置文件过滤,使之只能打开.mp3/.mp4/flac三种格式的音频文件
ofd.ShowDialog();
string fileName = ofd.FileName;
media.URL = fileName;
media.Ctlcontrols.play();
// start_Click(object sender, EventArgs e);
timer2.Enabled = true;
}
tick = 1;
timer1.Enabled = true;
Encoding encode = Encoding.GetEncoding("GB2312");
FileStream fs = new FileStream("陈一发儿-童话镇.lrc", FileMode.Open);
StreamReader sr = new StreamReader(fs, encode);
string s = sr.ReadLine();
//int xPos = 100;
int yPos = 50;
string a= media.currentMedia.durationString;
stime.Text = a;
while (s != null)
{
s = sr.ReadLine();
if(s==null)
{
break;
}
if (s.Equals(""))
{
continue;
}
Lyric1 lyric =new Lyric1();
lyric.minute =int.Parse(s.Substring(1,2));
lyric.second = int.Parse(s.Substring(4,2));
lyric.lyrics = s.Substring(10);
lyric.tosecond = lyric.minute * 60 + lyric.second;
//if(s.Substring(10)==null)
//{
// lyric.sminute = Convert.ToInt32(s.Substring(1, 1));
//lyric.ssecond = Convert.ToInt32(s.Substring(5, 1));
// }
listLyric1.Add(lyric);
yPos += 30;
}
if (isplaying)
{
start.BackgroundImage = Properties.Resources.play_circle_o;
isplaying = false;
media.Ctlcontrols.pause();
timer1.Enabled = false;
}
else
{
start.BackgroundImage = Properties.Resources.pause_circle_o;
isplaying = true;
media.Ctlcontrols.play();
timer1.Enabled = true;
}
fs.Close();
sr.Close();
}
···
另一个功能有一部分也包含在上述代码中,那就是重要的歌词绘制(只不过上面主要只实现了歌词文件(“.lrc”)的读取),其实有人说用label也能显示歌词、甚至实现歌词滚动、变色,可是吧…效果不太好,一方面不流畅,另一方面显示效果也差,甚至可能有闪屏
所以我采用了GDI+绘图实现的
注意哈,GDI+绘图是不会自动变化的,需要窗口隐藏以至于无效化才会更新
所以我们需要写程序使需要的区域(不一定是整个主窗口)不断自动刷新
···
Graphics g;//绘图对象
int PointY=140;
int current;
//主窗口绘制歌词
private void mainForm_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
if (tick == 2)
{
for (int i = 0; i < listLyric.Count; i++)
{
if (i == current)
g.DrawString(listLyric[i].lyrics, new Font("微软雅黑", 17), Brushes.LightBlue, 400, PointY + i * 50);
else
g.DrawString(listLyric[i].lyrics, new Font("微软雅黑", 14), Brushes.White, 400, PointY + i * 50);
}
}
else
{
for (int i = 0; i < listLyric1.Count; i++)
{
if (i == current)
g.DrawString(listLyric1[i].lyrics, new Font("微软雅黑", 17), Brushes.LightBlue, 400, PointY + i * 50);
else
g.DrawString(listLyric1[i].lyrics, new Font("微软雅黑", 14), Brushes.White, 400, PointY + i * 50);
}
}
}
double position;
//时钟:不停调用刷新主窗口
private void timer1_Tick(object sender, EventArgs e)
{
//获取当前歌曲播放时间
position = media.Ctlcontrols.currentPosition;
int a = (int)position;
int m = a / 60;
int s = a % 60;
time1.Text = m.ToString();
time2.Text = s.ToString();
PointY-=1;
for (int i = 0; i < listLyric.Count-1; i++)
{
double b = listLyric[i].tosecond;
double c = listLyric[i+1].tosecond;
// int positioni = (int)position;
if (position > b && position < c)
current = i;
}
this.Invalidate(UpdateRect);
}
Rectangle UpdateRect;
//主窗口刷新
private void mainForm_Load(object sender, EventArgs e)
{
UpdateRect = new Rectangle(0, 0, this.ClientSize.Width,
this.ClientSize.Height - panel1.Height);
}
···
还有一个功能是包含在上面代码里的
那就是歌曲总时间与现在时间的显示,这个的话现在时间直接读取来的时间通常是以秒为单位,我们为了显示更加直观,将其换算为正常的分与秒,总时间就采取直接显示原来的字符串形式
···
position = media.Ctlcontrols.currentPosition;
int a = (int)position;
int m = a / 60;
int s = a % 60;
time1.Text = m.ToString();
time2.Text = s.ToString();
string a = media.currentMedia.durationString;
stime.Text = a;
···
最后呢就是进度条怎么来的
这个我用了两个panel,不同的宽度,不同的颜色,通过在timer里调用增加蓝色panel的长度实现,这个我们要用到音频文件总时间,从而计算出单位timer时间里长度伸展多少,来实现进度条的功能
····
private void timer2_Tick(object sender, EventArgs e)
{
a = media.currentMedia.durationString;
int timm = int.Parse(a.Substring(1,1));
int tims = int.Parse(a.Substring(3,2));
int tim = timm * 60 + tims;
sizex += (610/ tim);
if(sizex<610&& isplaying==true)
{
going.Size = new Size(sizex, 10);
}
}
···
总体就这样啦,不过,很多地方可能都没说明,例如我是额外封装了一个类 Lyric1的、还多写了一个打开歌曲的通道,以及用tick判断打开形式;上面涉及到的当前歌词变大变色也没详细说明… … 代码贴在下面,大家自己读好了
代码
···
//Lyric1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace kuwo
{
class Lyric1
{
public int minute;
public int second;
public int tosecond;
public string lyrics;
}
}
//Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace kuwo
{
public partial class mainForm : Form
{
List<Lyric1> listLyric = new List<Lyric1>();
List<Lyric1> listLyric1 = new List<Lyric1>();
int tick = 0;
public mainForm()
{
InitializeComponent();
}
Point downpoint;
Point movepoint;
bool ismoving;
//实现鼠标控制窗口移动(1)
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
downpoint = e.Location;
ismoving = true;
}
private void timermove_Tick(object sender, EventArgs e)
{
}
//实现鼠标控制窗口移动(2)
private void mainForm_MouseMove(object sender, MouseEventArgs e)
{
if (ismoving == true)
{
movepoint = e.Location;
this.Location = new Point(
this.Location.X + (movepoint.X - downpoint.X),
this.Location.Y + (movepoint.Y - downpoint.Y)
);
}
}
//鼠标按键抬起窗口停止移动
private void mainForm_MouseUp(object sender, MouseEventArgs e)
{
ismoving = false;
}
bool isplaying = true;
string a;//歌曲总时间(字符串)
//点击播放:加载歌词
private void start_Click(object sender, EventArgs e)
{
if (tick == 0)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "mp3音乐|*.mp3|mp4音乐|*.mp4|flac文件|*.flac";//设置文件过滤,使之只能打开.mp3/.mp4/flac三种格式的音频文件
ofd.ShowDialog();
string fileName = ofd.FileName;
media.URL = fileName;
media.Ctlcontrols.play();
// start_Click(object sender, EventArgs e);
timer2.Enabled = true;
}
tick = 1;
timer1.Enabled = true;
Encoding encode = Encoding.GetEncoding("GB2312");
FileStream fs = new FileStream("陈一发儿-童话镇.lrc", FileMode.Open);
StreamReader sr = new StreamReader(fs, encode);
string s = sr.ReadLine();
//int xPos = 100;
int yPos = 50;
string a= media.currentMedia.durationString;
stime.Text = a;
while (s != null)
{
s = sr.ReadLine();
if(s==null)
{
break;
}
if (s.Equals(""))
{
continue;
}
Lyric1 lyric =new Lyric1();
lyric.minute =int.Parse(s.Substring(1,2));
lyric.second = int.Parse(s.Substring(4,2));
lyric.lyrics = s.Substring(10);
lyric.tosecond = lyric.minute * 60 + lyric.second;
//if(s.Substring(10)==null)
//{
// lyric.sminute = Convert.ToInt32(s.Substring(1, 1));
//lyric.ssecond = Convert.ToInt32(s.Substring(5, 1));
// }
listLyric1.Add(lyric);
yPos += 30;
}
if (isplaying)
{
start.BackgroundImage = Properties.Resources.play_circle_o;
isplaying = false;
media.Ctlcontrols.pause();
timer1.Enabled = false;
//"C#openfiledialog 设置文件过滤"
}
else
{
start.BackgroundImage = Properties.Resources.pause_circle_o;
isplaying = true;
media.Ctlcontrols.play();
timer1.Enabled = true;
}
fs.Close();
sr.Close();
}
//打开本地资源
private void startplay_Click(object sender, EventArgs e)
{
tick = 2;
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "mp3音乐|*.mp3|mp4音乐|*.mp4|flac文件|*.flac";//设置文件过滤,使之只能打开.mp3/.mp4/flac三种格式的音频文件
ofd.ShowDialog();
string fileName = ofd.FileName;
media.URL = fileName;
media.Ctlcontrols.play();
// start_Click(object sender, EventArgs e);
timer2.Enabled = true;
timer1.Enabled = true;
Encoding encode = Encoding.GetEncoding("GB2312");
FileStream fs = new FileStream("陈一发儿-童话镇.lrc", FileMode.Open);
StreamReader sr = new StreamReader(fs, encode);
string s = sr.ReadLine();
// int xPos = 100;
int yPos = 50;
string a = media.currentMedia.durationString;
stime.Text = a;
while (s != null)
{
s = sr.ReadLine();
if (s == null)
{
break;
}
if (s.Equals(""))
{
continue;
}
Lyric1 lyric = new Lyric1();
lyric.minute = int.Parse(s.Substring(1, 2));
lyric.second = int.Parse(s.Substring(4, 2));
lyric.lyrics = s.Substring(10);
lyric.tosecond = lyric.minute * 60 + lyric.second;
//if(s.Substring(10)==null)
//{
// lyric.sminute = Convert.ToInt32(s.Substring(1, 1));
//lyric.ssecond = Convert.ToInt32(s.Substring(5, 1));
// }
listLyric.Add(lyric);
yPos += 30;
}
fs.Close();
sr.Close();
}
//绘画
Graphics g;//绘图对象
int PointY=140;
int current;
//主窗口绘制歌词
private void mainForm_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
if (tick == 2)
{
for (int i = 0; i < listLyric.Count; i++)
{
if (i == current)
g.DrawString(listLyric[i].lyrics, new Font("微软雅黑", 17), Brushes.LightBlue, 400, PointY + i * 50);
else
g.DrawString(listLyric[i].lyrics, new Font("微软雅黑", 14), Brushes.White, 400, PointY + i * 50);
}
}
else
{
for (int i = 0; i < listLyric1.Count; i++)
{
if (i == current)
g.DrawString(listLyric1[i].lyrics, new Font("微软雅黑", 17), Brushes.LightBlue, 400, PointY + i * 50);
else
g.DrawString(listLyric1[i].lyrics, new Font("微软雅黑", 14), Brushes.White, 400, PointY + i * 50);
}
}
}
double position;
//时钟:不停调用刷新主窗口
private void timer1_Tick(object sender, EventArgs e)
{
//获取当前歌曲播放时间
position = media.Ctlcontrols.currentPosition;
int a = (int)position;
int m = a / 60;
int s = a % 60;
time1.Text = m.ToString();
time2.Text = s.ToString();
PointY-=1;
for (int i = 0; i < listLyric.Count-1; i++)
{
double b = listLyric[i].tosecond;
double c = listLyric[i+1].tosecond;
// int positioni = (int)position;
if (position > b && position < c)
current = i;
}
this.Invalidate(UpdateRect);
}
Rectangle UpdateRect;
//主窗口刷新
private void mainForm_Load(object sender, EventArgs e)
{
UpdateRect = new Rectangle(0, 0, this.ClientSize.Width,
this.ClientSize.Height - panel1.Height);
}
int sizex = 42;
private void timer2_Tick(object sender, EventArgs e)
{
a = media.currentMedia.durationString;
int timm = int.Parse(a.Substring(1,1));
int tims = int.Parse(a.Substring(3,2));
int tim = timm * 60 + tims;
sizex += (610/ tim);
if(sizex<610&& isplaying==true)
{
going.Size = new Size(sizex, 10);
}
}
//点击播放
private void lyricstart_Click(object sender, EventArgs e)
{
// tick = 1;
if (timer1.Enabled == true)
timer1.Enabled = false;
else
timer1.Enabled = true;
}
}
}
···