欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java 实现一个桌面弹幕

程序员文章站 2022-06-28 11:11:28
...

 本人菜鸟一枚,最近毕设要做一个桌面弹幕的功能,于是想着能不能用swing做一个。

首先,要实现弹幕,需要一块画布,我们写一个类继承自Jframe 。而且为了不遮挡桌面的其他部分,画布的背景应该是透明。这时我们需要用到

AWTUtilities.setWindowOpaque(this, false);//this 是你的Jframe窗口  把窗口设为透明
这个函数,首先要知道这个函数java默认工程的lib里面是没有加入的,需要额外导入rt.jar包,这个包不需要下载,在你的Jdk安装目录下lib/文件夹就可以找到,找到后直接导入你的工程就行了。

然后就是要把窗口最大化

 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();//获取桌面的大小
 Rectangle bounds = new Rectangle(screenSize); 
 this.setBounds(bounds);                                          //把窗口设为桌面大小
 this.setExtendedState(Frame.MAXIMIZED_BOTH);   
弹幕的窗口应该是在桌面的最上面的,所以你还需要设置
 this.setAlwaysOnTop(true);
java默认的jframe 是带有边框的,所以要把边框禁用
 this.setUndecorated(true);
这样弹幕的背景就算是完成了,接下了就是在背景上吧弹幕画出来。
画弹幕就要重写jframe的paint方法。
 @Override  
    public void paint(Graphics gg) {  
        super.paint(gg);}


这个方法有一个参数Graphics。Jframe每次加载一个控件是都会调用paint方法去绘制。当需要重新绘制时,调用repaint()方法。

后面我们就是通过不断调用repaint方法来让弹幕动起来的。参数Graphics可以理解为画笔,画笔可以设置相关的属性

。比如setColor(Color.RED) 方法把画笔设为红色,setFont()方法设置画笔的字体。先在桌面上画上你个你想要的字符串把。

String hello="Hello" ;
int x=300,y=300;//弹幕的坐标
@Override  
    public void paint(Graphics gg) {  
        super.paint(gg); 
        gg.setColor(Color.BLUE);   //把画笔设为蓝色
        gg.setFront(new 
        Front("Dialog",Font.BOLD,40);      //设置字体和样式,大小40
        gg.drawString(hello,x,y);   //在桌面坐标300,300的地方画出 Hello字符串
    }


结果就是这样了java 实现一个桌面弹幕怎么让弹幕动起来呢,前面讲到,我们需要不断调用repaint方法来进行绘制,于是我们只要不断改变弹幕的坐标

然后repaint,弹幕就动起来了。当然我们要在其他线程里面重新绘制。

 while(true){
         	x--;           //改变x的坐标
             try {  
                 Thread.sleep(10);// 每10ms执行一次
             } catch (InterruptedException e) {  
                 e.printStackTrace();  
             }  
             repaint();//重新绘制
         } 

这样弹幕就动起来啦。

当然弹幕可不只有一条,我们可以用一个list来管理所有的弹幕,每次往list中添加弹幕时就可以实现往屏幕添加弹幕的效果。我们还需要定义一个类DanContent来管理我们的弹幕的各种属性,颜色,大小,字体,坐标等。弹幕的高度可以用随机数控制,只要不超出屏幕就行。

这样pain函数就变为

 public void paint(Graphics gg) {  
        super.paint(gg);  
        int st=0;
        if(list.size()>maxScreenDanmuCount) st=list.size()-maxScreenDanmuCount;
        
    	for(int i=st;i<list.size();i++) {  //绘制list里面的从st开始有字符串
        	DanContent text=list.get(i);
        	if(text.x<-windowwidth)continue;   //如果弹幕坐标不在屏幕,就不画了。
        	gg.setColor(getColor(text.getColor()));
        	gg.setFont(new Font("楷体",text.getStyle(), text.getSize()));
        	gg.drawString(text.getText(), text.x, text.y);
    	}
    
    }  
单list里面的弹幕不断变多时,有些弹幕不在屏幕中我们就不需要去绘制了。为了减小list中的遍历次数,我们可以设置一个最大值
maxScreenDanmuCount
来限制每次重新绘制的弹幕数量。

然后绘制线程可以用Timer代替Thread,

    private void paintDanmu() {
    	Timer timer=new Timer();
    	timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
			int st=0;              //list的起始遍历位置
	        	if(list.size()>maxScreenDanmuCount) st=list.size()-maxScreenDanmuCount;
	        	for(int i=st;i<list.size();i++) {
	        		DanContent c=list.get(i);
	        		c.x-=spzce;                  //  改变弹幕的x坐标
	        	}
	          
	            repaint();
			}
		}, 100,1000/frame);//定时执行刷新
    }
