swing做的简易的lrc显示组件

今天上班实在是无法静下心来工作,突然想到给我以前写的mp3播放器添加一个歌词显示组件.

大概思路是这样.

在一个组件上绘制出所有的歌词信息.

然后按照歌曲进度和歌词所在的进度移动示口,把要显示的那行歌词显示在组件中央.

如果必要,可以重绘组件屏幕中央的那行文字.加上一些效果.(现在没有做)

而且也没有做offset的修正.

 

现在实在是太简陋了,等有空再完善.要做的事实在太多了.

那个ProgressListener在我以前的文章<swing做的mp3播放器>中.

 

首先是lrc模型,歌词的内容保存在TreeMap中,key为歌词开始的时间.单位为毫秒.value为歌词.

package jmp123.shell.lrc;

import java.util.TreeMap;

class LRC {
	private String						artist;
	private String						title;
	private String						album;
	private String						maker;
	private int							offset;

	private TreeMap<Integer, String>	texts;

	public String getArtist() {
		return this.artist;
	}

	public void setArtist(String artist) {
		this.artist = artist;
	}

	public String getTitle() {
		return this.title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAlbum() {
		return this.album;
	}

	public void setAlbum(String album) {
		this.album = album;
	}

	public String getMaker() {
		return this.maker;
	}

	public void setMaker(String maker) {
		this.maker = maker;
	}

	public int getOffset() {
		return this.offset;
	}

	public void setOffset(int offset) {
		this.offset = offset;
	}

	public TreeMap<Integer, String> getTexts() {
		if (this.texts == null) {
			this.texts = new TreeMap<Integer, String>();
		}
		return this.texts;
	}

}

 接着是读取和显示组件:

package jmp123.shell.lrc;

import java.awt.Dimension;

/**
 * 读取歌词 <br>
 * 
 * @日期. 2010-10-9 下午01:27:49
 */
public class LRCReader extends JScrollPane {

	private class DisplayComponent extends JComponent {
		/**
		 * 
		 */
		private static final long	serialVersionUID	= -1926347751983144607L;

		@Override
		protected void paintComponent(Graphics g) {
			int width = LRCReader.this.getViewport().getWidth();
			int height = this.getStringHeight();

			int y = (LRCReader.this.getViewport().getHeight() - height) / 2;
			String title = "标题: " + LRCReader.this.lrc.getTitle();
			g.drawString(title, (width - this.getStringWidth(title)) / 2, y);
			y += height;

			String artist = "艺术家: " + LRCReader.this.lrc.getArtist();
			g.drawString(artist, (width - this.getStringWidth(artist)) / 2, y);
			y += height;

			String album = "专辑: " + LRCReader.this.lrc.getAlbum();
			if (album != null) {
				g
						.drawString(album,
								(width - this.getStringWidth(album)) / 2, y);
			}
			y += height;

			String maker = LRCReader.this.lrc.getMaker();
			if (maker != null) {
				maker = "By: " + maker;
				g
						.drawString(maker,
								(width - this.getStringWidth(maker)) / 2, y);
			}
			y += height;

			// 空一行
			y += height;

			LRCReader.this.raise = height * 5 * 1000
					/ LRCReader.this.lrc.getTexts().firstKey();

			// 内容
			for (String s : LRCReader.this.lrc.getTexts().values()) {
				g.drawString(s, (width - this.getStringWidth(s)) / 2, y);
				y += height;
			}

			if (this.getHeight() < y) {
				this.setPreferredSize(new Dimension(this.getWidth(), y));
			}

		}

		private int getStringWidth(String text) {
			Graphics g = this.getGraphics();
			FontMetrics fm = g.getFontMetrics();
			int w = 0;
			for (char c : text.toCharArray()) {
				w += fm.charWidth(c);
			}
			return w;
		}

		private int getStringHeight() {
			Graphics g = this.getGraphics();
			FontMetrics fm = g.getFontMetrics();
			return fm.getAscent() + fm.getDescent() + fm.getLeading();
		}

		public void update(int current) {
			Integer key = LRCReader.this.lrc.getTexts().floorKey(current);
			System.out.println("Current:" + current + ";Key:" + key);
			if (key != null) {
				if (key != LRCReader.this.lrc.getTexts().firstKey()) {
					Integer next = LRCReader.this.lrc.getTexts().higherKey(key);
					if (next != null) {
						int i = next - key;
						if (i > 0) {
							LRCReader.this.raise = this.getStringHeight()
									* 1000 / i;
							System.out.println(raise);
						}
					}
				}
			}
		}
	}

	/**
	 * 
	 */
	private static final long	serialVersionUID	= 7690089125689655670L;

	/**
	 * artist艺术家、演唱者
	 */
	private static final String	TAG_AR				= "ar";
	/**
	 * title题目,标题,曲目
	 */
	private static final String	TAG_TI				= "ti";
	/**
	 * album唱片集、专辑
	 */
	private static final String	TAG_AL				= "al";
	/**
	 * (介词)制作者、编辑人员(一般指lrc歌词的制作人)
	 */
	private static final String	TAG_BY				= "by";
	/**
	 * 其单位是毫秒,正值表示延迟,负值表示提前。用于整体调整歌词显示慢(快)于音乐播放。
	 */
	private static final String	TAG_OS				= "offset";
	/**
	 * lrc文件路径
	 */
	private String				path;
	/**
	 * lrc内容
	 */
	private LRC					lrc;

