遗憾迟香 发表于 2021-1-22 10:21

winform动态歌词显示控件(基于ListBox与Lable)

    /// <summary>
    /// 歌词类
    /// </summary>
   
    public class Lyric
    {
      /// <summary>
      /// 曲名
      /// </summary>
      public string Ti { get; set; }
      /// <summary>
      /// 艺术家
      /// </summary>
      public string Ar { get; set; }
      /// <summary>
      /// 专辑
      /// </summary>
      public string Al { get; set; }
      /// <summary>
      /// 制作人
      /// </summary>
      public string By { get; set; }
      /// <summary>
      /// 时间补偿值
      /// </summary>
      public int Offset { get; set; }
      /// <summary>
      /// 行数
      /// </summary>
      public int Count { get { return Words.Count; } }
      /// <summary>
      /// 文本集
      /// </summary>
      public List<LrcWord> Words { get; set; }
      /// <summary>
      /// 导出格式
      /// </summary>
      public string Export
      {
            get
            {
                StringBuilder str = new StringBuilder("");
                str.Append(string.Format("\n\n\n\n\r\n", Ti, Ar, Al, By, Offset));
                foreach (LrcWord i in Words)
                { str.Append(i.Export); }
                return str.ToString().Trim();
            }
      }
      /// <summary>
      /// 文本
      /// </summary>
      public string Text
      {
            get
            {
                StringBuilder str = new StringBuilder("");
                foreach (LrcWord i in Words)
                { str.Append(i.Word + "\n"); }
                return str.ToString().Trim();
            }
      }
      /// <summary>
      /// Lyrec默认构造
      /// </summary>
      public Lyric()
      {
            Words = new List<LrcWord>();
      }
      /// <summary>
      /// 创建Lrcc歌词
      /// </summary>
      /// <param name="text"></param>
      /// <returns></returns>
      public static Lyric Create(string[] text)
      {
            Lyric l = new Lyric();
            foreach (string i in text)
            {
                l.Words.Add(new LrcWord(i));
            }
            return l;
      }
      /// <summary>
      /// 从字符串加载
      /// </summary>
      public static Lyric Parse(string str)
      {
            str =str.Replace(@"\n", "\n");
            string[] words = str.Split('\n');
            Lyric l = new Lyric();
            l.Ti = GetMiddleText(str, "");
            l.Ar = GetMiddleText(str, "");
            l.Al = GetMiddleText(str, "");
            l.By = GetMiddleText(str, "");
            l.Offset = ToInt32(GetMiddleText(str, ""), 0);
            l.Words = new List<LrcWord>();
            foreach (string i in words)
            {
                LrcWord lw = LrcWord.Parse(i);
                if (lw != null)
                { l.Words.Add(lw); }
            }
            if (l.Words.Count == 0)
            { return null; }
            return l;
      }
      /// <summary>
      /// 从文件加载
      /// </summary>
      /// <param name="path">路径</param>
      /// <param name="en">编码</param>
      public static Lyric FromFile(string path, Encoding en)
      {
            string str = File.ReadAllText(path, en);
            return Parse(str);
      }
      /// <summary>
      /// 保存歌词
      /// </summary>
      /// <param name="path">路径</param>
      /// <param name="en">编码</param>
      public void Save(string path, Encoding en)
      {
            File.Delete(path);
            File.AppendAllText(path, Export, en);
      }
      /// <summary>
      /// 保存为文本
      /// </summary>
      /// <param name="path">路径</param>
      /// <param name="en">编码</param>
      public void SaveText(string path, Encoding en)
      {
            File.Delete(path);
            File.AppendAllText(path, Text, en);
      }
      /// <summary>
      /// 取出中间字符串
      /// </summary>
      /// <param name="str">源字符串</param>
      /// <param name="left">左</param>
      /// <param name="right">右</param>
      /// <returns>成功返回结果,失败返回空</returns>
      private static string GetMiddleText(string str, string left, string right)
      {
            if (str == null || left == null || right == null) { return ""; }
            if (str == "" || left == "" || right == "") { return ""; }
            int a = str.IndexOf(left, 0);
            int b = str.IndexOf(right, a + 1);
            if (a < 0 || b < 0)
            { return ""; }
            else
            {
                a = a + left.Length;
                b = b - a;
                if (a < 0 || b < 0)
                { return ""; }
                return str.Substring(a, b);
            }
      }
      /// <summary>
      /// 字符串转整数
      /// </summary>
      /// <param name="str">字符串</param>
      /// <param name="str">默认值</param>
      /// <returns>成功返回结果,失败返回默认值</returns>
      private static int ToInt32(string str, int defultValue = 0)
      {
            try { return int.Parse(str); }
            catch (Exception)
            { return defultValue; }
      }
    }
    /// <summary>
    /// 歌词文本类
    /// </summary>
   
    public class LrcWord
    {
      /// <summary>
      /// 时间
      /// </summary>
      public double Time { get; set; }
      /// <summary>
      /// 文本
      /// </summary>
      public string Word { get; set; }
      /// <summary>
      /// 导出格式
      /// </summary>
      public string Export
      { get { return string.Format("[{0}:{1:f3}]{2}\n", ((int)Math.Floor(Time / 60)).ToString("00"), Time % 60, Word); } }
      /// <summary>
      /// LrcWord有参构造
      /// </summary>
      /// <param name="time">时间</param>
      /// <param name="word">文本</param>
      private LrcWord(double time, string word)
      {
            Time = time;
            Word = word;
      }
      /// <summary>
      /// LrcWord有参构造
      /// </summary>
      /// <param name="text">文本</param>
      public LrcWord(string text)
      { Word = text; }
      /// <summary>
      /// 将字符串转换为歌词文本对象
      /// </summary>
      /// <param name="s"></param>
      /// <returns></returns>
      public static LrcWord Parse(string s)
      {
            try
            {
                Regex regex = new Regex(@"\[(*)\]+(.*)", RegexOptions.Compiled);
                MatchCollection mc = regex.Matches(s.Trim());
                double time = TimeSpan.Parse("00:" + mc.Groups.Value).TotalSeconds;
                string word = mc.Groups.Value;
                return new LrcWord(time, word);
            }
            catch (Exception)
            { return null; }
      }
      public override string ToString()
      {
            return Word;
      }
    }