这样弹幕就完成了,

献上效果图和源代码:(代码比较乱,大佬看见了不要喷啊!记得导入rt.jar!)

java 实现一个桌面弹幕

弹幕类

import java.awt.Font;
import java.io.Serializable;

public class DanContent implements Serializable {  //弹幕管理类
	public static final int TextLarge=70;
	public static final int TextMedium=45;
	public static final int TextSmart=30;
	
	
	public static final int RED=0;
	public static final int BLUE=1;
	public static final int BLACK=2;
	public static final int CYAN=3;
	public static final int REDARK_GRAY=4;
	public static final int GREEN=5;
	public static final int ORANGE=6;
	public static final int WHITE=7;
	public static final int PINK=8;
	
	
	public static final int BOLD=1;
	public static final int ITALLIC=2;
	
	
	public int x=0;
	public int y=0;
	
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private int  color;
	private int size;
	private int style;
	private String text;
	private String senderId;
	private String receiverId;
	
	public String getReceiverId() {
		return receiverId;
	}
	public void setReceiverId(String receiverId) {
		this.receiverId = receiverId;
	}
	public String getSenderId() {
		return senderId;
	}
	public void setSenderId(String senderId) {
		this.senderId = senderId;
	}
	public DanContent(int color, int size, int style, String text) {
		this.color = color;
		this.size = size;
		this.style = style;
		this.text = text;
	}
	public int getColor() {
		return color;
	}
	public void setColor(int color) {
		this.color = color;
	}
	public int getSize() {
		return size;
	}
	public void setSize(int size) {
		this.size = size;
	}
	public int getStyle() {
		return style;
	}
	public void setStyle(int style) {
		this.style = style;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	
	
}
package paint;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Semaphore;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import com.example.lsj.teachapp.POJO.DanContent;
import com.sun.awt.AWTUtilities;  
  
/** 
 * java Swing界面编程 
 * 实现简单的弹幕
 *  
 * @author lsg 
 * 
 */  
public class DanmuNew extends JFrame implements Runnable{  
  
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public static void main(String[] args) {  
    	DanmuNew danmuNew=DanmuNew.getInstance();
    	 new Thread(new Runnable() {
 			
 			@Override
 			public void run() {
 				// TODO Auto-generated method stub
 				Scanner in=new Scanner(System.in);
 				while(true) {
 					String string=in.nextLine();
 					DanContent content=new DanContent(DanContent.ORANGE, 70, DanContent.BOLD, string);
 					danmuNew.add(content);
 				}
 				
 			}
 		}).start();
    }
    
	private int windowwidth;
	private int windwoheight;
	private int spzce;
	private int speed=1;
	private int frame=200;  
	private int maxScreenDanmuCount=50;
    private void ShowDanmu(){  
       // Thread t = new Thread(this);//启动面板的动画线程  
      //  t.start();     
    	paintDanmu();
    }  
      
