java实现在桌面淡入字体特效的小程序
完整项目代码已经发布到github上:https://github.com/SkyInNight/JavaDesktopFadeOut/tree/master
最近在研究java时突发的奇想,如果可以使窗体本身透明,而组件实现不透明,那么是否可以实现字体直接在电脑屏幕前淡出的特效。那么话不多说,开始讲解吧。
- 要想实现只有字体显现在桌面,首先要做的就是将窗体的背景颜色给去掉从而实现窗体透明而组件不透明的效果
- 要实现窗体透明首先要做的是要有一个窗体,这里小编我建议创建一个BaseWindow类去继承JWindow.
到这里又会有人问了,为啥不继承JFrame呢,分明都是窗体呀。
小编这里就多费口舌为小白们多讲解一下JWindow和JFrame的区别。
JFrame在初始化状态下是有边框,有状态栏,同时也有背景颜色去修饰,运行时,会在任务栏出现窗体图标,如果不设置下参数的话也会抢占屏幕焦点,就是会覆盖屏幕其他窗体内容的意思。
JWindow初始化是没有边框,没有状态栏的,同时不会去覆盖其他窗体组件,所以,这里用JWindow会比JFrame方便很多。
- 在继承了JWindow之后,在窗体的构造函数内加上以下这段代码,即可把窗体的背景颜色设置成透明,大家可以在这里去试一试。
AWTUtilities.setWindowOpaque(this, false); // 设置窗体背景颜色为透明
- 在成功完成上述步骤后就来解决显示字体的问题了。我的做法是在BaseWindow上添加一个JLabel然后在JLabel里面填入要添加的文字
这里小编建议小白们多去使用java的继承方式通过继承JLabel自己定义一个BaseLabel类这样可以十分灵活的去添加和修改字体在窗体的显示形式。
public class BaseLabel extends JLabel {
/**
*
*/
private static final long serialVersionUID = 1L;
// 设置默认的字体为楷体,粗体,字体大小为45
private static final Font LABELFONT = new Font("楷体", Font.BOLD, 45);
public BaseLabel(String character) {
super(character);
// 设置字体为黑色
setForeground(Color.black);
// 设置为默认字体
setFont(LABELFONT);
}
}
- 如果你已经创建好了你的BaseLabel类的话那么恭喜你,你可以去在桌面显示你的字了,具体只要在窗体(BaseWindow)的构造函数里面将你的BaseLabel创建并添加到窗体上即可
这里最值得注意的一点是,插入JLabel的语句必须要放到窗体背景色透明之前,不然窗体颜色的属性会直接传给BaseLabel从而导致字体直接无法显示
public BaseWindow(int width, int heigth, int x, int y, String character) {
// 插入字体,一定要先插入,不然会直接显示不出来,除非是图片。
add(new BaseLabel(character));
// 设置窗体背景颜色为透明
AWTUtilities.setWindowOpaque(this, false);
// 设置窗体大小
setSize(width, heigth);
// 设置窗体位置
setLocation(x, y);
// 显示窗体
setVisible(true);
}
做到这里你可以自己去试一试去实现桌面显示字体了,去试一试吧。
这里我是在桌面显示了“中”字
2. 接下来就是要实现如何去让字体淡入淡出了
下面我隆重推荐下面这行代码
com.sun.awt.AWTUtilities.setWindowOpacity(this, 0.0f);//设置窗体包括包含组件的透明度为0
这个方法可以使得窗体包括窗体上的所有组件全部透明化,前一个参数是传入要修改窗体的对象,透明程度由第二个参数来控制(0.0f为全透明)最大值为1.0f(即是完全实体显现)
- 有了上面这代码,我们就可以利用时间和循环去不断的修改窗体的透明度,让字体从透明状态不断向不透明变化。
这里我又要隆重介绍一个十分方便的java计时器对象Timer类,这类里面有一个方法schedule(TimerTask,long)
前一个参数是要执行的TimerTask对象,里面具体可以写你要去执行循环的代码段,后面的long参数是要在规定的的时间过去就开始执行TimerTask对象的run()方法,可以说相当于计时器的东西,当然还有其他形式,大家可以自己去查关于Timer类的概述,我这里就不过多说明了。
这里我是继续继承了TimerTask对象
/**
* 窗体显示特效的任务对象
*
* @author Sky_in_night
*
*/
private class MyTaskShow extends TimerTask {
BaseWindow bw;
public MyTaskShow(BaseWindow bw) {
super();
this.bw = bw;
}
@Override
public void run() {
// 判断是否到达最大实体值如果没有继续显现
while (alpha < MAX_VIRT - STEP_WEDITH) {
alpha = alpha + STEP_WEDITH;
com.sun.awt.AWTUtilities.setWindowOpacity(bw, alpha);//每次透明度改变都要去调用一次这个代码
try {
Thread.sleep(RUN_TIME);//让线程休眠一下,不然会看不出效果
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这里的alpha是透明参数值,而STRP_WEDITH则是每一次循环所要增加的透明度长度。
至此,你已经可以实现单独文字在桌面显示的特效了。
3. 那么现在就剩下最后一步了,如何让多个字体异步的在桌面淡入。
- 其实,稍微脑洞大一点,将视野扩展到窗体上,如果一个窗体可以实现单一字体淡入的话,那么在桌面显现多个窗体则不是就能做到多个字体异步显示了吗。
- 只要预先在每个窗体里面插入一个文字,再计算好每个窗体在桌面的位置,规定好每个窗体文字的显现时间(这个用Timer对象很好实现)那么就很容易实现做到像PPT一样让文字在桌面淡入的特效。
下面献上我的源代码(本来有背景音乐的,但是因为怕解释太多会出错,所以这里故把播放音乐类给删除了)
请运行的时候务必清一下内存,不然肯能会卡或者效果不佳,毕竟开了很多线程,java处理机制并不是很理想。
- BaseLabel
package com.usc.base.JLabel;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JLabel;
/**
* @author 作者:Sky_in_night
* @date 创建时间:2018年2月15日 下午4:36:05
* @ProjectName 项目名称:HappyNewYear
* @FileName 文件名称:com.usc.base.JLabel.BaseLabel.java
*
*/
public class BaseLabel extends JLabel {
/**
*
*/
private static final long serialVersionUID = 1L;
// 设置默认的字体为游梦手迹,粗体,字体大小为45
private static final Font LABELFONT = new Font("楷体", Font.BOLD, 45);
public BaseLabel(String character) {
super(character);
// 设置字体为黑色
setForeground(Color.black);
// 设置为默认字体
setFont(LABELFONT);
}
}
- BaseWindow
package com.usc.base.JFrame;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JWindow;
import com.sun.awt.AWTUtilities;
import com.usc.base.JLabel.BaseLabel;
/**
* @author 作者:Sky_in_night
* @date 创建时间:2018年2月15日 下午4:31:00
* @ProjectName 项目名称:HappyNewYear
* @FileName 文件名称:com.usc.base.JFrame.BaseFrame.java
*
*/
public class BaseWindow extends JWindow {
/**
*
*/
private static final long serialVersionUID = 1L;
private float alpha = 0;
private static float MAX_VIRT = 1.0f;// 窗体透明程度
private static float STEP_WEDITH = 0.01f;// 窗体渐变幅度
private static int RUN_TIME = 15;// 每次执行线程时的间隔时间
public BaseWindow(int width, int heigth, int x, int y, String character, int time) {
com.sun.awt.AWTUtilities.setWindowOpacity(this, 0.0f);
// 插入字体,一定要先插入,不然会直接显示不出来,除非是图片。
add(new BaseLabel(character));
// 设置窗体背景颜色为透明
AWTUtilities.setWindowOpaque(this, false);
// 设置窗体大小
setSize(width, heigth);
// 设置窗体位置
setLocation(x, y);
// 显示窗体
setVisible(true);
// 淡入窗体
showWindow(time);
}
/**
* 显示窗体的函数,有渐渐淡入的特效
*
* @param startTime
* 开始显示窗体的时间
*/
public void showWindow(int startTime) {
new Timer().schedule(new MyTaskShow(this), startTime);
}
/**
* 窗体显示特效的任务对象
*
* @author Sky_in_night
*
*/
private class MyTaskShow extends TimerTask {
BaseWindow bw;
public MyTaskShow(BaseWindow bw) {
super();
this.bw = bw;
}
@Override
public void run() {
// 判断是否到达最大实体值如果没有继续显现
while (alpha < MAX_VIRT - STEP_WEDITH) {
alpha = alpha + STEP_WEDITH;
com.sun.awt.AWTUtilities.setWindowOpacity(bw, alpha);
try {
Thread.sleep(RUN_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
- OptionClass
package com.usc.option;
import java.awt.Dimension;
import java.awt.Toolkit;
import com.usc.base.JFrame.BaseWindow;
/**
* @author 作者:Sky_in_night
* @date 创建时间:2018年2月15日 下午6:29:44
* @ProjectName 项目名称:HappyNewYear
* @FileName 文件名称:com.usc.option.OptionClass.java
*
*/
public class OptionClass {
// 获得桌面的大小
private static Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
// 获得桌面宽度
private static int width = (int) screensize.getWidth();
// 获得桌面高度
private static int height = (int) screensize.getHeight();
// 尾部提名
private static String Name = "——刘可舟";
// 总时长
private static int allTime = 34000;
// 每一个文字窗体的大小
private static final int WIINDOSIZE = 60;
/**
* 用来显示文本的函数
*
* @param coluns
* 每一行的字数
* @param content
* 要显示的文本
*/
public static void showText(String content) {
// 用来减少字体显示所需要拖慢进程的时间
int instanceTime = (content.length() + Name.length()) / 3;
// 每个字间隔显示的时间
int time = allTime / (content.length() + Name.length()) - instanceTime;
// 判断是否参数非法
time = time > 0 ? time : 1;
// 每行文字的个数
int coluns = width / 60;
// 换行的次数
int swap = 0;
// 总共的行数
int rows = content.length() / coluns + (content.length() % coluns >= 1 ? 1 : 0);
// 初始的横坐标
int initX = width / 2 - coluns * WIINDOSIZE / 2;
// 初始的纵坐标
int initY = height / 2 - rows * WIINDOSIZE / 2;
// 输出文本内容
for (int i = 0; i < content.length(); i++) {
new BaseWindow(WIINDOSIZE, WIINDOSIZE, initX + (i % coluns) * WIINDOSIZE, initY + swap * WIINDOSIZE,
content.substring(i, i + 1), i * time);
if ((i + 1) % coluns == 0)
swap++;
}
// 输出提名
for (int i = 0; i < Name.length(); i++) {
new BaseWindow(WIINDOSIZE, WIINDOSIZE, initX + (coluns - Name.length() + i) * WIINDOSIZE,
initY + rows * WIINDOSIZE, Name.substring(i, i + 1), (i + content.length()) * time);
}
}
}
- Main
package com.usc.main;
import java.io.IOException;
import com.usc.option.OptionClass;
/**
* @author 作者:Sky_in_night
* @date 创建时间:2018年2月15日 下午10:07:01
* @ProjectName 项目名称:HappyNewYear
* @FileName 文件名称:.Main.java
*
*/
public class Main {
public static String content = "希望来年的你,日月相伴,星辰为友,路无险阻,前途有光,每一个明天都熠熠生辉闪闪发光。新年快乐。";
public static void main(String[] args) throws IOException {
// @SuppressWarnings("resource")
// BufferedReader bfBufferedReader = new BufferedReader(new FileReader(new
// File("data/properties/content.properties")));
OptionClass.showText(content);
}
}
就分享到这了,其实这个本来是我用来写新年祝福语的啦,你现在也可以去在朋友面前装一装了哈哈哈
所用jdk环境:jdk 1.8.151
所用IDE:eclicpes
里面的字体和样式是可以自己更改的。
由于java本来就不适合写界面,加上本人的垃圾算法,所以这种小程序建议只是玩一玩。如果想用于办公界面,还是多花点时间在有意义的事情上吧。