很久以前,大概是12或13年,下载了眼神速读软件。
那时看一本小说只要一个上午,一分钟读上万字。文字从眼前刷刷而过,就看个大概,走马观花。
刚开始时,眼睛容易疲劳,看着看着,眼泪就流了出来。但是最终坚持了下来,从中受益良多。 小说这玩意,看着看着就没精神,但如果跟文字竞跑,就充满精神,乐此不疲。越看越精神,越看大脑越清明,好像有丝丝清气在大脑游荡,那种感觉,试过的都说好。
一直想找一个Android版的速读训练器,一直找不到。拖了很久,去年学了android,总算搞出来了。但用了一两个星期,就没兴趣了。一直赖在手机里,懒得删。
今天突发奇想,要标识一下小说。要干大事!
又把删掉的眼神速读软件下载了回来,40多兆,压缩包看着不是很顺眼,想起来一些不好的回忆——它不会记录阅读位置,背景颜色之类的调节也不尽如人意,界面太大太占地方,不能快捷键控制……
看着看着,不想安装了。自己写一个吧——java版的速读训练器
看看效果:
引用了一些工具类,有些机密不能公开。就发一下同一个包下的文件吧,以供参考:
package com.framework.libInteresting.poet.reader;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import com.framework.util.string.PropertyUtil;
public class FastReader extends JFrame implements ActionListener {
private static long serialVersionUID = 1L;
public final JTextPane textArea;
public FastReader() {
MyThread t=new MyThread();
// Set the initial size of the window
setSize(600, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
textArea=new JTextPane();
textArea.setEditable(false);
textArea.setBackground(Color.black);
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
setTitle(Util.getTitle());
if(e.getKeyCode()==32){//空格 暂停 继续
Util.isWait=!Util.isWait;
}
if(Util.isWait){
t.toSuspend();
}else{
t.toResume();
}
if(e.getKeyCode()==10){//Enter键关闭程序
Util.close();
}
}
});
Util.update(textArea,Util.getShowingString() );
JPanel panel = new JPanel(new BorderLayout());
panel.add(textArea);
getContentPane().add(panel);
setVisible(true);
t.start();
}
@Override
protected void processWindowEvent(WindowEvent e) {
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
Util.close();
}
}
@Override
public void actionPerformed(ActionEvent var1) {
}
class MyThread extends Thread {
private final Object lock = new Object();
private boolean suspend = false;
public void toSuspend(){
suspend = true;
}
public void toResume(){
synchronized (lock) {
lock.notify();//当前等待的线程继续执行
}
suspend = false;
}
@Override
public void run() {
super.run();
while(!Util.isend){
try {
while(suspend){
synchronized (lock) {
lock.wait();
}
}
Util.update(textArea,Util.getShowingString() );
Thread.sleep(Integer.parseInt(PropertyUtil.getValue(Util.getConfig(), "utf-8", "refresh", "1000")));
} catch (NumberFormatException e1) {
e1.printStackTrace();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new FastReader();
}
}
package com.framework.libInteresting.poet.reader;
import java.awt.Color;
import java.awt.Font;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextPane;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import com.framework.util.db.DbUtil;
import com.framework.util.file.FileUtil;
import com.framework.util.list.ListUtil;
import com.framework.util.money.SinoNumber;
import com.framework.util.string.PropertyUtil;
import com.framework.util.string.StringUtil;
public class Util {
public static boolean isWait=false;
private static List<String> chapters=new ArrayList<String>();//所有章节标题
private static String showingChapter="";//显示的章节内容
private static String showingTitle="";//显示的章节标题
private static List<List<String>> showing=new ArrayList<List<String>>();//本章节的显示
private static int showingIdx=0;//显示到第几个了
public static boolean isend=false;
public static void initChapterData(){
Connection conn = null;
try {
conn = getConn();
DbUtil db = new DbUtil(conn);
String name = PropertyUtil.getValue(getConfig(), "utf-8", "name", "");
String title = PropertyUtil.getValue(getConfig(), "utf-8", "title", "");
String startIndex = PropertyUtil.getValue(getConfig(), "utf-8", "startIndex", "0");
int showRow = Integer.parseInt(PropertyUtil.getValue(getConfig(), "utf-8", "showRow", ""));
int rowSize = Integer.parseInt(PropertyUtil.getValue(getConfig(), "utf-8", "rowSize", ""));
if(!name.matches("\\d+")){
name=db.queryForString("select id from spider_novel_name where name=?",new Object[]{name});
}
if(chapters.size()==0){
List<String> titles = db.getListStr("select title from spider_novel_chapter where id=?",new Object[]{name});
List<String> newtitles = SinoNumber.orderList(titles);
chapters.addAll(newtitles);
}
if("".equals(title)){
title=chapters.get(0);
PropertyUtil.saveProperty(getConfig(), "utf-8", "title", title);
}
showing.clear();
String chapter=db.queryForClob("select content from spider_novel_chapter where id=? and title=?", new Object[]{name,title});
showingChapter=chapter;
showingTitle=title;
int curidx=Integer.parseInt(startIndex);
if(chapter.length()>curidx){
chapter=chapter.substring(curidx);
}else{
curidx=0;
int valueIndex = ListUtil.getValueIndex(chapters, title);
if(valueIndex==-1){
isend=true;
return;
}
title=chapters.get(valueIndex+1);
chapter=db.queryForClob("select content from spider_novel_chapter where id=? and title=?", new Object[]{name,title});
showingChapter=chapter;
showingTitle=title;
}
//将文章拆分,分配好显示次序
List<String> subshowing=new ArrayList<String>();
List<String> rows = StringUtil.split(chapter, new String[]{",","。","!",FileUtil.symbolrn,FileUtil.symboln});
for (int i = 0; i < rows.size(); i++) {
String row = StringUtil.trim(rows.get(i));
if("".equals(row)){
continue;
}
List<String> ss = StringUtil.split(row, rowSize);
for (int j = 0; j < ss.size(); j++) {
String s = ss.get(j);
if(subshowing.size()==showRow){
showing.add(subshowing);
subshowing=new ArrayList<String>();
}
subshowing.add(s);
}
}
if(subshowing.size()>0){
showing.add(subshowing);
}
int valueIndex = ListUtil.getValueIndex(chapters, title);
if(valueIndex==-1){
isend=true;
return;
}
PropertyUtil.saveProperty(getConfig(), "utf-8", "title", chapters.get(valueIndex+1));
showingIdx=0;
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtil.close(conn);
}
}
public static void close(){
if(showingIdx>=showing.size()){
PropertyUtil.saveProperty(getConfig(), "utf-8", "startIndex","0");
}else{
List<String> list = showing.get(showingIdx);
PropertyUtil.saveProperty(getConfig(), "utf-8", "startIndex",String.valueOf(showingChapter.indexOf(list.get(0))));
}
PropertyUtil.saveProperty(getConfig(), "utf-8", "title",showingTitle);
System.exit(99);
}
public static String getConfig() {
return "D://DevSoft/OldProject/AllUtils/src/com/framework/libInteresting/poet/reader/config";
}
public static Connection getConn() {
return DbUtil.getBestConn();
}
public static void update(JTextPane textArea,String str){
textArea.setText(str);
Font font = new Font(PropertyUtil.getValue(Util.getConfig(), "utf-8", "fontType", "隶书"), Font.PLAIN,
PropertyUtil.getValue(Util.getConfig(), "utf-8", "fontSize", 40));
StyledDocument doc = textArea.getStyledDocument();
SimpleAttributeSet arrSet = new SimpleAttributeSet();
StyleConstants.setFontFamily(arrSet, font.getFamily());
StyleConstants.setFontSize(arrSet, font.getSize());
StyleConstants.setBold(arrSet, font.isBold());
StyleConstants.setItalic(arrSet, font.isItalic());
StyleConstants.setForeground(arrSet,Color.white);
doc.setCharacterAttributes(0, doc.getLength(), arrSet, false);
//设置居中
SimpleAttributeSet align = new SimpleAttributeSet();
StyleConstants.setAlignment(align, StyleConstants.ALIGN_CENTER);
doc.setParagraphAttributes(0,doc.getLength(),align,false);
}
public static String getTitle() {
return showingTitle;
}
public static String getShowingString() {
if(showing.size()==0||showingIdx>=showing.size()){
initChapterData();
}
if(isend) return "";
String re=ListUtil.list2Str(showing.get(showingIdx),"\n");
showingIdx++;
return re;
}
}
config文件
name:万族之劫
title:第31章 三个目标
startIndex:2568
showRow:3
rowSize:18
refresh:1000
fontSize:30
fontType:隶书