学生时代做的一个非常低级的C#卡拉OK播放器。

实现了桌面卡拉OK[单行,双行],繁简转换,歌曲搜索,3种播放模式[单首,循环,随机],全屏歌词,全局快捷键,XML配置,指定歌词文件夹,等等一些简单的功能。

源码点击下载

无意中翻出来了,看看,听听歌,有别有一番乐趣,想当初做这个的时候才接触编程1年。里面用了太多的集合,歌词判断也非常不准备。呵呵。算是用一种非常笨的方法实现的吧。里面没什么高深的技术。主要就是用到了双缓冲[一种防止歌词刷新时屏幕闪烁的技术]、注册全局快捷键等。

已经好久没有接触C#了,虽然这是曾经非常感兴趣的东西,却为了学习编程思想选择了JAVA。如果现在再让我做,我一定会把里面的代码简化简化再简化吧。看着那些乱七八糟的代码,想想自己当年的何其的菜鸟水平的作品。也是一种人生的乐趣。

主界面:

窗体卡拉OK

桌面卡拉OK显示[支持单行,双行]:

配置:

歌词配置[当时我还没有学XML,实现来源于网上]:

<configuration><appSettings><add key="lrcDir" value="E:\music\AIRPLAY.DAT\Lyrics" /><add key="playState" value="2" /><add key="sound" value="28" /><add key="DeskIsDoubleline" value="true" /><add key="DeskFontFamily" value="英章楷书" /><add key="DeskFontSize" value="27.75" /><add key="DeskFontStyle" value="bold" /><add key="DeskNormalColor" value="-65536" /><add key="DeskLightColor" value="-16711936" /><add key="FontSize" value="15" /><add key="NormalColor" value="-4144960" /><add key="LightColor" value="-16711872" /><add key="BackColor" value="-16777216" /><add key="FontStyle" value="bold" /><add key="FontFamily" value="英章楷书" /><add key="DeskBackColor" value="-16777216" /></appSettings>
</configuration>

读取配置文件的核心处理类:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;namespace LrcCollection
{internal class Config{public static string GetValue(string AppKey){try{XmlDocument document = new XmlDocument();document.Load(System.AppDomain.CurrentDomain.BaseDirectory + "LrcSet.xml");XmlElement element = (XmlElement)document.SelectSingleNode("//appSettings").SelectSingleNode("//add[@key='" + AppKey + "']");if (element != null){return element.GetAttribute("value");}return null;}catch{return null;}}public static void SetValue(string AppKey, string AppValue){try{XmlDocument document = new XmlDocument();document.Load(System.AppDomain.CurrentDomain.BaseDirectory + "LrcSet.xml");XmlNode node = document.SelectSingleNode("//appSettings");XmlElement element = (XmlElement)node.SelectSingleNode("//add[@key='" + AppKey + "']");if (element != null){element.SetAttribute("value", AppValue);}else{XmlElement newChild = document.CreateElement("add");newChild.SetAttribute("key", AppKey);newChild.SetAttribute("value", AppValue);node.AppendChild(newChild);}document.Save(System.AppDomain.CurrentDomain.BaseDirectory + "LrcSet.xml");}catch{SetValue(AppKey, AppValue, true);}}public static void SetValue(string AppKey, string AppValue, bool tt){XmlDocument document = new XmlDocument();XmlNode node = document.CreateNode(XmlNodeType.Element, "configuration", "");document.AppendChild(node);XmlNode node2 = document.CreateNode(XmlNodeType.Element, "appSettings", "");node.AppendChild(node2);XmlElement newChild = document.CreateElement("add");newChild.SetAttribute("key", AppKey);newChild.SetAttribute("value", AppValue);node2.AppendChild(newChild);document.Save(System.AppDomain.CurrentDomain.BaseDirectory + "LrcSet.xml");}}
}

下面是画歌词的处理类[现在自己都看不懂当初是如何实现的了,贴在这里吧。]:

说一说主要的思想:

画歌词的面板一定要继承UserControl类,然后重写其protected override void OnPaint(PaintEventArgs pe)方法,实现双缓冲,在这里面画歌词。

画卡拉OK歌词的原理是:先画背景[底层],再画你要显示的所有歌词[中间层],每行歌词都是顺序向下的,中间有间距,然后再你画好的歌词上面,画卡拉OK歌词,也就是高亮显示的那一行歌词[最上层],这一行歌词会覆盖之前画的中间层歌词的那一行,当然这样它还不是卡拉OK显示的,卡拉OK显示就要取出当前这句歌词和下一句歌词之间的时间,然后从左至右,匀速的画上高亮显示的这一行,看起来就是卡拉OK显示出来了。像酷狗这种歌词是经过精准处理的。

