java 实现一个桌面弹幕

2022-08-05 11:26:40

本人菜鸟一枚,最近毕设要做一个桌面弹幕的功能,于是想着能不能用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字符串
    }

 结果就是这样了怎么让弹幕动起来呢,前面讲到,我们需要不断调用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!)

弹幕类

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();
    		}
    	});
    }
}


  • 作者:lsj_150
  • 原文链接:https://blog.csdn.net/qq_23321609/article/details/79195766
    更新时间:2022-08-05 11:26:40