透明背景的文本显示器

  • 主题:透明背景的文本显示器(自用摸鱼阅读器)
  • 语言:java
  • 环境:win7+jdk8+eclipse
  • 额外jar包:fastjson-1.2.83.jarjintellitype-1.3.9.jar
  • 额外的windows的dll文件:JIntellitype.dll,JIntellitype64.dll
  • 功能:使用ArrayList对文本进行行存储,通过HashMap来存储文本的目录,通过将Java容器的背景设置透明色,实现只显示文字,通过监听鼠标的位置,来实现对容器的显示位置的移动,通过监听键盘实现对显示内容的切换。
  • 待优化:
  • 后续:加入使用快捷键显示所有阅读过的文本以及文本的相关信息。

快捷键
// alt + a:隐藏窗口
// alt + e:退出程序
// alt + q:显示窗口
// alt + z:自动翻页
// alt + c:停止自动翻页
// alt + s:下一页
// alt + w:上一页
// alt + d:下一章
// alt + u:上一章

  • 优点:快捷键是全局监听,参数过多,占用资源
  • 缺点:容易占用其他软件的快捷键,代码较乱不易阅读,会有一个缓存已经阅读的页数的文件在项目中但是缓存容易丢失
package jn.test;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.melloware.jintellitype.HotkeyListener;
import com.melloware.jintellitype.JIntellitype;

/**
 * @author user
 * @ClassName:NovelRead
 * @Description:展示文本用于阅读
 */
public class NovelRead extends JFrame {
	/**
	 *
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * @Fields:GLOBAL_HOT_KEY_*:设置热键
	 */
	public static final int GLOBAL_HOT_KEY_1 = 0;
	public static final int GLOBAL_HOT_KEY_2 = 1;
	public static final int GLOBAL_HOT_KEY_3 = 2;
	public static final int GLOBAL_HOT_KEY_4 = 3;
	public static final int GLOBAL_HOT_KEY_5 = 4;
	public static final int GLOBAL_HOT_KEY_6 = 5;
	public static final int GLOBAL_HOT_KEY_7 = 6;
	public static final int GLOBAL_HOT_KEY_8 = 7;
	public static final int GLOBAL_HOT_KEY_9 = 8;

	/**
	 * @Fields:flag:是否进行自动翻页的标识
	 */
	public static boolean flag;
	/**
	 * @Fields:rebot:自动按键的实例
	 */
	public static Robot rebot;
	/**
	 * @Fields:filePath:配置文件路径,配置文件用来保存看到的页数
	 */
	public static String filePath;
	/**
	 * @Fields:pageNum:记录已经看到的页数
	 */
	public static int pageNum = 0;
	/**
	 * @Fields:x:鼠标位置
	 * @Fields:y:鼠标位置
	 */
	int x = 0;
	int y = 0;


	private static Map<Integer,String> hm=new LinkedHashMap<>();


	public static NovelRead nr;

	public static void main(String[] args) {
		try {
			nr = new NovelRead();

			// 获取当前项目的运行地址
			String path = nr.getClass().getResource("").getPath(); // /E:/sts/Test/bin/jn/test/
			path = path.substring(1); // E:/sts/Test/bin/jn/test/

			// 获取文件:TODO:修改小说文件路径,注意使用反斜杠
			File file = new File("E:/Users/user/Desktop/asds.txt");
			String name = file.getName();

			// 生成与文件名称相同的隐形配置文件,目前配置文件是用来保存看到的页数
			File conf = new File(path + "." + name);
			// 判断文件是否存在,不存在就创建,存在就调用方法获取页数
			if (!conf.exists()) {
				conf.createNewFile();
			} else {
				readConf(conf);
			}

			// 获取配置文件地址,用于后面翻页是进行写入数据
			filePath = conf.getPath();
//			pageNum=25901;
			// 调用方法显示界面
			nr.showText(nr.readNovel(file, 30, "UTF-8"));
			// 设置窗体是否可见
			nr.setVisible(true);
		} catch (Exception e) {
			System.out.println("主函数出现错误:" + e);
		}

	}

