`
NeighborWolf
  • 浏览: 3060 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java模仿Kugou,实现歌词秀

阅读更多
Kugou的歌词秀如图:


我模拟的效果如图所示.


鼠标选中后如图:




歌词秀有以下细节注意点:
  1、没有“窗口”,直接在桌面上绘制歌词
  2、歌词文字是彩色的,且颜色渐变。已唱歌词与未唱歌词的渐变色不同。歌词、、文字有黑色边框,以便于周围背景清晰区分
  3、歌词可拖动,当鼠标移上去时会变成可拖动的形状

用Java实现,有以下技术点:
  1、透明窗口
       这个需要借助JNA来实现,通过
       System.setProperty("sun.java2d.noddraw", "true"); 
       WindowUtils.setWindowTransparent(this,true);
     使得窗口透明

2、渐变的彩色文字,使用GradientPaint填充一个BufferedImage,BufferedImage的渐变色即为歌词的渐变色。然后取得歌词的形状,
       用此BufferedImage填充即可。比较麻烦的是文字的黑色边框,这个最后想了一个办法就是分别向上下左右偏移一个像素绘制
       黑色的歌词,然后在其上绘制正常的彩色渐变歌词,这样最终的叠加相关就正好是我们需要的效果。

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.TexturePaint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.LinkedList;
import java.util.List;

import javax.swing.*;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.examples.WindowUtils;
import com.sun.jna.examples.win32.User32;
import com.sun.jna.examples.win32.W32API;
import com.sun.jna.ptr.IntByReference;

/**
 * 卡拉OK歌词效果,模仿Kugou桌面上的歌词秀
 * @author 李涛
 * @version v1.0    2011-09-11
 *
 * 歌词秀有以下细节注意点:
 * 1、没有“窗口”,直接在桌面上绘制歌词
 * 2、歌词文字是彩色的,且颜色渐变。已唱歌词与未唱歌词的渐变色不同。歌词、、文字有黑色边框,以便于周围背景清晰区分
 * 3、歌词可拖动,当鼠标移上去时会变成可拖动的形状
 * 
 * 用Java实现,有以下技术点:
 * 1、透明窗口
 *    这个需要借助JNA来实现,通过
 *    System.setProperty("sun.java2d.noddraw", "true");  
 *    WindowUtils.setWindowTransparent(this,true);
 *    使得窗口透明
 * 
 * 2、渐变的彩色文字,使用GradientPaint填充一个BufferedImage,BufferedImage的渐变色即为歌词的渐变色。然后取得歌词的形状,
 *    用此BufferedImage填充即可。比较麻烦的是文字的黑色边框,这个最后想了一个办法就是分别向上下左右偏移一个像素绘制
 *    黑色的歌词,然后在其上绘制正常的彩色渐变歌词,这样最终的叠加相关就正好是我们需要的效果。
 */

public class LyncWin extends JDialog {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JLabel infoLabel;
	private MyCloseButton closeButton;
	
	static List<String> msgList = new LinkedList<String>();
	public LyncWin()
	{
		setTitle("卡拉OK歌词Demo");                                  
		setBounds(300, 200, 800, 110);         
		final ContentPane panel = new ContentPane();
		this.setContentPane(panel);
		MyMouseListener m = new MyMouseListener(this, panel);
		panel.addMouseListener(m);
		panel.addMouseMotionListener(m);
		getContentPane().setLayout(null);   
		
		this.getRootPane().setOpaque(false);
		
		closeButton = new MyCloseButton(this);
		closeButton.setOpaque(false);
		closeButton.setBounds(0, 0, 18, 18);   
		closeButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}});
		closeButton.setVisible(false);
		add(closeButton);
		
		setResizable(false);
		this.setUndecorated(true);
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		//com.sun.awt.AWTUtilities.setWindowOpacity(this, 0.93f); 
		//com.sun.awt.AWTUtilities.setWindowShape(this, new Ellipse2D.Double(0, 0, getWidth(),getHeight()));
		
        this.setAlwaysOnTop(true);        

        initMsg();
        new Timer(30, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                LyncWin.this.repaint();//infoLabel.setText(msgList.get(i++));
            }
        }).start();
        
        panel.addMouseListener(new MouseAdapter(){
  			@Override
			public void mouseEntered(MouseEvent e) {
				closeButton.animateShow();
				panel.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
			}

			@Override
			public void mouseExited(MouseEvent e) {
				closeButton.animateHide();
			}});
        
        System.setProperty("sun.java2d.noddraw", "true");  
        WindowUtils.setWindowTransparent(this,true);
        
        this.setVisible(true);
	}

//	private void makeWinTransparent() {
//		Pointer winPointer = Native.getComponentPointer(this);
//        W32API.HWND hwnd = new W32API.HWND();
//        hwnd.setPointer(winPointer); 
//        IntByReference color = new IntByReference(this.getBackground().getRGB());
//        
//        User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_EXSTYLE, User32.INSTANCE.GetWindowLong(hwnd, User32.GWL_EXSTYLE)|User32.WS_EX_LAYERED);
//        User32.INSTANCE.SetLayeredWindowAttributes(hwnd, this.getBackground().getRGB(), (byte)220, User32.LWA_COLORKEY);
//        this.setVisible(false);
//        this.setVisible(true);
//	}
	
	void initMsg(){
		try {
			LineNumberReader lnr = new LineNumberReader(new InputStreamReader(Class.class.getResourceAsStream("/Msg.ini")));
			while(lnr.ready()){
				msgList.add(lnr.readLine());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	class ContentPane extends JPanel{
		private static final long serialVersionUID = 1L;
		int i = 0; //哪一行歌曲文字
		int length = 0; //本行文字的宽度
		String msg = null;
		BufferedImage bufferedImage;
		//已唱文字的渐变色彩
		
		private Color gradientStart = new Color(238,254,218);
		private Color gradientCenter = new Color(153,254,17);
		private Color gradientEnd = new Color(232,254,3);
		
		//未唱文字的渐变色彩
		private Color gradientEndU = new Color(14,104,0);
		private Color gradientStartU = new Color(134,242,32);
		public ContentPane(){
			setFont(new Font("黑体",Font.BOLD,40));
			this.setOpaque(false);
			this.setForeground(this.getBackground());
		}
		
		@Override
		protected void paintComponent(Graphics g){
			if(msg ==null){
				msg = msgList.get(0);
			}
			Graphics2D g2 = (Graphics2D)g.create();
			RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
	                RenderingHints.VALUE_ANTIALIAS_ON);
	        hints.put(RenderingHints.KEY_INTERPOLATION,
	                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
	        hints.put(RenderingHints.KEY_RENDERING,
	                RenderingHints.VALUE_RENDER_QUALITY);
			
	        g2.setRenderingHints(hints);
	        
			g2.setColor(new Color(0,0,0));
			g2.setFont(getFont());
			FontMetrics fm = getFontMetrics(getFont());
			Rectangle2D rect = fm.getStringBounds(msg, g2);
			if(length>rect.getWidth()){
				length = 0;
				if(i>=msgList.size()){
					i=0;
					msg = msgList.get(i++);
					fm = getFontMetrics(getFont());
					rect = fm.getStringBounds(msg, g2);
				}else{
					msg = msgList.get(++i);
					fm = getFontMetrics(getFont());
					rect = fm.getStringBounds(msg, g2);
				}
			}
			
			int x = 0;
			int y = 48;
			
			//当关闭按钮可见时,说明鼠标移上来了,此时绘制一个半透明的底纹,以便于用户操作(否则只有当鼠标在文字轮廓
			//上时才能收到鼠标事件
			if(closeButton.isVisible()){
				Graphics2D newg = (Graphics2D)g.create();
				newg.setColor(Color.gray);
				newg.setComposite(AlphaComposite.SrcOver.derive((float)(closeButton.alpha*0.5)));
				newg.fillRoundRect(x,y-((int)rect.getHeight()-fm.getDescent()*3),(int)rect.getWidth(),(int)rect.getHeight(),10,10);
				newg.dispose();
			}
			
			//上下左右各偏离1个像素绘制黑色歌词,经过后面的彩色歌词覆盖后,即变成文字的黑色轮廓
			g2.drawString(msg, x-1, y);
			g2.drawString(msg, x+1, y);
			g2.drawString(msg, x, y+1);
			g2.drawString(msg, x, y-1);
			
			//绘制渐变彩色歌词
	        createBufferedImage(fm, rect,length++);
			TexturePaint tp = new TexturePaint(bufferedImage, rect);
			FontRenderContext frc = g2.getFontRenderContext();
			TextLayout tl = new TextLayout(msg, getFont(), frc);
	        g2.setPaint(tp);
	        
	        g2.translate(0, y);
	        g2.fill(tl.getOutline(null));
	        g2.translate(0, -y);
	        
			//g2.drawImage(bufferedImage, null, x, y+14);
			
			g2.dispose();
		}
		
		//采用渐变色绘制文字
		protected void createBufferedImage(FontMetrics fm, Rectangle2D rectStr,int length) {
	        int width = (int)rectStr.getWidth();
	        int height = (int)rectStr.getHeight()-fm.getDescent()*2;

	        bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

	        //绘制已唱的文字
	        Graphics2D g2 = bufferedImage.createGraphics();
	        GradientPaint painter = new GradientPaint(0, 0, gradientStart, 0, height / 2, gradientCenter);
			g2.setPaint(painter);
			Rectangle2D rect = new Rectangle2D.Double(0, 0, length, height / 2.0);
			g2.fill(rect);

			painter = new GradientPaint(0, height / 2, gradientCenter, 0,height, gradientEnd);
			g2.setPaint(painter);
			rect = new Rectangle2D.Double(0, height / 2.0 , length,height);
			g2.fill(rect);
			
			painter = new GradientPaint(0, height / 2-2, gradientCenter, 0,height, gradientCenter);
			g2.setPaint(painter);
			rect = new Rectangle2D.Double(0, (height / 2.0)-2 , length, 4);
			g2.fill(rect);
			
			//绘制未唱的文字
	        painter = new GradientPaint(0, 0, gradientStartU, 0, height, gradientEndU);
			g2.setPaint(painter);

			rect = new Rectangle2D.Double(length, 0, width-length, height);
			g2.fill(rect);

			g2.dispose();
	   }
	}
	
	public static void main(String[] args){
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		} 
		new LyncWin();
	}
}

  • 卡拉OK歌词秀.jar (1.1 MB)
  • 描述: 直接运行即可看到效果,在Windows和Mac上都已测试,可正常运行
  • 下载次数: 166
3
14
分享到:
评论
4 楼 aak 2017-09-25  
楼主,强大。我参考你的思路,实现了一个播放器:https://github.com/zhangliangming/HappyPlayer-PC.git
3 楼 longen2011 2015-04-23  
会有闪屏,怎么用双缓冲解决,大神?
2 楼 longen2011 2015-04-23  
没有权限下载,谁能给个源代码我?
1 楼 yangxiutian 2012-06-07  
模仿的很像,是个牛人 ,我一直想把krc解析出来(苦于不知道它的文本和时间信息怎么存储,找不到相关资料),不行的话自己设计一直文件格式也行(速度要能控制到每一个字符),可是我还没想到怎么做,能指点一下吗,谢谢。

相关推荐

    模仿酷狗7(Kugou7)界面——Java版

    【标签】"模仿酷狗7(Kugou7)界面——Java版"再次强调了项目的核心目标,即用Java来实现酷狗7的界面复刻。标签通常用于分类和搜索,帮助其他对类似项目感兴趣的人找到这个资源。 【压缩包子文件的文件列表】: 1. **...

    模仿酷狗7(Kugou7)界面V0.2——Java版

    【标题】"模仿酷狗7(Kugou7)界面V0.2——Java版"是一个项目,旨在通过Java编程语言复刻酷狗音乐播放器Kugou7的用户界面。这个项目展示了如何使用Java来创建一个类似流行音乐应用的交互式界面,为用户提供相似的音乐...

    java Kugou

    java Kugou 很好的工具包,具体很详细的

    模仿酷狗7(Kugou7)界面源码

    【标题】"模仿酷狗7(Kugou7)界面源码"揭示了这个项目的核心是复制酷狗7音乐播放器的用户界面设计。酷狗7是一款知名的数字音乐服务软件,以其简洁的操作界面和丰富的音乐资源受到用户的喜爱。该源码的目的在于让...

    VC模仿酷狗7(Kugou7) UI界面源码,有动画效果

     VC模仿酷狗7(Kugou7) UI界面源码,有动画效果,原创作者:邓学彬(泪闯天涯)  源码说明:内含VC++源码、易语言源码各一份.包含所有图片源码(使用Fireworks编辑)  开发环境:VC版--VS2005、Gdiplus;易语言版--...

    VB 制作仿KUGOU播放器 桌面歌词效果

    VB 制作仿KUGOU播放器 桌面歌词效果 VB制作仿KUGOU播放器桌面歌词效果,可能这种效果很多朋友都见到过,就是把播放某首音乐的歌词显示在桌面上,其实不是桌面,是显示在屏幕下方,不过歌词字体很大,而且经过了修饰...

    VC 仿酷狗音乐桌面歌词效果源码.rar

    VC 仿酷狗音乐桌面歌词效果源码 仿QQ音乐等播放器的桌面上显示歌词效果,不过这个...演示如何制作桌面歌词秀  2.未实现卡拉OK的进度效果,本源码中仅是改变文字颜色颜色,修改下就能做到。  3.在XP VC6.0上调试通过

    C#实现歌词显示.LRC歌词

    本项目“C#实现歌词显示.LRC歌词”是利用C#语言开发的一个功能,它允许用户在应用程序中实时显示歌曲的LRC格式歌词,类似于知名的音乐播放器酷狗(KUGOU)的功能。 LRC歌词是一种特殊的文本格式,主要用于存储带有...

    用Java做一个管理Kugou下载的歌的小工具

    【标题】:“用Java做一个管理Kugou下载的歌的小工具” 这个项目是关于使用Java编程语言开发一个小型应用程序,它的主要功能是管理和处理从酷狗音乐平台下载的歌曲。酷狗音乐是中国知名的数字音乐服务提供商,提供...

    酷狗安装程序kugou8395.exe

    酷狗安装程序kugou8395.exe酷狗安装程序kugou8395.exe酷狗安装程序kugou8395.exe酷狗安装程序kugou8395.exe酷狗安装程序kugou8395.exe

    kugou7界面

    【Kugou7界面】是基于用户界面设计的一款模仿酷狗音乐7版本的软件界面,以其独特的美感和用户体验而受到用户的喜爱。这个界面设计注重细节,力求在视觉效果和功能性之间找到平衡,为用户提供一个既美观又易于操作的...

    VC模仿酷狗7(Kugou7) UI界面源码,有动画效果.rar

    VC模仿酷狗7(Kugou7) UI界面源码,有动画效果,原创作者:邓学彬(泪闯天涯) 源码说明:内含VC 源码、易语言源码各一份.包含所有图片源码(使用Fireworks编辑) 开发环境:VC版--VS2005、Gdiplus;易语言版--易语言5,...

    Kugou界面源码_C++_kugou_GUI_

    8. **文本处理**:Kugou的界面可能包含歌词显示功能,这就需要处理Unicode字符集和文本渲染。Qt等库提供了方便的文本处理工具。 9. **版本控制**:"80编程社区宣言"和"80句话实现所有编程梦想.txt"可能是关于编程...

    win32实现模仿酷狗QQ的带有广告的进度条

    本文将深入探讨如何使用Win32 API来实现一个模仿酷狗和QQ风格的带有广告的进度条。这个过程涉及到窗口创建、消息处理、绘图以及动态更新等多个知识点。 首先,我们需要理解进度条的基本结构。在Win32中,我们可以...

    Kugou-Control.zip

    Kugou-Control 是酷狗控制工具。 标签:Kugou

    kugou.rar_kugou_酷狗音乐特效

    综合以上信息,这个项目可能是C#开发者通过深入分析酷狗音乐的特效实现,以学习和模仿为目标的案例。开发者可以通过解析源代码,了解如何使用C#来实现动态界面效果,包括但不限于使用控件动画、图形渲染技术、事件...

    kugou基于vuevux的酷狗音乐

    2. **API调用**:酷狗音乐的API被用来获取歌曲信息、播放列表、歌词等数据,这通常涉及异步请求处理,可以使用axios或fetch等库来实现。 3. **状态管理**:可能采用了Vuex来集中管理应用的状态,如当前播放的歌曲、...

    kugou.zip_kugou_音乐盒

    【标题】"kugou.zip_kugou_音乐盒" 指的是一个与酷狗音乐盒相关的压缩文件,其中可能包含酷狗音乐播放软件的界面样式资源和代码,用于实现独特的窗口效果,如窗口之间的无缝连接。 【描述】中的“酷狗音乐盒的窗口...

Global site tag (gtag.js) - Google Analytics