学生时代做的一个非常低级的卡拉OK播放器
学生时代做的一个非常低级的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播放器相关推荐
- 我做了一个网易云音乐外链播放器的Vue组件,很nice
话不多说,上视频: https://www.bilibili.com/video/BV1p44y1M7KC/ 介绍 起因是我的一个小项目用到了网易云音乐的外链播放器:于是将它从项目里剥离出来做成一个V ...
- 学生时代的最后一个新年,请一定要做这五件事...
微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里研发工程师,于2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer 个人擅长领域 :自学编程.技术校园招聘.软件工 ...
- 第六节:用audio标签打造一个属于自己的HTML5音乐播放器
上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...
- 一个简单的基于 DirectShow 的播放器 1(封装类)
DirectShow最主要的功能就是播放视频,在这里介绍一个简单的基于DirectShow的播放器的例子,是用MFC做的,今后有机会可以基于该播放器开发更复杂的播放器软件. 注:该例子取自于<D ...
- 【游戏开发创新】手把手教你使用Unity制作一个高仿酷狗音乐播放器,滨崎步,旋律起,爷青回(声音可视化 | 频谱 | Audio)
文章目录 一.前言 二.获取UI素材 三.使用UGUI制作界面 1.界面布局 2.账号圆形头像 3.搜索框 4.调节UI层 5.黑色按钮悬浮高亮效果 6.纯文字按钮 7.滚动列表自适应 8.歌名与视频 ...
- iOS一个模仿百度音乐盒的音乐播放器(带EQ均衡器)
工作之余, 断断续续写了这么一个音乐播放器, eq实现各种音效, 指定位置播放, 快进快退, 锁屏耳机线控等等, 基本就是参考百度音乐盒的功能来实现的.(项目地址最后放出, 项目中的资源接口, 是抓百 ...
- 用jq和bootstrap3 实现一个自定义网页版的音乐播放器
用jq和bootstrap3 实现一个自定义网页版的音乐播放器 1.主要实现功能 1.1.点击播放与暂停,上一首和下一首: 注:用python返回所有歌曲的信息,加载完成默认选择第一首歌曲,通过传递歌 ...
- 一个简单的基于 DirectShow 的播放器 2(对话框类)
上篇文章分析了一个封装DirectShow各种接口的封装类(CDXGraph):一个简单的基于 DirectShow 的播放器 1(封装类) 本文继续上篇文章,分析一下调用这个封装类(CDXGrap ...
- 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器...
[索引页] [×××] 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器 作者:webabcd 介绍 Silverlight 2.0 ...
最新文章
- java中怎样克隆,如何在Java中克隆列表?
- 成功解决AttributeError: module 'tensorflow' has no attribute 'scalar_summary'
- leetcode 无重复字符的最长子串
- HTTP--历史、组件系统
- vForum 2011 Beijing现场图文播报三 动手实验营
- 工作流学习——Activiti流程实例、任务管理四步曲 (zhuan)
- linux下录屏与截屏软件kazam
- GIS案例练习-----------第五天
- Sentinel 实战应用中的小技巧
- linux驱动开发详解——宋宝华 笔记
- 微信小程序实现自动登录
- android 电容触摸屏,剖析触摸屏上的电容按键
- 服务器上打开PHP文件却出现下载界面或者502
- laravel与TP的区别
- mysql mgr 启动_使用MySQL Shell创建MGR
- DTI-ATS入门(1):DTI综述
- 智云大咖秀:怎样的稳定器才是摄影师的“灵魂辅助”?
- 微信小程序canvas2d使用封装与案例使用
- php源码中powerby,小龙源码网 - discuz论坛怎么去掉power by discuz版权
- IDEA显示树状目录结构