深入学习TimeSpan
一、文件操作常用相关类
File //操作文件,静态类,对文件整体操作。拷贝,删除,剪切等
Directory //操作目录(文件夹),静态类
Path //对文件或目录的路径进行操作(很方便),字符串
Stream //文件流。抽象类
FileStream //文件流。MemoryStream(内存流),NetworkStream(网络流)
StreamReader //快速读取文本文件
StreamWriter //快速写入文本文件
1、神奇的Dictionary
Dictionary<string,string>性能测试中,为什么速度快?
Dictionary中有一个存储键值对的区域,这个区域的每个存储单元有地址编号,根据
hashCode算法,计算key的值的键值对应该存储的地址,将键值对放入指定的地址即可.
查找的时候首先计算key的地址,就可以找到数据了。
即:根据key直接房间号,而不是逐个房间找.
当把一个KeyValuePair采用一个固定算法(散列算法)根据key来计算这个KeyValuePair
存储的地址。取的时候也是根据要找的key可以快速算出kvp存放的地址。
2、Path类(对字符串的操作)
玩的就是字符串,本身路径,文件名,扩展名,没有发生改变。
using System.IO;
string ChangeExtension(string path,string extension) 修改文件的后缀名.
修改支持字符串层面的,没有真的给文件改名。
string s=Path.ChangeExtension(@"C:\temp\F3.png","jpg")
string Combine(string path1,string path2) 将两路径合并成一个路径。
比+好用,可以方便解决中间不加斜线的问题,自动处理分隔符。
string s=Path.Combine(@"C:\temp","a.jpg");//自动添加\
string GetDirectoryName(string path) 获取路径(除驱动器外,最后无\)
string s=Path.GetDirectoryName(@"C:\temp\a.jpg");
string GetExtension(string path) 获取扩展名(带点号,如.txt)
string GetFileName(string path) 获取文件名部分(不带路径)
string GetFileNameWithoutExtension(string path)获取不带扩展名的文件名
string GetFullPath(string path) 取得文件的全路径。可由相对路径获取绝对路径。
string p1 = Path.GetFullPath(@"1.txt");
//D:\OneDrive\CSharp\Test\Test\bin\Debug\1.txt
string p2 = Path.GetFullPath(@"\1.txt");
//D:\1.txt
相对路径由程序的位置确定:
1)前面没有\,则直接使用程序当前路径。如1.txt,1\1.txt等.
2)前面有\,则直接使用当前驱动器.如\1.txt,\1\1.txt等.(D:\1.txt,D:\1\1.txt)
Path.Combine(string path1,string path2)
如果路径之一是零长度字符串,则该方法返回其他路径。如果path2包含绝对路径,
则该方法返回path2.
如果path1不是以分隔符结束,并且不是C:或D:等驱动器引用,则自动在串联前为
path1增加\分隔符。
分隔符:与操作系统平台有关:
Path.DirectorySeperatorChar是\
Path.PathSEparator是;
Path.ValumeSeparatorChar是:
Path.GetFileName() 获取文件名
当目录为C:\windows\test时,可获取最后一个目录名,但是当目录路径为C:\windows
\test\时,不可以。reflector查看。
获取当前exe文件执行的路径:
1)assembly.GetExecutingAssembly().Location;//全路径文件名,全适用
2)Appication.StartPath;//仅路径无文件名。适用winform
3)AppDomain.CurrentDomain.BaseDirectory;//仅路径无文件名。全适用.
不要用: Directory.GetCurrentDirectory();//获取应用程序的当前工作目录。
因为这个可能会变,通过使用OpenFileDialog或者我去设置
Directory.SetCurrentDirectory();
这样当前程序目录可能就不是正在使用的目录。
上面常应用于WinForm程序。
3、File类
File.Create(string path);
File.Delete(string path);删除指定文件。若不存在不异常。但只读/正在使用则异常
File.Copy(string src, string des);(重载第3参true表示覆盖)
File.Move(string src, string des);
File.ReadAllBytes(string path); 返回字节数组.(修改字节数组长度为内容长度)
File.ReadAllLines(string path); 返回字串数组
File.ReadAllText(string path); 返回全部文本文件中的字符.
上面三个读完,关闭文件。不用人工再关.
一次性读取,费资源,适用于小文件。大文件用FileStream
File.ReadLines(string path); 返回集合
File.Exists(string path) 判断文件是否存在.返回bool
byte[] buffer = new byte[1024];
buffer = File.ReadAllBytes(@"E:\1.txt");
string s = Encoding.UTF8.GetString(buffer);
Console.WriteLine(buffer.Length);//30内容长度,不再是1024
Console.WriteLine(s);//内容
或者改成下面:
byte[] b= File.ReadAllBytes(@"E:\1.txt");
string s = Encoding.UTF8.GetString(b);//解码全部.GetString(b,1,4)
Console.WriteLine(s);//内容
编码:把字符串以怎样的形式存储为二进制。ASC,GBK
File.WriteAllBytes(string path, byte[] bytes);
File.WriteAllText(string path, string contents);
File.WriteAllLines(string path, string[] contents);
上面写入都是覆盖式,操作完成后自动关闭.
File.WriteAllLines(@"E:\4.txt", new string[4], Encoding.UTF8);//写入四个回车
File.AppendAllLines(string path, IEnumerable<string>contents); //按行
File.AppendAllText(string path, string contents);
下面用得比较少,都是返回的是流:
File.CreateText,File.AppendText,File.OpenText
一般用StreamReader或StreamWriter即可。
技巧:注意看智能提示中方法的返回类型,即可确定大概的使用方向。
string p = @"E:\4.txt";
if (!File.Exists(p))
{
using (StreamWriter sw = File.CreateText(p))
{
sw.Write("第一次写入");
sw.WriteLine("再写入一行");//与上面紧贴
sw.WriteLine("这才是第二行");
}
}
using (StreamWriter sw = File.AppendText(p))
{
sw.Write("紧贴第二行");
sw.Write('\n');
sw.WriteLine("进入第三行");
}
using (StreamReader sr = File.OpenText(p))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
用File类快速得到文件流的还有:
FileStream fs=File.Open();//返回FileStream
FileStream fs=File.OpenRead();//返回只读FileStream
FileStream fs=File.OpenWrite();//返回只读FileStream
上面都可以用下面替代:
FileStream fs=new FileStream(参数)
Stream是所有流的父类,是一个抽象类。
文件操作的类都在System.IO.*;
ReadLines和ReadAllLines方法的区别:
当你使用ReadLines时,你可以在整个字符串集合被返回之前开始枚举该集合;
当你使用ReadAllLines时,你必须等待整个字符串数组被返回之后才能访问该数组。
因此,当你处理非常大的文件时,ReadLines会更有效率。
你可以使用ReadLines方法来做以下事情:
1)在一个文件上执行LINQ to Objects查询,以获得其行的过滤集合。
2)用File.WriteAllLines(String, IEnumerable<String>)方法将返回的行集合写入文件,
或者用File.AppendAllLines(String, IEnumerable<String>)方法将它们追加到现有文件中。
3)创建一个立即填充的集合实例,该集合的构造函数需要一个IEnumerable<T>的字符串集合,
例如IList<T>或Queue<T>。
该方法使用UTF8作为编码值。
例子:获取指定目录(含子目录)下所有txt文件中含"x"字符的行。
private static void Main(string[] args)
{
try
{
string docPath = @"E:\BaiduNetdiskDownload";
var files = from file in Directory.EnumerateFiles(docPath, "*.txt", SearchOption.AllDirectories)
from line in File.ReadLines(file)
where line.Contains("x")
select new
{
File = file,
Line = line
};
foreach (var f in files)
{
Console.WriteLine($"{f.File}\t{f.Line}");
}
Console.WriteLine($"{files.Count().ToString()} files found.");
}
catch (UnauthorizedAccessException uAEx)
{
Console.WriteLine(uAEx.Message);
}
catch (PathTooLongException pathEx)
{
Console.WriteLine(pathEx.Message);
}
Console.ReadKey();
}
4、Directory类
创建文件夹
Directory.CreateDirectory(string path) 创建文件夹.末尾与是否有\无关.
Directory.Delete(string path) 删除文件夹。
1)无该文件夹时,会异常。用下面判断,
Directory.Exists(string path) //存在目录为真,否则为假
2)该文件夹内有文件或子目录时会异常。确实要删除。用下面第二参数为真:
Directory.Delete(string path, bool recursive)
Directory.Move(string src,string des) 将源目录(含文件及子目录)移动到目标目录
Directory.GetFiles(string p[,string sPattern[,SearchOption sOption]])
返回指定目录中的文件(含路径)的数组。
1)第二参数指定过滤。例如:"*.txt"指明返回文本文件.
2)第三参数指定是否包含子目录文件文件,否则仅当前目录。
指定过滤的通配符SearchPattern为:
*(星号) 该位置零个或多个字符。
?(问题) 该位置恰好是一个字符。
注意路径path不区别大小写.
系统文件夹的指定:
获取我的文档目录。参数为枚举,
string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
参数Environment.SpecialFolder.MyDocuments,枚举类型,其中Mydocument指
的是“我的文档”,类似有:
CommonProgramFilesX86 “Program Files”文件夹。
Cookies 用作 Internet Cookie 的公共储存库的目录。
Fonts 包含字体的虚拟文件夹。
ProgramFilesX86 x86 “Program Files”文件夹。
Programs 包含用户程序组的目录。
MyMusic “我的音乐”文件夹。
MyPictures “我的图片”文件夹。
...
方法Environment.GetFolderPath是获取对应目录。
5、流
FileStream操作的是字节。
StreamReader与StreamWriter操作的是字符。
对于字符最好的操作用本类,对于中文,一个字节无法显示什么,但对字符可以
显示出中文
下面显示6个汉字转为utf-8编码,共18个字节,因此一个字节无法显示什么内容。
string p = @"E:\4.txt";
using (FileStream fs = new FileStream(p, FileMode.OpenOrCreate, FileAccess.Write))
{
byte[] b = Encoding.UTF8.GetBytes("常练常记常乐");
fs.Write(b, 0, b.Length);
}
using (FileStream fs = new FileStream(p, FileMode.Open, FileAccess.Read))
{
byte[] b = new byte[1];
int n, m = 0;
do
{
n = fs.Read(b, 0, b.Length);
if (n == 0)
{
break;
}
Console.WriteLine(b[0]);
m++;
} while (n > 0);
Console.WriteLine(m);//18
}
Stream把所有内容当成二进制来看待,如果是文本内容,则需要程序员来处理文本和
二进制之间的转换。
用StreamWriter是辅助Stream进行处理的。
StreamWriter是辅助Stream进行处理的
string p = @"E:\4.txt";
Stream s = File.OpenRead(p);
using (StreamReader sr = new StreamReader(s, Encoding.UTF8))
{
Console.WriteLine(sr.ReadLine());//第一行
Console.WriteLine(sr.ReadToEnd());//第二行到最后
}
由上可知:
ReadToEnd 从当前位置读到最后。内容大的话会占内存,每次调用都往下走,不能
无意中调用两次。
ReadLine 读取一行。如果到了末尾,返回null
注意:文件流有一个游标,表示当前在流的位置,当读取一次,游标对应移动。
创建流的几种方法:file有6种,还有:
练习:对职工工资文件处理,所有人工资加倍.
原文件:
马大哈|3000
宋江|8000
韩立|9000
白话魔法师|4000
string p = @"E:\4.txt";
using (StreamWriter sw = new StreamWriter(File.OpenWrite(p), Encoding.UTF8))
{
sw.WriteLine("马大哈|3000");
sw.WriteLine("宋江|8000");
sw.WriteLine("韩立|9000");
sw.WriteLine("白话魔法师|4000");
}
string[] s = File.ReadAllLines(p);
for (int i = 0; i < s.Length; i++)
{
if (s[i].Contains("|"))//防止非工资条进入而异常
{
string[] s2 = s[i].Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
s[i] = s2[0] + "|" + int.Parse(s2[1]) * 2;
}
}
File.WriteAllLines(p, s);
注意:流的的写入是覆盖式,但它是内容的覆盖式,不是文件的覆盖式。
比如原文件长度是30,如果写入长度是20,则覆盖的是内容中前面
长度20的内容,后面的10个长度内容是原样。
using语句
1)不是任何类型的对象都可以写在using()的小括号里。
2)只有实现了IDisposable接口的类型的对象,才能写在using小括号里.
3)当using{}执行完毕时,会自动调用对象的Dispose()方法来释放资源。
二、对象序列化(二进制序列化)
对象序列化是将对象(比如Person对象)转换为二进制数据(字节流),反序列化是将二进制
数据还原为对象。
对象是稍纵即逝的,不仅程序重启、操作系统重启会造成对象的消失,就是退出函数范围
等都可能造成对象的消失。
序列化/反序列化就是为了保持对象的持久化。就好像用DV录像(序列化)和用播放器(反序列
化)一样。
对象序列化,只能针对对象的字段进行序列化。
BinaryFomatter类有两个方法:
void Serialize(Stream stream,object graph) 对象graph序列化到stream中
object.Deserialize(Stream stream) 将对象从stream中反序列化,返回值为反
序列化得到的对象。
练习:将几个int,字符串添加到ArrayList中,然后序列化到文件中,再反序列化回来。
不是所有对象都能序列化,只有可序列化的对象才能序列化。
在类添加[Serializeble],对象的属性、字段的类型也必须可序列化。
关于二进制序列化需要注意的事项:
1)要序列化的类型必须标记为:[Serializable]
2)该类型的父类也必须标记为:[Serializable]
3)该类型中的所有成员的类型也必须标记为:[Serializable]
4)序列化只会对类中的字段序列化。(只能序列化一些状态信息)
为什么要序列化?
将一个复杂的对象转换流,方便我们的存储与信息交换。
序列化的步骤:
1)创建一个二进制序列化器(BinaryFormatter);
2)创建文件流
3)bf.Serialize(stream,对象)
反序列化的步骤
1)创建一个二进制序列化器(BinaryFormatter);
2)创建文件流;
3)执行反序列化。object obj=bf.Deserialize(stream);
注意:反序列化返回类型是object,所以要进行类型转换
练习:序列化一个对象,保存到文件中。再读出到另一个对象中。
private static void Main(string[] args)
{
Student s = new Student();
s.Name = "韩立"; s.Age = 1000; s.Gender = '男';
string p = @"E:\4.txt";
using (FileStream fs = new FileStream(p, FileMode.OpenOrCreate, FileAccess.Write))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, s);
}
Student s1;
using (FileStream fs = new FileStream(p, FileMode.Open, FileAccess.Read))
{
BinaryFormatter bf = new BinaryFormatter();
s1 = (Student)bf.Deserialize(fs);
}
Console.WriteLine(s.Name + "-" + s.Age);
Console.ReadKey();
}
[Serializable]
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public char Gender { get; set; }
}
三、练习项目:播放器
添加Windows Media Player到组件,项目中要使用这个组件。
如何给工具箱添加新的控件或组件:
建立一个winForm项目,切换到窗体界面,对左侧工具箱的"组件"右击,选择“选择
项”.稍等几秒,加载完成。切换到"COM组件"标签,向下查找到"Windwos Media
Player",选择它.
这样Windows Media Player组件就被添加到工具箱的“组件”栏中。如果是对"打印"
右击添加的,则控件或组件会添加到“打印”栏中。已经添加的控件或组件,选中它,左
键按住不动,拖拽到其它栏松开鼠标,可将控件或组件移动到目标栏中。
Windows Media Player属性
Url 歌曲的地址或目录
一些方法
musicPlay.Ctlcontrols 控制相关
musicPlay.Ctlcontrols.Play() 播放。类似有,Pause()暂停,Stop()停止,Next()下一曲
Previous上一曲,PlayItem
musicPlay.Ctlcontrols.currentItem 类似的有: currentPosition,CurrentPositionString
musicPlay.settings.autoStart 设置控制是否自动开始播放(bool)
它只能设置在开始,然后有了url才生效。若已经在播放了,该设置失效无用。
listBox可以设置多选。
listBox1.SelectionMode = SelectionMode.MultiExtended;//多选有两咱,这里用扩展
多选后,listBox1.SelectedIndex为第一个按下鼠标选择的项。(可能在选定范围的开始
或者结尾)
多选的范围的索引在集合listBox1.SelectedIndices中。比如,选定第3项到第8项,那么这
个集合就是{2,3,4,5,6,7}。如果从上向下拖动选定,则listBox1.SelectedInex为2;如果
是从下向上拖动选定的上面范围,则listBox1.SelectedIndex为7.
注意:无论从上往下选择,还是从下向上选择,listBox1.SelectedIndices集合的排列
顺序都是从小到大。
contextMenuStrip1绑定到相关控件(属性ContextMenuStrip)中,两者产生关联,右击将
弹出这个菜单。通过contextMenuStrip1.Items[0].Enabled = false;定位设置相关属性。
标签自适应图片,没找到,自己用属性适应。
思路:让label1属性AutoSize设置为false,即人为手工来设置大小,不自动。
然后让label1的大小与图片的大小刚好相等。
label1.Size = label1.Image.Size;
对于显示图片,没有文字的标签无法判断是什么图片。
两个或多个图片,可以用label1.tag来设置标签,判断是什么图片。这时可以把tag
当作是text来对待。
为了统一控制,很多方法可以直接调用控制的事件,比如btnPlay.Click事件,在代码中
用btnPlay.PerformClick()来代码。其实也可以写成单独的方法,来统一调用,这里直接
用控件的事件中代码。
播放中的地址musicPlay.Url如果重新赋值,会从头开始播放。因此设置一个标志b(bool)
只准它使用一次,这样下次点的时候,播放会从暂停处重新开始。这个b会在切换listBox1
的SelectedIndex时会重新为true,因为这表明歌曲发生更改。
添加的歌曲,会在添加时,同步对应到泛型mList中,它与listBox1的序列一一对应。这
样选择歌曲时会用索引对应到泛型中,取得真实的歌曲目录。
上一曲和下一曲,注意判断索引的极限进行加或减,然后调用播放事件。
双击时,比较当前歌曲与选中歌曲是否相同。不同则播放;相同则在播放与暂停间切换。
timer1计时器用来判断播放器状态(播放中,停止,其它)从来决定是否自动下一曲
及显示当前播放的时间。
所有歌曲删除时,所有状态应重置。
显示歌曲:搜索对应的Lrc歌词文件,有则清空原的时间泛型timelist和歌词泛型lrclist
.将原歌词拆分后有效部分(时间与歌词)添加到上面两个集合中。同时重置索引,开启
tmer2,逐个与timeList[index]比较,大于就显示歌曲。歌曲分成五句,逐个滚动显示,注
意,索引的限制范围。
为了显示制作痕迹,一些控件就不重命名了。
源代码地址:
由于本人有时也要积分下载,所以上面链接加了积分。
您也可直接由下面代码自己免费制作。
界面:
歌词格式:
代码:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace Play
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<string> mlist = new List<string>();//歌曲集合
private List<double> timeList = new List<double>();//时间集合
private List<string> lrcList = new List<string>();//歌词集合
private bool b = true;//是否第一次进入播放。
private bool bAuto = false;//是否自动播放
private int index = 0;//当前词条索引
private void Form1_Load(object sender, EventArgs e)
{
//禁止程序开打就播放
//musicPlay.URL = @"E:\红枣树.mp3";//不能放前面,状态设置不能控制播放。
musicPlay.settings.autoStart = false;//只能先设置状态,后面才不播放。
//musicPlay.URL = @"E:\红枣树.mp3";
//AxWMPLib.AxWindowsMediaPlayer w=new AxWMPLib.AxWindowsMediaPlayer();
//上句是动态生成组件
//设置listbox多选属性
listBox1.SelectionMode = SelectionMode.MultiExtended;
//播放无效
btnPlay.Enabled = false;
lblMute.Image = Image.FromFile(@"E:\放音.jpg");
lblMute.Size = lblMute.Image.Size;
lblMute.Tag = "放音";
}
private void btnPlay_Click(object sender, EventArgs e)
{
if (listBox1.SelectedIndex == -1) //无歌曲
{
MessageBox.Show("未选定歌曲");
}
else
{
if (b)
{//第一次进入,从头开始播放。否则第二次进入,b为假不需要再用url,继续前面位置播放
musicPlay.URL = mlist[listBox1.SelectedIndex];
ShowLrc(musicPlay.URL);
b = false;
}
if (btnPlay.Text == "播放")
{
musicPlay.Ctlcontrols.play();
btnPlay.Text = "暂停";
}
else
{
musicPlay.Ctlcontrols.pause();
btnPlay.Text = "播放";
}
}
}
private void ShowLrc(string p)//显示歌词
{
//检测歌词文件lrc是否存在
string f = Path.GetFileNameWithoutExtension(p) + ".lrc";
f = Path.Combine(Path.GetDirectoryName(p), f);
if (!File.Exists(f))
{
label1.Text = "";//label1-labe5清空
label2.Text = "";
label3.Text = "无歌词";
label4.Text = "";
label5.Text = "";
return;
}
timeList.Clear();//清空原歌词
lrcList.Clear();
string[] s = File.ReadAllLines(f);
for (int i = 0; i < s.Length; i++)
{
//分割,只要前面三个元素
string[] s1 = s[i].Split(new char[] { '[', ']' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (s1.Length > 1)//只加时间和歌词部分
{
double d = TimeSpan.Parse("00:" + s1[0]).TotalSeconds;//取得时长
timeList.Add(d);
lrcList.Add(s1[1]);
}
}
index = 0; //重置歌词开始
timer2.Enabled = true;//激活歌词显示
}
private void btnStop_Click(object sender, EventArgs e)//停止播放
{
musicPlay.Ctlcontrols.stop();
btnPlay.Text = "播放";
}
private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)//右击删除
{
if (listBox1.SelectedItems.Count == 0)
{
//没有选中,不必删除
}
else if (listBox1.SelectedItems.Count < listBox1.Items.Count)
{
int min = listBox1.SelectedIndices[0];
foreach (int i in listBox1.SelectedIndices)
{
mlist.RemoveAt(i);
listBox1.Items.RemoveAt(i);
}
listBox1.SelectedIndices.Clear();
if (min == 0)
{
listBox1.SelectedIndex = 0;
}
else
{
listBox1.SelectedIndex = min - 1;
}
}
else//全部删除,停止播放
{
listBox1.Items.Clear();
mlist.Clear();
timer2.Enabled = false;
btnPlay.Text = "播放";
bAuto = false;
btnAutoNext.Text = "自动播放";
lblDuration.Text = "显示播放时长";
musicPlay.Ctlcontrols.stop();
btnPlay.Enabled = false;
}
}
private void BtnBrowser_Click(object sender, EventArgs e)//添加歌曲
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = @"E:\音乐";
ofd.Filter = "MP3文件|*.mp3|WAV文件|*.wav";
ofd.Multiselect = true;
if (ofd.ShowDialog() == DialogResult.OK)
{
string[] f = ofd.FileNames;
//listBox1.Items.AddRange(f);//添加到列表
//mlist.AddRange(f);//添加到泛型
for (int i = 0; i < f.Length; i++)
{
mlist.Add(f[i]);
listBox1.Items.Add(Path.GetFileName(f[i]));
}
btnPlay.Enabled = true;
}
}
private void listBox1_MouseClick(object sender, MouseEventArgs e)//右击菜单是否生效
{
if (e.Button == MouseButtons.Right)//右击
{
if (listBox1.Items.Count == 0)//无歌曲
{
contextMenuStrip1.Items[0].Enabled = false;//第一项"右击"失效
}
else
{
contextMenuStrip1.Items[0].Enabled = true;
}
}
else if (e.Button == MouseButtons.Left)//单击
{
if (listBox1.SelectedIndex != -1)
{//已经由双击做起了播放。实际中双击更人性化,单击播放用户操作不便.
}
}
}
private void btnNext_Click(object sender, EventArgs e)//下一曲
{
if (listBox1.SelectedIndex == -1)
{
MessageBox.Show("尚未选定歌曲");
}
else
{
int index = listBox1.SelectedIndex;
index++;
if (index == listBox1.Items.Count)
{
index = 0;
}
listBox1.SelectedIndices.Clear();
listBox1.SelectedIndex = index;
btnPlay.Enabled = true;//激活,上面已经先选定item,下面直接调用播放
btnPlay.Text = "播放";//关键,不然间隔不播放
btnPlay.PerformClick();
}
}
private void btnPre_Click(object sender, EventArgs e)//上一曲
{
if (listBox1.SelectedIndex == -1)
{
MessageBox.Show("尚未选定歌曲");
}
else
{
int index = listBox1.SelectedIndex;
index--;
if (index == -1)
{
index = listBox1.Items.Count - 1;
}
listBox1.SelectedIndices.Clear();
listBox1.SelectedIndex = index;
btnPlay.Enabled = true;
btnPlay.Text = "播放";
btnPlay.PerformClick();
}
}
private void lblMute_Click(object sender, EventArgs e)//静音切换
{
if (lblMute.Tag.ToString() == "静音")
{
musicPlay.settings.mute = false;
lblMute.Image = Image.FromFile(@"E:\放音.jpg");
lblMute.Size = lblMute.Image.Size;
lblMute.Tag = "放音";
}
else
{
musicPlay.settings.mute = true;
lblMute.Image = Image.FromFile(@"E:\静音.jpg");
lblMute.Size = lblMute.Image.Size;
lblMute.Tag = "静音";
}
}
private void button1_Click(object sender, EventArgs e)//音量加
{
musicPlay.settings.volume += 2;
}
private void button2_Click(object sender, EventArgs e)//音量减
{
musicPlay.settings.volume -= 2;
}
private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)//双击播放
{
if (listBox1.SelectedIndex != -1)
{
if (musicPlay.URL != mlist[listBox1.SelectedIndex])
{
btnPlay.Enabled = true;
btnPlay.Text = "播放";
btnPlay.PerformClick();
}
else
{
b = false;
btnPlay.PerformClick();//相同歌曲,双击可在播放也暂停之间切换
}
}
}
private void timer1_Tick(object sender, EventArgs e)//自动下一曲
{
//if (musicPlay.playState == WMPLib.WMPPlayState.wmppsPlaying)
//{
// // lblDuration.Text = musicPlay.currentMedia.duration.ToString();//总时长184 秒数
// //lblDuration.Text = musicPlay.currentMedia.durationString;//总时长03:05 时分秒
// //lblDuration.Text = musicPlay.Ctlcontrols.currentPosition.ToString();//播放的时间,秒数
// //lblDuration.Text = musicPlay.Ctlcontrols.currentPositionString;//播放的时间,秒数
// double d1 = musicPlay.currentMedia.duration;//本身是double不用转
// double d2 = musicPlay.Ctlcontrols.currentPosition;//本身是double不用转换
// if (d1 - d2 < 1) //因为在转换中四舍五入,两者可能有点差异,也就不到1秒的差异
// {
// btnNext.PerformClick();
// }
//}
if (musicPlay.playState == WMPLib.WMPPlayState.wmppsStopped)
{
btnPlay.Text = "播放";//停止时,恢复初始
timer2.Enabled = false;//无歌放,歌词也停止
if (bAuto) btnNext.PerformClick();
}
else if (musicPlay.playState == WMPLib.WMPPlayState.wmppsPlaying)
{
lblDuration.Text = musicPlay.Ctlcontrols.currentPositionString;
}
else
{
lblDuration.Text = "显示播放时长";
}
}
private void btnAutoNext_Click(object sender, EventArgs e)//自动开关
{
if (listBox1.SelectedIndex == -1)
{
MessageBox.Show("请先选择起始歌曲!");
return;
}
if (btnAutoNext.Text == "自动播放")
{
bAuto = true;
if (musicPlay.playState == WMPLib.WMPPlayState.wmppsStopped || musicPlay.playState == WMPLib.WMPPlayState.wmppsUndefined)
{
btnPlay.PerformClick();
}
btnAutoNext.Text = "停止自动";
}
else
{
bAuto = false;
btnAutoNext.Text = "自动播放";
}
}
private void timer2_Tick(object sender, EventArgs e)//歌曲显示
{
if (musicPlay.Ctlcontrols.currentPosition > timeList[index])
{
label3.Text = lrcList[index];
if (index > 1) label1.Text = lrcList[index - 2];
else label1.Text = "";
if (index > 0) label2.Text = lrcList[index - 1];
else label1.Text = "";
if (index < lrcList.Count - 2) label4.Text = lrcList[index + 1];
else label4.Text = "";
if (index < lrcList.Count - 3) label5.Text = lrcList[index + 2];
else label5.Text = "";
if (index < lrcList.Count - 1) index++;//最后一个不再累增
}
}
private void lblMute_Click_1(object sender, EventArgs e)//静音与放音
{
if (lblMute.Tag.ToString() == "放音")
{
lblMute.Image = Image.FromFile(@"E:\静音.jpg");
lblMute.Size = lblMute.Image.Size;
lblMute.Tag = "静音";
musicPlay.settings.mute = true;
}
else
{
lblMute.Image = Image.FromFile(@"E:\放音.jpg");
lblMute.Size = lblMute.Image.Size;
lblMute.Tag = "放音";
musicPlay.settings.mute = false;
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)//歌曲切换时重置
{
b = true;
}
}
}