`
i2534
  • 浏览: 182820 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

swing做的简易的lrc显示组件

    博客分类:
  • util
阅读更多

今天上班实在是无法静下心来工作,突然想到给我以前写的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;
	}
}
分享到:
评论

相关推荐

    musicPlayer123_swing_音乐播放器_

    在Java编程领域,Swing库是一个非常重要的组件,它提供了丰富的图形用户界面(GUI)工具,用于构建桌面应用程序。本项目“musicPlayer123_swing_音乐播放器_”显然是一个利用Swing来实现的音乐播放器。下面将详细...

    wav简易音乐播放器java实现

    - 歌词显示:可以解析LRC格式的歌词文件,将歌词与时间戳关联,根据播放进度展示相应的歌词。 5. WAV文件读取与播放: - 使用`AudioInputStream`读取WAV文件,通过`Clip`对象进行播放控制。 - ` Clip.open(Audio...

    Java音乐播放器歌词同步

    Java音乐播放器歌词同步是一个基于Java编程语言开发的简易音乐播放器,主要特色在于实现歌词与音乐播放的同步。在本文中,我们将深入探讨这个项目的核心技术和相关知识点,以帮助你理解和掌握Java在多媒体处理方面的...

    java音乐播放器

    【Java音乐播放器】是一个基于Java编程语言开发的全功能音乐播放软件,它不仅具备了基本的音频播放功能,还特别加入了LRC歌词同步显示,为用户提供了丰富的音乐体验。这款音乐播放器的设计考虑到了跨平台性,因此既...

    java开源音乐播放器

    Swing是Java标准库的一部分,提供了丰富的用户界面组件,用于构建桌面应用,包括音乐播放器这样的多媒体应用程序。这款播放器因其开源特性而备受青睐,允许开发者深入研究其代码,学习并扩展其功能。 在音乐播放器...

    音乐播放器

    3. **歌词显示**:为了实时同步显示歌词,开发者可能使用LRC(Lyrics)文件格式,这是一种时间标记的文本格式,用于存储歌曲的逐句歌词。解析LRC文件并将其与音乐播放进度同步是实现这一功能的关键。 4. **图形用户...

    Java MP3播放器

    虽然在给出的代码片段中没有详细展示歌词显示的具体实现方式,但可以推测这可能通过读取单独的歌词文件(通常是.txt或.lrc格式),并在`JTextArea`组件中动态更新歌词内容来实现。 ```java TextArea textArea = new...

    音乐播放器——湘潭大学JAVA课程设计题目

    使用Swing或JavaFX等图形用户界面库可以创建进度条组件。 4. **示波器波形图显示**:示波器波形图能直观地展示音乐的音频信号。这通常通过读取音频数据并进行傅立叶变换来实现,然后将结果显示在图形界面上。可能...

    Java课程设计——电子音乐盒

    程序会解析LRC文件中的时间标签,并将对应的歌词在界面上适时滚动显示,增强用户的听歌体验。为了使功能正常工作,用户需要将歌词文件放置在播放器指定的目录下,与对应的音乐文件一起。 在开发过程中,学生需要...

    歌词制造器(集成了mp3播放器)

    4. **用户界面**:为了方便用户操作,歌词制造器可能使用JavaFX或Swing等GUI工具包来构建用户界面,包括播放、暂停、停止等控制按钮,以及歌词显示区域。 5. **事件监听和处理**:为了响应用户的操作,如点击播放...

    简单MP3播放Java程序

    这些库提供了各种组件,如按钮、文本框和标签,用于构建播放、暂停、停止等控件,以及歌词显示区域。 7. **事件监听**: 播放器中的按钮和其他交互元素需要监听用户的操作,例如点击播放按钮会触发播放事件。这是...

    Java音乐播放器

    同时,为了实现音乐播放器的界面,开发者可能使用了Java Swing或JavaFX库,它们提供了丰富的UI组件,如按钮、播放进度条、音量控制等,用于构建一个用户友好的界面。 歌词同步功能是该播放器的一大亮点。这通常涉及...

    基于jmf的mp3播放器

    - **播放器界面**:通常使用Swing或JavaFX等GUI库构建用户界面,包括播放按钮、进度条、音量控制、歌词显示区域等组件。 - **音频流处理**:JMF的`Player`类用于播放音频流,开发者需要创建`Player`实例,加载MP3...

    一个通用的工具类core.7z

    在JavaFX或Swing中,可以改变组件的外观和感觉(LookAndFeel)。 5. **调节亮度**:对于支持这一特性的平台,例如Android,可以通过改变系统或应用程序的亮度设置来实现。这通常涉及到获取和设置系统的亮度值,或者...

    Java课程设计-音乐播放器.pdf

    音乐播放器的开发涉及到了多个技术组件: 1. **Java Sound API**:Java Sound API是Java标准版平台提供的底层声音处理接口,能够实现录音、播放和编辑声音等多种功能。它还允许通过服务提供者接口(SPI)来扩展支持...

    YOYOPlayer1.2

    考虑到支持歌词显示,播放器界面很可能有一个专门区域用于实时滚动显示歌词,这部分可能采用了类似于LRC格式的歌词文件解析技术。 对于多平台支持,开发者可能利用了Java的JNI(Java Native Interface)技术与各...

    Java仿千千静听音乐播放器源代码

    8. **歌词同步**:如果项目包含歌词同步功能,开发者需要解析LRC格式的歌词文件,并在播放过程中实时更新歌词显示。 9. **设计模式**:在开发大型项目时,设计模式如单例模式、工厂模式等可以帮助保持代码结构清晰...

    java编写的基于jmf的音乐播放器

    开发者需要解析LRC文件,将歌词与音乐的时间轴同步,然后根据音乐播放的进度实时更新歌词显示。这可以通过定时器或者监听音乐播放器的事件来实现。 4. **进度条拖动** 进度条拖动功能允许用户自由调整音乐播放的...

    MP3音乐播放器

    项目通过联网获取与当前播放歌曲对应的LRC歌词文件(一种文本格式,包含时间戳和歌词内容)。开发者可能使用HTTP或HTTPS协议发送请求到歌词服务器,接收到响应后解析出歌词内容,并将其同步显示在界面上,以便用户在...

    ktv.rar_KTV

    3. 实时歌词同步:通过LRC文件或者API获取歌词信息,配合歌曲播放实现逐句滚动显示,提升用户体验。 四、系统扩展性 1. 蓝牙/网络点歌:为了满足不同场景需求,系统应支持蓝牙设备或网络进行点歌,这需要Java的...

Global site tag (gtag.js) - Google Analytics