桌面歌词就很简单了,主要是一个无标题的窗体,做上鼠标移动事件即可拖动,单行,双行歌词也只不过是多了一层判断。双行就是每次唱完一句就取出下一句画在面板上。单行就是唱一句画一句。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using LrcCollection;namespace MediaPlayer
{public partial class DeskLrcControl : UserControl{public DeskLrcControl(){InitializeComponent();Size1(this.Size);Components();this.DoubleBuffered = true;}#region 字段public LrcPanel lrcPanel = null;private ArrayList lrcConfig = new ArrayList();int width = 0;Bitmap imgBack;Bitmap imgLrc;int middleTime = 0;public string currentPosition = null;int minute;int second;public Dictionary<int, string> lrcSortedList = new Dictionary<int, string>();//用来保存歌词和时间排序后的集合private SolidBrush backBrush;private SolidBrush lightBrush;private Color backColor;private Font fontStyle;private StringFormat stringFormatter;[Description("普通歌词颜色"), Category("歌词样式设置")]public SolidBrush BackBrush{get { return backBrush; }set { backBrush = value; }}[Description("高亮歌词颜色"), Category("歌词样式设置")]public SolidBrush LightBrush{get { return lightBrush; }set { lightBrush = value; }}[Description("歌词背景颜色"), Category("歌词样式设置")]public Color BackColors{get { return backColor; }set { backColor = value; }}[Description("当前歌曲时间"), Category("歌词样式设置")]public string CurrentPosition{get { return currentPosition; }set { currentPosition = value; }}[Description("歌词字体样式"), Category("歌词样式设置")]public Font FontSty{get { return fontStyle; }set { fontStyle = value; }}[Description("歌词字体排序"), Category("歌词样式设置")]public StringFormat StringFormatter{get { return stringFormatter; }set { stringFormatter = value; }}public override Color BackColor{get{return backColor;}set{base.BackColor = value;}}public void Size1(Size s){if (imgBack != null){imgBack.Dispose();}if (imgLrc != null){imgLrc.Dispose();}imgBack = new Bitmap(s.Width, s.Height);imgLrc = new Bitmap(s.Width, s.Height);//maxWidth = 0;//lrcSortedList.Clear();//Graphics g = Graphics.FromHwnd(this.contextMenuStrip1.Handle);//for (int i = 0; i < tempTime.Length; i++)//{//    if (i + 1 < tempTime.Length)//    {//        if (g.MeasureString(lrcList.ElementAt(i).Value, fontStyle).Width > maxWidth)//        {//            maxWidth = (int)g.MeasureString(lrcList.ElementAt(i).Value, fontStyle).Width;//        }//    }//    lrcSortedList.Add(tempTime[i], lrcList[tempTime[i]]);//}//g.Dispose();//imgBack = new Bitmap(maxWidth + 2, this.Height);//imgLrc = new Bitmap(maxWidth + 2, this.Height); //this.Refresh();}public override Size MinimumSize{get{return new Size(200, 20);}set{base.MinimumSize = value;}}#endregionprotected override void OnPaint(PaintEventArgs pe){if (currentPosition != null){if (load == false){Components();load = true;}DrawString(currentPosition, pe.Graphics, BackBrush, LightBrush, this.fontStyle, this.BackColor, stringFormatter);pe.Dispose();}}bool load = false;#region //初始化public void Components(){try{backBrush = new SolidBrush(Color.FromArgb(Convert.ToInt32(Config.GetValue("DeskNormalColor"))));lightBrush = new SolidBrush(Color.FromArgb(Convert.ToInt32(Config.GetValue("DeskLightColor"))));backColor = Color.FromArgb(Convert.ToInt32(Config.GetValue("DeskBackColor")));FontStyle f = FontStyle.Regular;if (Config.GetValue("DeskFontStyle") == "bold"){f = FontStyle.Bold;}else if (Config.GetValue("DeskFontStyle") == "italic"){f = FontStyle.Italic;}else if (Config.GetValue("DeskFontStyle") == "strikeout"){f = FontStyle.Strikeout;}else if (Config.GetValue("DeskFontStyle") == "underline"){f = FontStyle.Underline;}else{f = FontStyle.Regular;}fontStyle = new Font(Config.GetValue("DeskFontFamily"), float.Parse(Config.GetValue("DeskFontSize")),f);if (Config.GetValue("DeskIsDoubleline") != null){isDoubleLine = Convert.ToBoolean(Config.GetValue("DeskIsDoubleline"));}stringFormatter = new StringFormat();stringFormatter.Alignment = StringAlignment.Center;stringFormatter.LineAlignment = StringAlignment.Center;stringFormatter.Trimming = StringTrimming.Character;}catch{backBrush = new SolidBrush(Color.Blue);lightBrush = new SolidBrush(Color.Red);backColor = Color.Black;fontStyle = new Font("幼圆", 34f);stringFormatter = new StringFormat();stringFormatter.Alignment = StringAlignment.Center;stringFormatter.LineAlignment = StringAlignment.Center;stringFormatter.Trimming = StringTrimming.Character;}}#endregion#region 画歌词public bool isKana = true;public bool isTranKey = true;public bool isDoubleLine = true;SizeF imgSize = SizeF.Empty;SizeF img1 = SizeF.Empty;public string DrawString(string nowTime, Graphics g, SolidBrush backBrush, SolidBrush lightBrush, Font f, Color backColor, StringFormat format){if (isTranKey == true){this.BackColors = Color.Transparent;this.FindForm().BackColor = Color.Turquoise;this.FindForm().TransparencyKey = Color.Turquoise;}if (lrcSortedList.Count > 0 && LrcConnections.lrcPath != null){Size1(this.FindForm().Size);//歌词居中imgLrc = DrawLrcImg(nowTime, lightBrush, backBrush, f, backColor, format);if (isKana == true){imgBack = ShowLrc(backBrush, f, backColor, format);//画背景歌词g.CompositingQuality = CompositingQuality.HighQuality;g.SmoothingMode = SmoothingMode.AntiAlias;g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;if (imgLrc != null && imgBack != null){Rectangle rec = new Rectangle(0, 0, width, this.imgLrc.Height);g.DrawImage(imgBack, 0, 0);//画当前高亮显示的歌词,其实就是画歌词图像的一部分,以像素显示会呈现卡拉OK歌词g.DrawImage(imgLrc, 0, 0, rec, GraphicsUnit.Pixel);//g.Flush();}}else if (imgLrc != null){g.DrawImage(imgLrc, 0, 0);//g.Flush();}}else{if (LrcConnections.lrcPath == null){Graphics gg = Graphics.FromImage(imgBack);gg.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;gg.CompositingQuality = CompositingQuality.HighQuality;gg.SmoothingMode = SmoothingMode.AntiAlias;SizeF imgSize = gg.MeasureString("对不起,没有找到歌词,您可以手动指定歌词", f);//当前歌词长度this.FindForm().Size = new Size((int)imgSize.Width, (int)imgSize.Height);Size1(this.Size);gg.Dispose();gg = Graphics.FromImage(imgBack);gg.DrawString("对不起,没有找到歌词,您可以手动指定歌词", f, backBrush, 0, 0);gg.Dispose();g.DrawImage(imgBack, 0, 0);}}return null;}#endregion#region 显示高亮歌词的方法private Bitmap DrawLrcImg(string currentTime, SolidBrush lightBrush, SolidBrush backBrush, Font f, Color backColor, StringFormat format){if (currentTime == "" || currentTime == null){return null;}if (imgLrc == null){return null;}Graphics gra = Graphics.FromImage(imgLrc);gra.Clear(backColor);minute = Convert.ToInt32(currentTime.Substring(0, 2)) * 60;//分钟转为秒second = Convert.ToInt32(currentTime.Substring(3));for (int i = 0; i < lrcSortedList.Count - 1; i++){if (lrcSortedList.ElementAt(i).Key == (minute + second))//高亮显示当前歌词{//float lrcWidth = g.MeasureString(lrcSortedList.ElementAt(i).Value, f).Width;UserHelper.currentLrcIndex = i;width = 0;break;}}if ((UserHelper.currentLrcIndex + 1) <= lrcSortedList.Count){middleTime = lrcSortedList.ElementAt(UserHelper.currentLrcIndex + 1).Key - lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Key;}imgSize = gra.MeasureString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f);//当前歌词长度if (isDoubleLine == false){this.FindForm().Size = new Size((int)imgSize.Width, (int)imgSize.Height);Size1(this.Size);}else//如果是双行的话{if (UserHelper.currentLrcIndex < lrcSortedList.Count - 1){img1 = gra.MeasureString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex + 1).Value, f);}if (imgSize.Width > img1.Width){this.FindForm().Size = new Size((int)imgSize.Width, (int)imgSize.Height * 2);Size1(this.Size);}else{this.FindForm().Size = new Size((int)img1.Width, (int)img1.Height * 2);Size1(this.Size);}gra.Dispose();}if (width == 0){width++;}else{width += (int)(imgSize.Width / (middleTime * 6));//歌词匀速以卡拉OK形式前进,毫秒化为秒}Graphics g = Graphics.FromImage(imgLrc);g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;g.CompositingQuality = CompositingQuality.HighQuality;g.SmoothingMode = SmoothingMode.AntiAlias;if (isDoubleLine == false){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f, lightBrush, 0, 0);}else{if (UserHelper.currentLrcIndex % 2 == 0){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f, lightBrush, 0, 0);if (UserHelper.currentLrcIndex < lrcSortedList.Count - 1){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex + 1).Value, f, backBrush, 0, f.Height);}}else{if (UserHelper.currentLrcIndex < lrcSortedList.Count - 1){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex + 1).Value, f, backBrush, 0, 0);}g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f, lightBrush, 0, f.Height);}}//g.Flush();g.Dispose();return imgLrc;}#endregion#region 显示背景歌词的方法public Bitmap ShowLrc(SolidBrush backBrush, Font f, Color backColor, StringFormat format){Graphics gra = Graphics.FromImage(imgBack);gra.Clear(backColor);//Font f1 = new Font(f.FontFamily, f.Size + 0.2f, FontStyle.Regular);//for (int index = 0; index < lrcSortedList.Count - 1; index++)//{//    Graphics g = Graphics.FromImage(imgBack);//    g.SmoothingMode = SmoothingMode.AntiAlias;//    g.DrawString(lrcSortedList.ElementAt(index).Value, f1, new SolidBrush(Color.Blue), this.imgBack.Width / 2, f.Height * (index + space + 1 + lines), format);//    g.Dispose();//}//f1.Dispose();//显示歌词Graphics g = Graphics.FromImage(imgBack);g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;g.CompositingQuality = CompositingQuality.HighQuality;g.SmoothingMode = SmoothingMode.AntiAlias;if (isDoubleLine == false){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f, backBrush, 0, 0);}else{if (UserHelper.currentLrcIndex % 2 == 0){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f, backBrush, 0, 0);if (UserHelper.currentLrcIndex < lrcSortedList.Count - 1){g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex + 1).Value, f, backBrush, 0, f.Height);}}else{g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex + 1).Value, f, backBrush, 0, 0);g.DrawString(lrcSortedList.ElementAt(UserHelper.currentLrcIndex).Value, f, backBrush, 0, f.Height);}}//g.Flush();g.Dispose();return imgBack;}#endregion}
}

歌词繁简转换也很容易:

 /// <summary>/// 简体到繁体转换/// </summary>/// <param name="simplifiedChinese">简体</param>/// <returns>繁体</returns>private string SimplifiedToTraditional(string simplifiedChinese){string traditionalChinese = string.Empty;System.Globalization.CultureInfo vCultureInfo = new System.Globalization.CultureInfo("zh-CN", false);traditionalChinese = Microsoft.VisualBasic.Strings.StrConv(simplifiedChinese, Microsoft.VisualBasic.VbStrConv.TraditionalChinese, vCultureInfo.LCID);return traditionalChinese;}/// <summary>/// 繁体到简体转换/// </summary>/// <param name="traditionalChinese">繁体</param>/// <returns>简体</returns>private string TraditionalToSimplified(string traditionalChinese){string simplifiedChinese = string.Empty;System.Globalization.CultureInfo vCultureInfo = new System.Globalization.CultureInfo("zh-CN", false);simplifiedChinese = Microsoft.VisualBasic.Strings.StrConv(traditionalChinese, Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, vCultureInfo.LCID);return simplifiedChinese;}

歌词窗体出现时是动态显示的,以及全局快捷键的[当时只知道使用系统的user32.dll实现的]代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;namespace MediaPlayer
{public partial class LrcFrm : Form{public AxWMPLib.AxWindowsMediaPlayer axWmplayer;public System.Windows.Forms.Timer timer;//动画窗体调用[System.Runtime.InteropServices.DllImport("user32")]private static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags);const int AW_HOR_POSITIVE = 0x0002;const int AW_HOR_NEGATIVE = 0x0004;const int AW_VER_POSITIVE = 0x0008;const int AW_VER_NEGATIVE = 0x00016;const int AW_CENTER = 0x0010;const int AW_HIDE = 0x10000;const int AW_ACTIVATE = 0x20000;const int AW_SLIDE = 0x20000;const int AW_BLEND = 0x80000;public LrcFrm(AxWMPLib.AxWindowsMediaPlayer axWmplayer,System.Windows.Forms.Timer timer){InitializeComponent();this.DoubleBuffered = true;LrcConnections.lrcfrm = this;LrcConnections.lrcPanel = this.lrcPanel1;this.axWmplayer = axWmplayer;this.timer = timer;}#region 字段public override Size MinimumSize{get{return new Size(100, 100);}set{base.MinimumSize = value;}}#endregion#region //注册热键[DllImport("user32.dll", SetLastError = true)]public static extern bool RegisterHotKey(IntPtr hWnd, // handle to window  int id, // hot key identifier  KeyModifiers fsModifiers, // key-modifier options  System.Windows.Forms.Keys vk // virtual-key code  );[DllImport("user32.dll", SetLastError = true)]public static extern bool UnregisterHotKey(IntPtr hWnd, // handle to window  int id // hot key identifier  );[Flags]public enum KeyModifiers{None = 0,Alt = 1,Control = 2,Shift = 4,Windows = 8}private const int WM_HOTKEY = 0x312; //窗口消息-热键private const int WM_CREATE = 0x1; //窗口消息-创建private const int WM_DESTROY = 0x2; //窗口消息-销毁private const int MOD_ALT = 0x1; //ALTprivate const int MOD_CONTROL = 0x2; //CTRLprivate const int MOD_SHIFT = 0x4; //SHIFTprivate const int VK_SPACE = 0x20; //SPACE protected override void WndProc(ref Message m){//base.WndProc(ref m);switch (m.Msg){case WM_HOTKEY: //窗口消息-热键switch (m.WParam.ToString()){case "1989":this.lrcPanel1.showFullScreen();break;case "11": //热键IDthis.lrcPanel1.KanaOK();break;case "12":this.lrcPanel1.showLrcSetFrm();break;case "13":this.lrcPanel1.showLrc();break;case "14":this.lrcPanel1.showFullScreen();break;case "15": //热键IDHelper.main.PlayNext();break;case "16":Helper.main.playPre();break;//case "17"://    this.lrcPanel1.showLrc();//    break;//case "18"://    this.lrcPanel1.showFullScreen();//    break;default:break;}break;case WM_CREATE: //窗口消息-创建RegisterHotKey(this.Handle, 1989, KeyModifiers.None, Keys.Escape);RegisterHotKey(this.Handle, 11, KeyModifiers.Control | KeyModifiers.Alt, Keys.K);RegisterHotKey(this.Handle, 12, KeyModifiers.Control | KeyModifiers.Alt, Keys.G);RegisterHotKey(this.Handle, 13, KeyModifiers.Control | KeyModifiers.Alt, Keys.D);RegisterHotKey(this.Handle, 14, KeyModifiers.Control | KeyModifiers.Alt, Keys.F);//播放控制//下一首RegisterHotKey(this.Handle, 15, KeyModifiers.Control | KeyModifiers.Alt, Keys.Right);//上一首RegisterHotKey(this.Handle, 16, KeyModifiers.Control | KeyModifiers.Alt, Keys.Left);//音量加// RegisterHotKey(this.Handle, 17, KeyModifiers.Control | KeyModifiers.Alt, Keys.Up);//音量减//  RegisterHotKey(this.Handle, 18, KeyModifiers.Control | KeyModifiers.Alt, Keys.Down);break;case WM_DESTROY: //窗口消息-销毁UnregisterHotKey(this.Handle, 1989);UnregisterHotKey(this.Handle, 11); //销毁热键UnregisterHotKey(this.Handle, 12);UnregisterHotKey(this.Handle, 13);UnregisterHotKey(this.Handle, 14);UnregisterHotKey(this.Handle, 15);UnregisterHotKey(this.Handle, 16);//  UnregisterHotKey(this.Handle, 17);// UnregisterHotKey(this.Handle, 18);break;default:break;}base.WndProc(ref m);}#endregionprivate void LrcFrm_Load(object sender, EventArgs e){Thread t = new Thread(loadLrc);t.IsBackground = true;t.Start();//动画由小渐大,现在取消AnimateWindow(this.Handle, 2000, AW_CENTER | AW_ACTIVATE);}private void loadLrc(){int i = 0;while (LrcConnections.isReading == true){Thread.Sleep(1000);i++;if (LrcConnections.isReading == false || i == 5){break;}}if (LrcConnections.isReading == false){this.lrcPanel1.lrcSortedList = LrcConnections.lrcSortedList;}Thread.CurrentThread.Abort();}#region//改变窗体大小时  歌词面板改变private void LrcFrm_Resize(object sender, EventArgs e){this.lrcPanel1.Size1(this.Size);//歌词居中this.lrcPanel1.ChangeSize();}#endregionprivate void LrcFrm_FormClosing(object sender, FormClosingEventArgs e){this.Visible = false;e.Cancel = true;//存储当前状态}}
}

如果你想单独试试双缓冲,可以试试这个,你可以拿它和没有使用双缓冲的timer比较下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;namespace MediaPlayer
{public partial class myLabel : UserControl{public myLabel(){InitializeComponent();Timer t = new Timer();this.DoubleBuffered = true;t.Interval = 1000;t.Tick += new EventHandler(t_Tick);t.Enabled = true;}protected override void OnPaint(PaintEventArgs pe){Draw(pe.Graphics);pe.Dispose();}//程序人生 人生如戏 戏如人生 却不能游戏人生void t_Tick(object sender, EventArgs e){this.Refresh();}private void Draw(Graphics g){g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;Font f = new Font("华文行楷", 35F, FontStyle.Italic);SolidBrush fontB = new SolidBrush(Color.Gray);SolidBrush fontA = new SolidBrush(Color.Red);//先画阴影,坐标偏移5g.DrawString("程序", f, fontB, 15, 30);g.DrawString("人生", f, fontB, 15, this.Size.Height / 2 + 15);//再画字体g.DrawString("程序", f, fontA, 0, 15);g.DrawString("人生", f, fontA, 0, this.Size.Height / 2);}//Font f1 = new Font("幼圆", 15F, FontStyle.Regular);//SolidBrush fontC = new SolidBrush(Color.LightGray);//for (int i = 0; i <= 360; i += 60)//{//    //平移Graphics对象到窗体中心//    g.TranslateTransform(this.Width / 2, this.Height / 2);//    //设置Graphics对象的输出角度//    g.RotateTransform(i);//    //设置文字填充颜色//    //旋转显示文字//    g.DrawString("土豆水印", f1, fontC, 10, 10);//    //恢复全局变换矩阵//    g.ResetTransform();//}}
}

搜索歌词的方法,一种很笨的方法:

 string song = null;List<int> songIndex = new List<int>();private void btnFind_Click(object sender, EventArgs e){if (song != null && song != txtSong.Text.Trim()){songIndex.Clear();song = txtSong.Text.Trim();}else if (song == null){song = txtSong.Text.Trim();}if (song != null && song != ""){for (int flag = 0; flag < lbPlayerList.Items.Count; flag++){if (songIndex.Contains(flag)){continue;}if (lbPlayerList.Items[flag].ToString().Contains(txtSong.Text.Trim())){songIndex.Add(flag);lbPlayerList.SelectedIndex = flag;break;}else{//如果到了末尾,清空集合。下次从新开始if (flag == lbPlayerList.Items.Count - 1){MessageBox.Show("已经到了末尾...");songIndex.Clear();}}}}}

如果你看到了关于窗体,你可能找不到上面显示的文字从哪来,事实上里面有2个dll文件,它描述的版本,作者,制作时间等信息,只有用特性和反射机制才可能读出来。

特性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AttributeTudou;namespace AttributeReflection
{/// <summary>/// 特性,更新版本时可用反射读取此程序的信息/// /// 作者,创建时间,最后修改时间,公司名称,产品名称,版本,声明/// </summary>[AttibuteTuDou("很拽の土豆", "2009年12月", "2011年2月", "土豆工作室", "雅风随风", "1.0.0", "CopyRight 2011 很拽の土豆 All Rights Reserved", "以上一切信息版权归原作者所有\r\n\r\n郑重声明:版权所有,翻版不究\r\n\r\n\r\t\r\t2009.12\r\t很拽の土豆\r\nQQ:475589699\r\n邮箱:yaerfeng1989@163.com")]public class Tudou{}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace AttributeTudou
{[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]//允许多个访问,可以对任何应用程序的元素应用此特性public class AttibuteTuDou : Attribute{public AttibuteTuDou(){}public AttibuteTuDou(string author,string createDate,string lastUpDate,string comp,string producter,string version,string copyRight,string otherDesc){this.Author = author;this.CreateDate = createDate;this.LastUpTime = lastUpDate;this.Company = comp;this.Producter = producter;this.Version = version;this.CopyRight = copyRight;this.OtherDesc =otherDesc;}private string author;public string Author{get { return author; }set { author = value; }}private string createDate;public string CreateDate{get { return createDate; }set { createDate = value; }}private string lastUpTime;public string LastUpTime{get { return lastUpTime; }set { lastUpTime = value; }}private string version;public string Version{get { return version; }set { version = value; }}private string company;public string Company{get { return company; }set { company = value; }}private string producter;public string Producter{get { return producter; }set { producter = value; }}private string otherDesc;public string OtherDesc{get { return otherDesc; }set { otherDesc = value; }}private string copyRight;public string CopyRight{get { return copyRight; }set { copyRight = value; }}}
}

如何读取:

如果你眼睛好,你会发现这里面还有2个方法

1个是用记事本打开歌词的,1个是定位文件[给一个路经它,它会自动在电脑上帮你定位这个文件]的。前者可能简单,但后者却更实用。

实现方法分别为:

System.Diagnostics.Process.Start("NOTEPAD.EXE", 文本的路径);

System.Diagnostics.Process.Start("explorer.exe", "/select," + 文本的路径);

整体代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using LrcCollection;
using AttributeTudou;
using System.Reflection;namespace MediaPlayer
{public partial class LrcSetFrm : Form{//private Font fontStyle;private Color normalColor;private Color lightColor;private Color backColor;private LrcPanel lrcPanel;public LrcSetFrm(LrcPanel lrcPanel){InitializeComponent();this.lrcPanel = lrcPanel;tudou = AssemblyTitle;this.Text = String.Format("关于 {0}", AssemblyProduct);this.labelProductName.Text = AssemblyProduct;this.labelVersion.Text = String.Format("版本 {0}", AssemblyVersion);this.labelCopyright.Text = AssemblyCopyright;this.labelCompanyName.Text = AssemblyCompany;this.textBoxDescription.Text = AssemblyDescription;}private void btnOpenLrc_Click(object sender, EventArgs e){if (txtPath.Text.Trim() != "" && txtPath.Text.Trim() != null){if (File.Exists(txtPath.Text)){System.Diagnostics.Process.Start("NOTEPAD.EXE", txtPath.Text);}else{MessageBox.Show("对不起,不存在该文件!");}}}private void btnOpenLrcFile_Click(object sender, EventArgs e){if (textBox1.Text.Trim() != "" && textBox1.Text.Trim() != null){if (Directory.Exists(textBox1.Text)){System.Diagnostics.Process.Start("explorer.exe", "/select," + textBox1.Text);}else{MessageBox.Show("对不起,不存在该文件夹,请重新指定文件夹!");}}}AttibuteTuDou tudou = null;#region 程序集属性访问器public AttibuteTuDou AssemblyTitle{get{Assembly ass = Assembly.Load("AttributeReflection");Type[] t = ass.GetTypes();foreach (Type type in t){Attribute[] attributes = Attribute.GetCustomAttributes(type);if (attributes.Length > 0){foreach (Attribute a in attributes){tudou = (AttibuteTuDou)a;return tudou;}}}return null;}}public string AssemblyVersion{get{if (tudou != null){return tudou.Version;}return "1.0.0";}}public string AssemblyDescription{get{if (tudou != null){return tudou.OtherDesc;}return "支持作者 支持原创";}}public string AssemblyProduct{get{if (tudou != null){return tudou.Producter;}return "土豆作品";}}public string AssemblyCopyright{get{if (tudou != null){return tudou.CopyRight;}return "CopyRights  € 2010";}}public string AssemblyCompany{get{if (tudou != null){return tudou.Company;}return "土豆工作室";}}public string CreateDate{get{if (tudou != null){return tudou.CreateDate;}return null;}}public string LastUpDate{get{if (tudou != null){return tudou.LastUpTime;}return null;}}public string author{get{if (tudou != null){return tudou.Author;}return "很拽の土豆";}}#endregionprivate void btnDel_Click(object sender, EventArgs e){if (this.txtPath.Text != null){FileInfo f = new FileInfo(this.txtPath.Text);if (f.Exists){if (MessageBox.Show("确认永久删除歌词" + f.FullName + "?","警告",MessageBoxButtons.OKCancel,MessageBoxIcon.Warning) == DialogResult.OK){f.Delete();}}}}}
}

想想曾经为做这个付出的心血,不得不自己苦笑一下,兴趣吧,也许只是因为曾经的兴趣,有机会,我会再研究一下C#的。等我快老了吧。

一个非常简单的东西我却会用到高级特性,反射,系统热键注册,双缓冲,也许是因为有了需求,才有了结果吧。

先学好JAVA,做好当前事。

学生时代做的一个非常低级的卡拉OK播放器相关推荐

  1. 我做了一个网易云音乐外链播放器的Vue组件,很nice

    话不多说,上视频: https://www.bilibili.com/video/BV1p44y1M7KC/ 介绍 起因是我的一个小项目用到了网易云音乐的外链播放器:于是将它从项目里剥离出来做成一个V ...

  2. 学生时代的最后一个新年,请一定要做这五件事...

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里研发工程师,于2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer 个人擅长领域 :自学编程.技术校园招聘.软件工 ...

  3. 第六节:用audio标签打造一个属于自己的HTML5音乐播放器

    上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...

  4. 一个简单的基于 DirectShow 的播放器 1(封装类)

    DirectShow最主要的功能就是播放视频,在这里介绍一个简单的基于DirectShow的播放器的例子,是用MFC做的,今后有机会可以基于该播放器开发更复杂的播放器软件. 注:该例子取自于<D ...

  5. 【游戏开发创新】手把手教你使用Unity制作一个高仿酷狗音乐播放器,滨崎步,旋律起,爷青回(声音可视化 | 频谱 | Audio)

    文章目录 一.前言 二.获取UI素材 三.使用UGUI制作界面 1.界面布局 2.账号圆形头像 3.搜索框 4.调节UI层 5.黑色按钮悬浮高亮效果 6.纯文字按钮 7.滚动列表自适应 8.歌名与视频 ...

  6. iOS一个模仿百度音乐盒的音乐播放器(带EQ均衡器)

    工作之余, 断断续续写了这么一个音乐播放器, eq实现各种音效, 指定位置播放, 快进快退, 锁屏耳机线控等等, 基本就是参考百度音乐盒的功能来实现的.(项目地址最后放出, 项目中的资源接口, 是抓百 ...

  7. 用jq和bootstrap3 实现一个自定义网页版的音乐播放器

    用jq和bootstrap3 实现一个自定义网页版的音乐播放器 1.主要实现功能 1.1.点击播放与暂停,上一首和下一首: 注:用python返回所有歌曲的信息,加载完成默认选择第一首歌曲,通过传递歌 ...

  8. 一个简单的基于 DirectShow 的播放器 2(对话框类)

    上篇文章分析了一个封装DirectShow各种接口的封装类(CDXGraph):一个简单的基于 DirectShow 的播放器  1(封装类) 本文继续上篇文章,分析一下调用这个封装类(CDXGrap ...

  9. 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器...

    [索引页] [×××] 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器 作者:webabcd 介绍 Silverlight 2.0 ...

最新文章

  1. java中怎样克隆,如何在Java中克隆列表?
  2. 成功解决AttributeError: module 'tensorflow' has no attribute 'scalar_summary'
  3. leetcode 无重复字符的最长子串
  4. HTTP--历史、组件系统
  5. vForum 2011 Beijing现场图文播报三 动手实验营
  6. 工作流学习——Activiti流程实例、任务管理四步曲 (zhuan)
  7. linux下录屏与截屏软件kazam
  8. GIS案例练习-----------第五天
  9. Sentinel 实战应用中的小技巧
  10. linux驱动开发详解——宋宝华 笔记
  11. 微信小程序实现自动登录
  12. android 电容触摸屏,剖析触摸屏上的电容按键
  13. 服务器上打开PHP文件却出现下载界面或者502
  14. laravel与TP的区别
  15. mysql mgr 启动_使用MySQL Shell创建MGR
  16. DTI-ATS入门(1):DTI综述
  17. 智云大咖秀:怎样的稳定器才是摄影师的“灵魂辅助”?
  18. 微信小程序canvas2d使用封装与案例使用
  19. php源码中powerby,小龙源码网 - discuz论坛怎么去掉power by discuz版权
  20. IDEA显示树状目录结构

热门文章

  1. php保留一位小数不四舍五入,PHP保留小数点后一位并且不四舍五入的方法
  2. 搞懂全局变量、外部变量、静态全局变量的区别
  3. 程序员!!!程序员的打油诗
  4. 签三方、试用期 注意事项
  5. BP神经网络(原理及代码实现)
  6. 【设计模式第一弹】策略模式
  7. ubuntu系统搜狗输入法简繁切换ctrl+shift+f快捷键禁用
  8. 【维生素C语言】练习:画图解析C语言指针笔试题
  9. GStreamer功能详解
  10. 让ArcMap变得更加强大,用python执行地理处理以及编写自定义脚本工具箱