ListBox实现
    public class LrcView : ListBox
    {
      private Lyric currentLrc;
      /// <summary>
      /// 当前歌词
      /// </summary>
      public Lyric CurrentLrc
      {
            get { return currentLrc; }
            set
            {
                LoadLrc(value);
                currentLrc = value;
            }
      }
      /// <summary>
      /// 设置超前时间
      /// </summary>
      public double Offset { get; set; }
      /// <summary>
      /// 加载歌词
      /// </summary>
      /// <param name="l"></param>
      private void LoadLrc(Lyric l)
      {
            this.Items.Clear();
            if (l != null)
            {
                foreach (var item in l.Words)
                {
                  this.Items.Add(item);
                }
            }
      }
      /// <summary>
      /// 根据播放进度展示歌词
      /// </summary>
      /// <param name="t"></param>
      public void Play(double t)
      {
            try
            {
                //当歌词不为空的时候滚动
                if (CurrentLrc != null)
                {
                  //计算超前时间
                  double offset = t + CurrentLrc.Offset + Offset;
                  for (int i = 0; i < CurrentLrc.Words.Count; i++)
                  {//循环遍历歌词文本
                        if (CurrentLrc.Words.Time >= offset)
                        {//如果那句歌词时间大于等于进度则显示
                            this.SelectedIndex = i - 1;
                            break;
                        }
                  }
                }
            }
            catch (Exception)
            { }
      }
    }

Lable实现
    public class LrcLabel : Label
    {
      private Lyric currentLrc;
      /// <summary>
      /// 当前歌词
      /// </summary>
      public Lyric CurrentLrc
      { get; set; }
      /// <summary>
      /// 设置超前时间
      /// </summary>
      public double Offset { get; set; }
      /// <summary>
      /// 根据播放进度展示歌词
      /// </summary>
      /// <param name="t"></param>
      public void Play(double t)
      {
            try
            {
                //当歌词不为空的时候滚动
                if (CurrentLrc != null)
                {
                  //计算超前时间
                  double offset = t + CurrentLrc.Offset + Offset;
                  for (int i = 0; i < CurrentLrc.Words.Count; i++)
                  {//循环遍历歌词文本
                        if (CurrentLrc.Words.Time >= offset)
                        {//如果那句歌词时间大于等于进度则显示
                            this.Text = CurrentLrc.Words.Word;
                            break;
                        }
                  }
                }
            }
            catch (Exception)
            { }
      }
    }
窗体部分代码(wmp控件实现播放)
      private void Form1_Load(object sender, EventArgs e)
      {
            axWindowsMediaPlayer1.URL = "leinov - 程序员之歌.mp3";
            Lyric l = Lyric.FromFile("leinov - 程序员之歌.lrc", Encoding.Default);
            lrcView1.CurrentLrc = l;
            lrcLabel1.CurrentLrc = l;
            timer1.Start();
      }

      private void timer1_Tick(object sender, EventArgs e)
      {
            double t = axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
            lrcView1.Play(t);
            lrcLabel1.Play(t);
      }

coolcalf 发表于 2021-1-22 11:32

.Net前端早该换WPF,别等了,兄弟。

wgw555 发表于 2021-1-31 14:07

怎样设置保留行号??
页: [1]
查看完整版本: winform动态歌词显示控件(基于ListBox与Lable)