zoukankan      html  css  js  c++  java
  • C#_音乐播放器_用ListBox显示歌词


      在用ListBox显示歌词的时候,可以显示多行,同时可以控制每一行显示的样式等等。控制显示样式是在它的DrawItem事件中来控制的。首先要先将ListBox的DrawMode属性设置为OwnerDrawVariable或OwnerDrawFixed。ListBox有个ItemHeight属性,在DrawMode设置为Normal时,这个属性是不可设置的,并且其值是根据当前字体进行计算获得的。只有当DrawMode设置为OwnerDrawVariable或OwnerDrawFixed时,设置ItemHeight才生效。DrawMode属性中有三个成员变量:

    属性值 说明
    Normal 组件里面的所有元素都是操作系统来绘制,并且所有组件大小相同。(默认值)
    OwnerDrawFixed 组件里面的所有元素都是由我们手动绘制,并且大小相同
    OwnerDrawVariable 组件里面的所有元素都是由我们手动绘制,大小可以不相同


    DrawItem事件中,的参数e里面有许多的属性值,包括获取前景色和背景色,获取当前绘制行(焦点行)从0开始的索引,获取字体、画笔、范围、状态等等很多的内容。这次试用的是索引,字体,画笔和范围。

    在定时器中先为ListBox要显示的歌词进行赋值,代码如下:

    <span style="font-size:18px;">private void timer1_Tick(object sender, EventArgs e)
    {	
    	//也几行可以写在定时器外面
    	int totalHeight = listShowSongLrc.Height;
    	//设置显示的每一项的高度
    	int height = listShowSongLrc.ItemHeight = 30;
    	//需要显示多少行歌词
    	int num = totalHeight / height;
    	//显示歌词为奇数行,方便获取当前歌词行
    	num = num%2==1?num:num-1;
    	
    	if (songLrc != null)
    	{
    		#region MyRegion
    		for (int i = 0; i < songLrc.Length - 1; i++)
    		{
    		   //歌曲当前位置
    			string currenPosition = axMediaPlayer.Ctlcontrols.currentPositionString;
    			
    			//歌曲唱的过程中,显示当前歌词的前后各num/2行
    			if (CheckTime(currenPosition, songLrc[i]) && CheckTime(songLrc[i + 1], currenPosition))
    			{
    				//清除只能够放在if里面,放在if外面基本上看不到歌词
    				listShowSongLrc.Items.Clear();
    
    				for (int x = (i - num / 2); x <= (i + num / 2); x++)
    				{
    					listShowSongLrc.Items.Add(x < 0 || x >= songLrc.Length ? "" : GetSongLrc(x));
    				}
    			}
    			//歌曲唱完以后,后面显示为空
    			if (CheckTime(currenPosition, songLrc[songLrc.Length - 1]))
    			{
    				listShowSongLrc.Items.Clear();
    				for (int x = -num / 2; x <= num / 2; x++)
    				{
    					listShowSongLrc.Items.Add(x <= 0 ? GetSongLrc(songLrc.Length - 1 + x) : "");
    				}
    			}
    			//歌词还没有开始显示的时候,中间显示歌名,后面显示前几行歌词
    			if (CheckTime(songLrc[0], currenPosition))
    			{
    				listShowSongLrc.Items.Clear();
    				for (int x = -num / 2; x <= num / 2; x++)
    				{
    					listShowSongLrc.Items.Add(x > 0 ? GetSongLrc(x) : (x < 0 ? "" : listShowSong.Items[listSong.IndexOf(axMediaPlayer.URL)]));
    				}
    			}
    			//让每一项获得焦点,调用歌词绘制事件DrawItem
    			for (int j = 0; j < listShowSongLrc.Items.Count; j++)
    			{
    				listShowSongLrc.SelectedIndex = j;
    			}
    		}
    		#endregion
    	}
    	else
    	{
    		listShowSongLrc.Items.Clear();
    		for (int x = 0; x < num; x++)
    		{                       
    			listShowSongLrc.Items.Add(x != num / 2 ? "" : "---未  找  到  歌  词---");
    		}
    	}
    }</span>


    上面涉及到两个方法,比较当前时间和歌词的时间大小方法。歌词中,是按照时间来进行一个排序的,每一行歌词前面是时间,然后用’|‘和歌词分割,可以百度下一首歌词(.lrc)来看看

    <span style="font-size:18px;">        private bool CheckTime(string str1, string str2)
            {
                return string.CompareOrdinal(str1, 0, str2, 0, str2.Length) > 0;
            }</span>


    获取当前时间的歌词方法,歌词是存放在一个数组中,传递过来当前要获取的行数,进行歌词的分割,然后返回

    <span style="font-size:18px;"> private string GetSongLrc(int i)
            {
                return songLrc[i].Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries)[1];
            }</span>


    接下来便是ListBox中歌词的绘制,是通过画图的方式来实现的(GDI+)

    <span style="font-size:18px;">private void listShowSongLrc_DrawItem(object sender, DrawItemEventArgs e)
    {
    	//获取当前绘制的行的索引
    	int index = e.Index;
    	Graphics g = e.Graphics;
    	//得到每一项的绘制区域大小
    	Rectangle bound = e.Bounds;
    	//得到当前项的文本内容
    	string text = listShowSongLrc.Items[index].ToString();
    	
    	//判断当前选择的项是正在唱的歌词,也就是中间一行歌词
    	if (index == listShowSongLrc.Items.Count / 2)
    	{//如果当前行为选中行。
    		//绘制选中时要显示的蓝色边框,实际不需要就注释掉了
    		// g.DrawRectangle(Pens.Blue, bound.Left, bound.Top, bound.Width - 1, bound.Height - 1);
    		//绘制边框后,里面的矩形框大小改变,故重新定义一个,如果没有绘制边框就不需要重新定义
    		Rectangle rect = new Rectangle(bound.Left - 1, bound.Top - 1,
    									   bound.Width - 2, bound.Height - 2);
    		//绘制选中时要显示的蓝色背景。可以选中其它色,此处省略了背景绘制
    		// g.FillRectangle(Brushes.Blue, rect);
    		//定义一个字体,是用来绘制显示的当前歌词文本。
    		Font font = new System.Drawing.Font("微软雅黑", 18, FontStyle.Bold & FontStyle.Italic);
    		//绘制歌词,颜色为红色
    		TextRenderer.DrawText(g, text, font, rect, Color.Red,
    							  TextFormatFlags.VerticalCenter);
    	}
    	else
    	{   
    		//定义一个颜色为白色的画刷
    		using (Brush brush = new SolidBrush(Color.White))
    		{
    			g.FillRectangle(brush, bound);//绘制背景色。
    		}
    		//填充字体,字体的颜色为黑色
    		TextRenderer.DrawText(g, text, this.Font, bound, Color.Black,
    							  TextFormatFlags.VerticalCenter | TextFormatFlags.Left);
    	}
    }</span>


    至此,整个歌词的自动绘制就基本上完成了,显示效果除了当前行是用红色一次性显示完成意外,其余的滚动和酷狗音乐中歌词写真基本上是一样的。



  • 相关阅读:
    scrapy中selenium的应用
    Django的锁和事务
    redis
    【leetcode】187. Repeated DNA Sequences
    【leetcode】688. Knight Probability in Chessboard
    【leetcode】576. Out of Boundary Paths
    【leetcode】947. Most Stones Removed with Same Row or Column
    【leetcode】948. Bag of Tokens
    【leetcode】946. Validate Stack Sequences
    【leetcode】945. Minimum Increment to Make Array Unique
  • 原文地址:https://www.cnblogs.com/qigang/p/3841942.html
Copyright © 2011-2022 走看看