    public DanmuNew(){  
    	   Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
           windwoheight=(int) screenSize.getHeight();
           windowwidth=(int) screenSize.getWidth();
           spzce=speed;
           System.out.println(windwoheight+" "+windowwidth);
           
           Rectangle bounds = new Rectangle(screenSize); 
           this.setTitle("发送弹幕");
           this.setLayout(null);
           this.setBounds(bounds); 
           this.setExtendedState(Frame.MAXIMIZED_BOTH);
           
           this.setAlwaysOnTop(true);
           // 判断是否支持透明度
           this.setUndecorated(true); // 禁用或启用此窗体的修饰。只有在窗体不可显示时
           //this.setDefaultLookAndFeelDecorated(true);
           this.setDefaultCloseOperation(EXIT_ON_CLOSE);
           Image image=Toolkit.getDefaultToolkit().getImage(getClass().getClassLoader().getResource("llll.png"));
   			setIconImage(image);
   			AWTUtilities.setWindowOpaque(this, false);
           this.setVisible(true);
         
        }  
      
   
		// TODO Auto-generated constructor stub
    	
	public void add(DanContent c) {
		
		Random random=new Random();
		c.y=random.nextInt(windwoheight-150)+50;
		c.x=windowwidth;
		list.add(c);
	}
   // Queue<DanContent> list=new LinkedList<>();
	private   List<DanContent> list=new ArrayList<>();
    @Override  
    public void paint(Graphics gg) {  
        super.paint(gg);  
      //  gg.setColor(Color.red);
       // gg.setFont(new Font("Dialog", Font.BOLD,50 ));
        int st=0;
        if(list.size()>maxScreenDanmuCount) st=list.size()-maxScreenDanmuCount;
        
    	for(int i=st;i<list.size();i++) {
        	DanContent text=list.get(i);
        	if(text.x<-windowwidth)continue;
        	gg.setColor(getColor(text.getColor()));
        	gg.setFont(new Font("楷体",text.getStyle(), text.getSize()));
        	gg.drawString(text.getText(), text.x, text.y);
    	}
    
    }  
    
    //使用线程刷新弹幕
    @Override  
    public void run() {  
        paint2();     
    }  
    
    private void paint2() {
    	 while(true){
         	int st=0;
         	if(list.size()>maxScreenDanmuCount) st=list.size()-maxScreenDanmuCount;
         	for(int i=st;i<list.size();i++) {
         		DanContent c=list.get(i);
         		c.x-=spzce;
         	}
             try {  
                 Thread.sleep(1000/frame);//
             } catch (InterruptedException e) {  
                 e.printStackTrace();  
             }  
             repaint();//
         } 
    }
    //使用Timer刷新弹幕
    private void paintDanmu() {
    	Timer timer=new Timer();
    	timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				int st=0;
	        	if(list.size()>maxScreenDanmuCount) st=list.size()-maxScreenDanmuCount;
	        	for(int i=st;i<list.size();i++) {
	        		DanContent c=list.get(i);
	        		c.x-=spzce;
	        	}
	            repaint();//
			}
		}, 100,1000/frame);
    }
    
    private Color getColor(int idx) {
		switch(idx) {
			case 0:return Color.RED;
			case 1:return Color.BLUE;
			case 2:return Color.BLACK;
			case 3:return Color.CYAN;
			case 4:return Color.DARK_GRAY;
			case 5:return Color.GREEN;
			case 6:return Color.ORANGE;
			case 7:return Color.WHITE;
			case 8:return Color.PINK;
			
		default :return Color.WHITE;
		
		}
	}
    
    public void setMaxDanmuNum(int num) {
    	this.maxScreenDanmuCount=num;
    }
    
    private static DanmuNew instacne=null;
    private static Semaphore semaphore=new Semaphore(0);
    public static synchronized DanmuNew getInstance() {
    	if(instacne==null) {
    		try {
    			show2();
				semaphore.acquire();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		return instacne;
    	}
    	return instacne;
    }
    
    
    
    private static void show2() {
    	SwingUtilities.invokeLater(new Runnable() {
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			instacne = new DanmuNew();  
    			instacne.ShowDanmu(); 
    			semaphore.release();
    		}
    	});
    }
}