	private ProgressListener	listener;

	private volatile int		raise;
	/**
	 * 匹配标签
	 */
	private static Pattern		PATTER_TAG			= Pattern
															.compile("\\[(.*?)\\]");
	/**
	 * 匹配时间
	 */
	private static Pattern		PATTER_TIME			= Pattern
															.compile("(\\d+):(\\d+)(\\.(\\d+))?");

	public LRCReader(String path) {
		this.path = path;

		this
				.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		this
				.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);

		this.init();
	}

	private void init() {
		if (this.path != null) {
			try {
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(new FileInputStream(this.path),
								"GBK"));
				String line = null;
				this.lrc = new LRC();
				while ((line = reader.readLine()) != null) {
					if (line.trim().length() > 0) {
						Matcher tagMatcher = LRCReader.PATTER_TAG.matcher(line);
						while (tagMatcher.find()) {
							String tag = tagMatcher.group(1).trim();
							Matcher timeMatcher = LRCReader.PATTER_TIME
									.matcher(tag);
							if (timeMatcher.matches()) {// lrc内容
								String m = timeMatcher.group(1);
								String s = timeMatcher.group(2);
								String ms = timeMatcher.group(4);
								int tms = 0;
								tms += Integer.valueOf(m) * 60 * 1000;
								tms += Integer.valueOf(s) * 1000;
								if (ms != null) {
									tms += Integer.valueOf(ms);
								}
								String text = line.substring(
										line.lastIndexOf("]") + 1).trim();
								this.lrc.getTexts().put(tms, text);
							} else {// tags
								if (tag != null) {
									String[] array = tag.split(":");
									String key = array[0].trim();
									String value = array[1].trim();
									if (LRCReader.TAG_AL.equalsIgnoreCase(key)) {
										this.lrc.setAlbum(value);
									} else if (LRCReader.TAG_AR
											.equalsIgnoreCase(key)) {
										this.lrc.setArtist(value);
									} else if (LRCReader.TAG_BY
											.equalsIgnoreCase(key)) {
										this.lrc.setMaker(value);
									} else if (LRCReader.TAG_OS
											.equalsIgnoreCase(key)) {
										this.lrc.setOffset(Integer
												.valueOf(value));
									} else if (LRCReader.TAG_TI
											.equalsIgnoreCase(key)) {
										this.lrc.setTitle(value);
									}
								}
							}
						}
					}
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		if (this.lrc != null) {
			this.setViewportView(new DisplayComponent());

			final Timer timer = new Timer(1000, new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					JViewport vp = LRCReader.this.getViewport();
					Point p = vp.getViewPosition();
					p.setLocation(p.x, p.y + LRCReader.this.raise);

					if (p.y < vp.getView().getHeight() - vp.getHeight() / 2) {
						vp.setViewPosition(p);
					}
				}

			});
			timer.start();
		}
	}

	public ProgressListener getLRCListener() {
		if (this.listener == null) {
			this.listener = new ProgressListener() {

				public void update(ProgressEvent event) {
					int current = (int) (event.getLength() * 1000
							* event.getFrame() / event.getFrames());
					((DisplayComponent) LRCReader.this.getViewport().getView())
							.update(current);
				}

			};
		}
		return this.listener;
	}

	public static void main(String[] args) {
		LRCReader r = new LRCReader("E:\\music\\lyrics\\王力宏 - 十八般武艺_1.lrc");
		LRC lrc = r.lrc;
		System.out.println(lrc.getArtist());
		for (Map.Entry<Integer, String> entry : lrc.getTexts().entrySet()) {
			System.out.println(entry.getKey() + " : " + entry.getValue());
		}
	}
}

 测试类:

package jmp123.shell.lrc;

import java.awt.BorderLayout;

public class LRCTest extends JFrame {

	/**
	 * 
	 */
	private static final long	serialVersionUID	= -9185495379210075085L;
	private JPanel				contentPane;
	private LRCReader			reader;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					LRCTest frame = new LRCTest();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public LRCTest() {
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setBounds(100, 100, 450, 431);
		this.contentPane = new JPanel();
		this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		this.contentPane.setLayout(new BorderLayout(0, 0));
		this.setContentPane(this.contentPane);
		this.contentPane.add(this.getReader(), BorderLayout.CENTER);
	}

	private LRCReader getReader() {
		if (this.reader == null) {
			this.reader = new LRCReader("E:\\music\\lyrics\\王力宏 - 十八般武艺_1.lrc");
			final ProgressListener pl = this.reader.getLRCListener();
			new Timer(1000, new ActionListener() {

				private int	i	= 0;

				public void actionPerformed(ActionEvent e) {
					pl.update(new ProgressEvent(null, 240, 240, i++));
				}

			}).start();
		}
		return this.reader;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值