使用C# WPF写的哦,写看成果:
第一步:首先把要实现的功能写出来,就用PS简单画了个界面
第二步:分析一下每个功能是怎样实现的:
项目二: 音乐播放器
基本功能: 歌曲列表、上一曲、下一曲、暂停、重播
扩展功能:自动下一曲、歌词显示、播放进度选择
支持的音频格式:
WAV;MP3
功能:打开音乐
1.加入播放列表
2.找同目录下歌词
3.开始播放
功能:暂停、播放
1.无文件时,打开文件
2.播放时,修改为(暂停)、开始timer
3.暂停时,修改为(播放)、停止timer
功能:重播
1.调用方法
功能:上一曲、下一曲
1.调用方法
功能:自动下一曲
1.添加一个事件,播放完成后调用
2.判断checkbox是否勾选
3.判断当前文件在列表中的位置
4.有下一曲? 播放下一曲
5.否则,什么也不做
功能:显示歌词
1.是否有歌词文件.是否有歌手图片
2.正则匹配,把能读取的读进来
3.Timer,检查播放进度
4.显示歌词,显示歌手写真
正则:
(?<=^\[)(\d+:\d+\.\d+).(.+)(?=$)
(?<=^)(\[\d+:\d+\.\d+).(.+)(?=$)
[*]功能:音量调节
1.API。。。...OK
控件:进度条
1.拖动 --> 改变进度...OK
2.事件 --> 更新进度...OK
3.没有文件时锁定.
控件:播放列表
1.双击 --> 播放...OK
2.右键 --> 添加...OK
3.右键 --> 删除...OK
好了,实现代码如下:
界面代码:
<Window x:Class="Player.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="风车播放器 bete1" Height="650" Width="825" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100" Width="315"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="120"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<MediaElement Name="mediaelement" Visibility="Hidden" LoadedBehavior="Manual" />
<!--写控件-->
<Canvas>
<TextBlock Canvas.Left="32" Canvas.Top="13" Height="23" Name="txt_title" Text="Follow your heart~Listening~~" Width="233" TextAlignment="Center" />
<Slider Canvas.Left="9" Canvas.Top="43" Name="sd_pos" Width="266" Maximum="100" SmallChange="1" PreviewMouseLeftButtonDown="sd_pos_ui_MouseDown" PreviewMouseLeftButtonUp="sd_pos_ui_MouseUp" IsMoveToPointEnabled="False" />
<Slider Canvas.Left="281" Canvas.Top="6" Height="70" Name="sd_vol" Orientation="Vertical" Value="5" ValueChanged="sd_vol_ValueChanged" />
<Button Canvas.Left="125" Canvas.Top="65" Content="Play" Height="35" Name="btn_play" Width="52" Click="btn_play_Click" />
<Button Canvas.Left="183" Canvas.Top="77" Content="重播" Height="23" Name="btn_reset" Width="34" Click="btn_reset_Click" />
<Button Canvas.Left="214" Canvas.Top="77" Content="下一曲" Height="23" Name="btn_next" Width="51" Click="btn_next_Click" />
<Button Canvas.Left="32" Canvas.Top="77" Content="上一曲" Height="23" Name="btn_prev" Width="51" Click="btn_prev_Click" />
<CheckBox Canvas.Left="89" Canvas.Top="81" Height="16" Name="cb_continue" Width="30" >
<Ellipse Height="10" Width="10" Stroke="Black" StrokeThickness="2" ></Ellipse>
</CheckBox>
<CheckBox Canvas.Left="281" Canvas.Top="84" Height="16" Name="ck_vol" Width="25" Click="ck_vol_Click" IsThreeState="False" ClickMode="Release" ClipToBounds="False" Focusable="False" >
<Ellipse Height="10" Width="10" Stroke="Black" ></Ellipse>
</CheckBox>
<TextBlock Canvas.Left="175" Canvas.Top="101" Height="17" Name="txt_starttime" Text="" TextAlignment="Right" Width="138" />
</Canvas>
<!--文件列表-->
<DockPanel Grid.Row="1" LastChildFill="True">
<ToolBar DockPanel.Dock="Top">
<Button Name="btn_open" Click="btn_open_Click">添加</Button>
<Button Name="btn_del" Click="btn_del_Click">删除</Button>
<Button Name="btn_start" Click="btn_start_Click">播放</Button>
<Button Name="btn_loadlrc" Click="btn_loadlrc_Click">加载歌词</Button>
</ToolBar>
<ListBox Name="lb_list" DisplayMemberPath="Filename" Grid.Row="1" MouseDoubleClick="btn_start_Click">
<ListBox.ContextMenu>
<ContextMenu >
<MenuItem Header="添加" Click="btn_open_Click" />
<MenuItem Header="删除" Click="btn_del_Click" />
<MenuItem Header="播放" Click="btn_start_Click" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</DockPanel>
<!--右侧歌词-->
<Grid ClipToBounds="True" Margin="20,50,20,50" Grid.Column="1" Grid.Row="1">
<TextBlock ClipToBounds="False" Name="tb_lyric_old" TextAlignment="Center" TextWrapping="WrapWithOverflow" FontWeight="Bold" FontSize="18" VerticalAlignment="Top" ></TextBlock>
<TextBox Grid.Column="1" Grid.Row="1" ClipToBounds="False" Name="tb_lyric" TextAlignment="Center" TextWrapping="WrapWithOverflow" FontWeight="Bold" FontSize="18" VerticalAlignment="Top" Foreground="DarkGreen"></TextBox>
</Grid>
<Rectangle Grid.Column="1" Grid.Row="1">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White" Offset="0" />
<GradientStop Color="White" Offset="1" />
<GradientStop Color="Transparent" Offset="0.475" />
<GradientStop Color="#C8FEFEFE" Offset="0.375" />
<GradientStop Color="#C8FFFFFF" Offset="0.575" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<!--分割线-->
<!--<GridSplitter Grid.Column="0" Grid.Row="1" Width="3" Background="Gray" />-->
</Grid>
</Grid>
</Window>
C#代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using Microsoft.Win32;
using System.Windows.Threading;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Media.Animation;
namespace Player
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
#region 保存文件信息用结构
class finfo
{
public finfo(string name, string path) { Filename = name; Filepath = path; }
public string Filename { set; get; }
public string Filepath { set; get; }
public List<lyricinfo> Lyric = new List<lyricinfo>();
}
class lyricinfo
{
public TimeSpan time;
public string lrc;
}
#endregion
//定义绑定用的List
BindingList<finfo> list = new BindingList<finfo>();
//定义Timer
DispatcherTimer g_timer = new DispatcherTimer();
//全局变量,是否暂停
bool g_IsPause = true;
//全局变量,当前曲目序号
int g_index = -1;
public MainWindow()
{
InitializeComponent();
//绑定列表
lb_list.ItemsSource = list;
//绑定更新进度条的Timer
g_timer.Interval = new System.TimeSpan(10);
g_timer.Tick += new EventHandler(Progress_timer_Tick);
//绑定音频结束时的事件
mediaelement.MediaEnded += new RoutedEventHandler(mediaelement_MediaEnded);
}
//移动歌词
private void MoveLyric()
{
//TranslateTransform mv = new TranslateTransform(0, tb_lyric.RenderTransform.Value.OffsetY - CalcY());
//DoubleAnimation dbanimat= new DoubleAnimation();
//dbanimat.By = -10; //移动的大小
//dbanimat.Duration = new System.Windows.Duration(TimeSpan.FromSeconds(0.5));
//tb_lyric.RenderTransform = mv; //绑定控件
//mv.BeginAnimation(TranslateTransform.YProperty, dbanimat);
tb_lyric.ScrollToLine(CalcY()); tb_lyric.LineDown();
}
//计算,歌词移动的Y坐标
private int CalcY()
{
try
{
int i = 0;
for (i = 1; i < list[g_index].Lyric.Count; ++i)
{
TimeSpan lytime = list[g_index].Lyric[i].time;
TimeSpan pos = mediaelement.Position;
double diff = lytime.TotalSeconds / 10 - pos.TotalSeconds;
if (lytime.CompareTo(pos) > 0) break;
}
return i;
}
catch
{
return 0;
}
}
//读取lrc文件
private void ReadLyric(ref finfo f, string filelyric)
{
string lrc = File.ReadAllText(filelyric, System.Text.Encoding.GetEncoding("GB2312"));
Regex rx = new Regex(@"(?<=^\[)(\d+:\d+\.\d+).(.+)(?=$)", RegexOptions.Multiline);
//匹配表达式
foreach (Match x in rx.Matches(lrc))
{
try
{
//读取时间
TimeSpan ti = new TimeSpan(0, int.Parse(x.Value.Substring(0, 2)),
int.Parse(x.Value.Substring(3, 2)));//int.Parse(x.Value.Substring(6, 2))
//读取歌词
string ly = x.Value.Substring(9);
f.Lyric.Add(new lyricinfo() { time = ti, lrc = ly });
}
catch
{
//continue;
}
}
}
//设置UI
private void SetUI(bool start)
{
//start==true,设为播放状态
//start==false,设为暂停
//if (!mediaelement.HasAudio) return;//没有音频时不执行代码
g_timer.IsEnabled = start; //设置Timer
btn_play.Content = start ? "Pause" : "Play"; //设置按钮标题
g_IsPause = !start; //设置全局标记:[是否暂停中]
}
//设置播放信息,并播放文件
private void SetSource()
{
//取文件信息
var obj = lb_list.SelectedItem as finfo;
if (obj == null) return;
//打开文件
mediaelement.Source = new Uri(obj.Filepath);
//设置歌词
string lrc = "\n\n\n\n\n\n\n\n\n\n";
if (obj.Lyric.Count > 0)
{
foreach (var x in obj.Lyric) { lrc = string.Concat(lrc + x.lrc + '\n'); }
}
lrc = string.Concat(lrc + "\n\n\n\n\n\n\n\n\n\n");
tb_lyric.Text = lrc;
//设置标题
txt_title.Text = obj.Filename;
//保存当前曲目序号
g_index = lb_list.SelectedIndex;
//开始播放
mediaelement.Play();
//设置界面
SetUI(true);
}
#region 开始、暂停、重播
/// <summary>
/// 播放按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_play_Click(object sender, RoutedEventArgs e)
{
//列表为空时,调用[打开文件]
if (list.Count <= 0) { btn_open_Click(this, null); return; }
//开始或暂停播放
if (g_IsPause) { mediaelement.Play(); }
else { mediaelement.Pause(); }
//设置界面
SetUI(g_IsPause);
}
/// <summary>
/// 重播按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_reset_Click(object sender, RoutedEventArgs e)
{
if (!mediaelement.HasAudio) return;
mediaelement.Stop();
//开始播放
SetUI(true);
mediaelement.Play();
}
#endregion
#region 上一曲、下一曲、自动下一曲
/// <summary>
/// 播放上一曲
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_prev_Click(object sender, RoutedEventArgs e)
{
int index = g_index - 1;
//判断是否有上一曲
if (index >= 0 && index < list.Count)
{
lb_list.SelectedIndex = index;
SetSource();
}
}
/// <summary>
/// 播放下一曲
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_next_Click(object sender, RoutedEventArgs e)
{
int index = g_index + 1;
//判断是否有上一曲
if (index >= 0 && index < list.Count)
{
lb_list.SelectedIndex = index;
SetSource();
}
}
/// <summary>
/// 自动下一曲
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void mediaelement_MediaEnded(object sender, RoutedEventArgs e)
{
if (cb_continue.IsChecked != true) return;
//播放下一曲
btn_next_Click(this, null);
}
#endregion
#region 音量设置
/// <summary>
/// 修改音量
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sd_vol_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
//设置音量
mediaelement.Volume = e.NewValue / 10;
}
/// <summary>
/// 设置静音
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ck_vol_Click(object sender, RoutedEventArgs e)
{
mediaelement.IsMuted = (bool)ck_vol.IsChecked;
}
#endregion
#region 添加、删除、播放、加载歌词
/// <summary>
/// 添加文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_open_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "音频格式(*.mp3,*.wav)|*.mp3;*.wav";
dlg.Multiselect = true;
if (dlg.ShowDialog() != true) return; //不为确定时返回
for (int i = 0; i < dlg.FileNames.Length; ++i)
{
finfo newfile = new finfo(dlg.SafeFileNames[i], dlg.FileNames[i]);
//是否有歌词文件
string filelyric = dlg.FileNames[i].Remove(dlg.FileNames[i].Length - 4) + ".lrc";
//加载歌词
if (File.Exists(filelyric)) { ReadLyric(ref newfile, filelyric); }
//添加到列表
list.Add(newfile);
}
lb_list.SelectedIndex = (list.Count - 1);
if (g_IsPause)
{
//设置并播放文件
SetSource();
}
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_del_Click(object sender, RoutedEventArgs e)
{
int index = lb_list.SelectedIndex;
if (index < 0) return;
//移除选定元素
list.RemoveAt(index);
//如果删除的是当前歌曲,播放下一曲
if (lb_list.SelectedIndex == g_index) btn_next_Click(this, null);
}
/// <summary>
/// 播放文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_start_Click(object sender, RoutedEventArgs e)
{
if (list.Count <= 0) return;
if (mediaelement.HasAudio) mediaelement.Stop();
SetSource();
}
/// <summary>
/// 添加歌词文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_loadlrc_Click(object sender, RoutedEventArgs e)
{
if (list.Count <= 0) return;
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "歌词文件(*.lrc)|*.lrc";
if (dlg.ShowDialog() != true) return;
//打开歌词文件
finfo gfifo = list[g_index];
ReadLyric(ref gfifo, dlg.FileName);
//设置歌词
string lrc = "\n\n\n\n\n\n\n\n\n\n";
if (gfifo.Lyric.Count > 0)
{
foreach (var x in gfifo.Lyric) { lrc = string.Concat(lrc + x.lrc + '\n'); }
}
lrc = string.Concat(lrc + "\n\n\n\n\n\n\n\n\n\n");
tb_lyric.Text = lrc;
}
#endregion
#region 进度条
/// <summary>
/// 计时器,更新进度条
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Progress_timer_Tick(object sender, EventArgs e)
{
//得到播放进度
if (!mediaelement.HasAudio) return;
try
{
TimeSpan ts = mediaelement.Position;
TimeSpan max = mediaelement.NaturalDuration.TimeSpan;
//计算进度百分比
double pos = ts.TotalSeconds / max.TotalSeconds * 100;
//格式化字符串
string timepos = string.Format("{0}/{1}", ts.ToString("hh':'mm':'ss"), max.ToString("hh':'mm':'ss"));
//更新进度
sd_pos.Value = pos;
txt_starttime.Text = timepos;
//显示歌词
if (list[g_index].Lyric.Count > 0) MoveLyric();
}
catch
{
//MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 拖动进度条,改变文件进度,处理鼠标按下和弹起事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sd_pos_ui_MouseDown(object sender, MouseButtonEventArgs e)
{
g_timer.IsEnabled = false;
}
private void sd_pos_ui_MouseUp(object sender, MouseButtonEventArgs e)
{
if (!mediaelement.HasAudio) return;
//计算相应时间
TimeSpan max = mediaelement.NaturalDuration.TimeSpan;
double per = sd_pos.Value / 100;
TimeSpan pos = TimeSpan.FromSeconds(max.TotalSeconds * per);
//设置进度
mediaelement.Position = pos;
g_timer.IsEnabled = true;
}
#endregion
}
}