	/**
	 * @Title:readConf
	 * @Description:用于读取配置文件,返回已经读到的页数
	 * @param file 需要的读取的配置文件
	 * @return
	 * @return
	 * @throws
	 */
	public static void readConf(File file) {
		// 初始化
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(file));
			String str;
			if ((str = in.readLine()) != null) {
				pageNum = Integer.parseInt(str);
			} else {
			}
		} catch (Exception e) {
			System.out.println("读文件报错:" + e);
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * @Title:writeCondf
	 * @Description:用于写入已经看得页数到配置文件中
	 * @param: page 具体的int页数值
	 * @return void
	 * @throws
	 */
	public static void writeCondf(int page) {
		PrintStream ps = null;
		try {
			ps = new PrintStream(filePath);
			ps.print(page);
		} catch (Exception e) {
			System.out.println("写文件报错:" + e);
		} finally {
			ps.close();
		}
	}


	/**
	 * @Title:readNovel
	 * @Description:用于读取文件内容,并使用arraylist进行存储
	 * @param:file 需要读取的文件
	 * @param:LINELENGTH	每行显示的字数
	 * @param:charSet 文件的编码
	 * @param:
	 * @return ArrayList<String>
	 * @throws
	 */
	public ArrayList<String> readNovel(File file, int LINELENGTH, String charSet) {
		try {
			BufferedReader in = new BufferedReader(new InputStreamReader(
					new FileInputStream(file), Charset.forName(charSet)));
			String str;
			int i = 1;
			int j = 0;
//			StringBuilder sb;
			ArrayList<String> al = new ArrayList<>();

			String reg="^[第][0-9]*[章].*";
			while ((str = in.readLine()) != null) {
				// 去除空字符串的情况,像文本本身存在的空行
				if (str.isEmpty())
					continue;
				if (i > 0 && i <= 630000000) {
					// 将行内容取出进行长度判断,若是大于设置的长度值,就进行截取分为两段进行存入到ArrayList中
					while (str.length() > LINELENGTH) {
						al.add(str.substring(0, LINELENGTH));
						// 截取字符串
						str = str.substring(LINELENGTH);
						//行号自增
						j++;
					}
					//匹配章节的行数,并进行存储,便于跳转章节
					if(str.matches(reg)){
						hm.put(j,str);
					}
					j++;
					al.add(str);
				}
				i++;
			}
			in.close();
			return al;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}


	/**
	 * @Title:showText
	 * @Description:用于展示界面和文本
	 * @param al 用于存储文本的ArrayList
	 * @return void
	 * @throws
	 */
	public void showText(final ArrayList<String> al) {
		try {

			// 设置窗体初始显示位置
			int initx = 20;
			int inity = 200;
			// 设置窗体显示大小
			int width = 500;
			int height = 20;

			// 获取屏幕的高宽
			 Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
			 initx = (int) screensize.getWidth()/2-400;
			 inity = (int) screensize.getHeight()-62;
			// 设置窗体局部管理器
			this.setLayout(null);
			// 设置窗体观感(皮肤、主题)
			// UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
			// 设置窗体标题
			this.setTitle("阅读");
			// 隐藏任务栏图标
			this.setType(Type.UTILITY);
			// 设置窗体组件是否可见
			// this.setVisible(true);
			// 设置窗体透明度
			// this.setOpacity(0.6f);
			// 设置窗体大小是否可调节
			this.setResizable(false);
			// 设置窗体是否总是在最顶层显示
			this.setAlwaysOnTop(true);
			// 设置背景颜色
			// this.setBackground(Color.white);
			// //不生效是因为在上层显示的并不是该图层,需要使用下面这个设置背景颜色
//			this.getContentPane().setBackground(Color.white);
			// 设置容器焦点
			this.setFocusable(false);
			// 设置窗体关闭就退出程序
			this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			// 添加鼠标监听用来获取鼠标当前位置
			this.addMouseListener(new MouseAdapter() {
				@Override
				public void mousePressed(MouseEvent e) {
					x = e.getX();
					y = e.getY();
				}
			});
			// 设置鼠标移动窗体事件
			this.addMouseMotionListener(new MouseMotionAdapter() {
				@Override
				public void mouseDragged(MouseEvent e) {
					// 获取鼠标移动了多少距离
					int xOnScreen = e.getXOnScreen();
					int yOnScreen = e.getYOnScreen();
					// 移动后鼠标的位置
					int xx = xOnScreen - x;
					int yy = yOnScreen - y;
					// 移动窗体到鼠标位置
					NovelRead.this.setLocation(xx, yy);
				}
			});

			JPanel jPanel = new JPanel();// 得到窗口的容器
			jPanel.setLayout(null);
			jPanel.setBounds(0, 0, width, height);
			// 设置组件是否背景透明,使用外层背景颜色
			jPanel.setOpaque(true);
			// 设置组件是否可见
			jPanel.setVisible(true);
			// 设置窗口的背景为透明色(显示文本层的所有外层的背景颜色都设置为new Color(0,0,0,0))
			jPanel.setBackground(new Color(0, 0, 0, 0));
			this.add(jPanel);

			// jPanel.setSize(300, 20);

			final JLabel l1 = new JLabel(); // 创建一个标签
			// 设置显示的字体颜色
			l1.setForeground(new Color(0,0,0,40));
			// 设置字体样式
			Font font = new Font("宋体", Font.PLAIN, 15);
			l1.setFont(font);
			l1.setBounds(0, 0, width, height);

			jPanel.add(l1);
			// 设置窗体位置,大小
			this.setBounds(initx, inity, width, height);
			// 是否去掉外边框修饰
			this.setUndecorated(true);
			// 设置窗口的背景为透明色(显示文本层的所有外层的背景颜色都设置为new Color(0,0,0,0))
			this.setBackground(new Color(0, 0, 0, 0));

			if (pageNum >= 0 && pageNum < al.size()) {
				l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
			} else if (pageNum >= al.size()) {
				pageNum = al.size() - 1;
				l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
			} else {
				l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
			}

			// 注册全局热键快捷键,当点击alt+S时调用GLOBAL_HOT_KEY_1
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_1,JIntellitype.MOD_ALT, (int) 'S');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_2,JIntellitype.MOD_ALT, (int) 'W');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_3,JIntellitype.MOD_ALT, (int) 'A');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_4,JIntellitype.MOD_ALT, (int) 'Q');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_5,JIntellitype.MOD_ALT, (int) 'E');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_6,JIntellitype.MOD_ALT, (int) 'Z');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_7,JIntellitype.MOD_ALT, (int) 'C');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_8,JIntellitype.MOD_ALT, (int) 'D');
			JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_9,JIntellitype.MOD_ALT, (int) 'U');
			// 监听按键,并对热键进行相关操作
			// alt + a:隐藏窗口
			// alt + e:退出程序
			// alt + q:显示窗口
			// alt + z:自动翻页
			// alt + c:停止自动翻页
			// alt + s:下一页
			// alt + w:上一页
			// alt + d:下一章
			// alt + u:上一章
			JIntellitype.getInstance().addHotKeyListener(new HotkeyListener() {
				public void onHotKey(int markCode) {
					switch (markCode) {
					case GLOBAL_HOT_KEY_1:
						if (pageNum < (al.size() - 1)) {
							pageNum += 1;
							// 由于背景色为透明的,每次更新文本时,并没有重新加载外层组件,就会导致更新文本后,文本重叠的情况,只需要更新文本内容时,更新外层组件
							nr.repaint();
							l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
							writeCondf(pageNum);
						} else {
							nr.repaint();
							l1.setText(al.get(al.size() - 1) + "	" + pageNum+ "/" + (al.size() - 1));
						}
						break;
					case GLOBAL_HOT_KEY_2:
						if (pageNum >= 1) {
							pageNum--;
							nr.repaint();
							l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
							writeCondf(pageNum);
						} else {
							nr.repaint();
							l1.setText(al.get(0) + "	" + pageNum + "/"+ (al.size() - 1));
						}
						break;
					case GLOBAL_HOT_KEY_3:
						// 删除已经注册全局快捷键
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_1);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_2);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_3);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_5);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_6);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_7);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_8);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_9);
						flag = false;
						nr.setVisible(false);
						break;
					case GLOBAL_HOT_KEY_4:
						// 注册全局快捷键
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_1, JIntellitype.MOD_ALT,(int) 'S');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_2, JIntellitype.MOD_ALT,(int) 'W');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_3, JIntellitype.MOD_ALT,(int) 'A');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_5, JIntellitype.MOD_ALT,(int) 'E');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_6, JIntellitype.MOD_ALT,(int) 'Z');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_7, JIntellitype.MOD_ALT,(int) 'C');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_8, JIntellitype.MOD_ALT,(int) 'D');
						JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_9, JIntellitype.MOD_ALT,(int) 'U');
						nr.setVisible(true);
						flag = true;
						break;
					case GLOBAL_HOT_KEY_5:
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_1);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_2);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_3);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_4);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_5);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_6);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_7);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_8);
						JIntellitype.getInstance().unregisterHotKey(GLOBAL_HOT_KEY_9);
						flag = false;
						System.exit(0);
						break;
					case GLOBAL_HOT_KEY_6:
						flag = true;
						rebottest();
						break;
					case GLOBAL_HOT_KEY_7:
						flag = false;
						break;
					case GLOBAL_HOT_KEY_8:
						for (Integer i : hm.keySet()) {
							if(i>pageNum){
								pageNum=i;
								nr.repaint();
								l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
								writeCondf(pageNum);
//								System.out.println(i+":"+hm.get(i));
								break;
							}
						}
						break;
					case GLOBAL_HOT_KEY_9:
						int zj=0;
						for (Integer i : hm.keySet()) {
							if(i>=pageNum){
								pageNum=zj;
								nr.repaint();
								l1.setText(al.get(pageNum) + "	" + pageNum + "/"+ (al.size() - 1));
								writeCondf(pageNum);
//								System.out.println(i+":"+hm.get(i));
								break;
							}
							zj=i;
						}
						break;
					}
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * @Title:rebottest
	 * @Description:用于自动翻页的
	 * @return void
	 * @throws
	 */
	public static void rebottest() {
		try {

			rebot = new Robot();
			// 小说翻页

			Thread t1 = new Thread(new Runnable() {

				@Override
				public void run() {
					while (flag) {
						try {
							rebot.keyPress(KeyEvent.VK_ALT);
							rebot.keyPress(KeyEvent.VK_S);
							rebot.keyRelease(KeyEvent.VK_S);
							rebot.keyRelease(KeyEvent.VK_ALT);
							Thread.sleep(6000);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}

			});
			t1.start();
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值