摘要:实际上,如果百度字幕遮挡器,很可以找到一些结果,但多半是不透明的,不符合我的使用需要,再者自己写这种小工具是很有趣的学习过程。
实际上,如果百度“字幕遮挡器,很可以找到一些结果,但多半是不透明的,不符合我的使用需要,再者自己写这种小工具是很有趣的学习过程。这个学习过程中有一些心得,不得不记录一二。
程序用途对字幕进行遮挡(学习英语用)
在网页中对一段文字加上底色,提高阅读时的注意力程度(个人需求)
两种用途如下图所示
根据程序的用途可以看出,该程序必须实现以下功能:
半透明窗体
总在最前
大小调整
拖动
关闭
后三个功能实际上都是因为无标题,所以需要自己实现。此外,还有一些锦上添花的功能:
颜色选择(包括不透明度的调节)
切换是否总在最前
记忆颜色与位置
防止窗口缩得过小而无法找到
后来在编程实现的过程中也会按这些功能来描述。
编程实现语言: Java
程序的功能并不复杂,因此结构上也偷了些懒。一个主类Cover,其中调用起继承自JFrame的CoverFrame。
这里都是一些很定式的写法,没什么特别的
public class Cover { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { CoverFrame frame = new CoverFrame(); ... } }); } } class CoverFrame extends JFrame { ... }
程序的各项主要功能基本上是在CoverFrame中实现的,具体将在后文一一叙述。
半透明窗体半透明窗体的关键是先要去掉窗体的标题和边框,然后给该Frame设置半透明背景色即可。
class CoverFrame extends JFrame { ... private Color color = new Color(0, 0, 0, 200); //半透明 ... public CoverFrame() { ... setUndecorated(true); //去掉边框 ... setBackground(color); ... getContentPane().setBackground(color); } }
这部分比较简单,不过值得一说的是,如果窗体将保持半透明,即窗体不会被设置成不透明色的话(因为后面加入了颜色选择,用户完全可能选择完全不透明的颜色),只要对CoverFrame对象setBackground(color)即可。
但一旦选择了完全不透明的颜色(Alpha值为255),窗口则会变为默认的灰色。避免这种情况,就需要把Frame的ContentPane也设置成相同顔色getContentPane().setBackground(color)。
想要窗体总在最前也比较简单,有一个现成的函数setAlwaysOnTop来控制。要让程序能切换是否总在最前,也只要在CoverFrame中设置一个布尔型的state,作为是否总在最前的开关,并添加一个JCheckBoxMenuItem到窗口的JPopupMenu中去。
class CoverFrame extends JFrame { ... private JPopupMenu popupMenu = new JPopupMenu(); //右键菜单 private Color color = new Color(0, 0, 0, 200); private boolean onTop = true; //默认总在最前 ... public CoverFrame() { setAlwaysOnTop(onTop); ... CoverFrame that = this; // set up popup menus ... JMenuItem topItem = new JCheckBoxMenuItem("Always On Top", true); //带勾选框,默认勾选 topItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { onTop = !onTop; setAlwaysOnTop(onTop); //改变当前状态 } }); popupMenu.add(topItem); ... } }拖动与大小调整
这两个功能本来应该是一个窗体固有的,但因为把标题与边框都去掉了,现在都需要自己来实现。因为两个功能的代码犬牙交错,所以放在一起来讲了。
拖动的原理是,点击时记录点击位置(相对于窗口原点),拖动时获得鼠标在屏幕上的绝对位置,这一位置减去之前记录的相对点击位置,就是新的窗口的位置了,这样就实现了窗口的拖动功能。
大小调整的思路则是判断点击位置是处于窗口的边缘位置,如果是,改变鼠标指针。如果位置处于左侧或者上方,拖动里改变宽/高,并改变窗口位置,如果在右侧或者正文,拖动时改变窗口的宽/高。
class CoverFrame extends JFrame { private Point point = new Point(0, 0); //用于保存点击位置 ... public CoverFrame() { ... addMouseListener(new MouseAdapter() { //监听鼠标点击 public void mousePressed(MouseEvent event) { // record the point where you begin to drag point = event.getPoint(); //记录点击位置 popupEvent(event); //右键菜单 } public void mouseReleased(MouseEvent event) { popupEvent(event); } private void popupEvent(MouseEvent event) { if (event.isPopupTrigger()) { popupMenu.show(event.getComponent(), event.getX(), event.getY()); //在右键位置显示菜单 } } } ); addMouseMotionListener(new MouseMotionListener() { // 用来标识点击区域(上下左右) private boolean top = false; private boolean down = false; private boolean left = false; private boolean right = false; final private int GAP = 3; public void mouseMoved(MouseEvent event) { //窗体的宽高 int width = getWidth(); int height = getHeight(); //点击位置(相对) int x = event.getX(); int y = event.getY(); top = false; down = false; left = false; right = false; if (Math.abs(y) <= GAP) { top = true; } else if (Math.abs(y-height) <=GAP) { down = true; } if (Math.abs(x) <= GAP) { left = true; } else if (Math.abs(x-width) <=GAP) { right = true; } //如果判断在边缘就改变鼠标指针 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); if (top || down) setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); if (left || right) setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); if ((left && top) || (right && down)) setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)); if ((right && top) || (left && down)) setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)); } public void mouseDragged(MouseEvent event) { bounds = getBounds(); if (!(top || down || left || right)) { // 在中间拖动窗口 Point absPoint = event.getLocationOnScreen(); // set the location of window relate to where you click absPoint.translate(-(int)point.getX(), -(int)point.getY()); setLocation(absPoint); } else { //在四角缩放窗体 if (top) { bounds.setLocation((int)bounds.getX(), (int)bounds.getY() + event.getY()); bounds.setSize((int)bounds.getWidth(), (int)bounds.getHeight() - event.getY()); } if (down) { bounds.setSize((int)bounds.getWidth(), event.getY()); } if (left) { bounds.setLocation((int)bounds.getX() + event.getX(), (int)bounds.getY()); bounds.setSize((int)bounds.getWidth() - event.getX(), (int)bounds.getHeight()); } if (right) { bounds.setSize(event.getX(),(int)bounds.getHeight()); } validateBounds(); setBounds(bounds); } } } );关闭与保存设置
关闭本来其实是没啥说的,就算是没有标题栏,但是因为把颜色和位置信息记录下来,还是有一些要注意的地方。
一般通过按键关闭窗口,会调用dispose函数,但是这样的话,并不会触发windowClose的事件。要主动发出这一事件才可以。
首先先设置关闭里的默认动作,并监听关闭事件,在保存设置后再退出。程序中设置的保存就很简单的在文本文件中存了几个数字,这里就不细说了。
public class Cover { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { CoverFrame frame = new CoverFrame(); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //自己处理关闭 frame.setVisible(true); frame.addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e) { super.windowClosing(e); frame.writeCfg(); // 保存设置 System.out.println("window is closed!"); System.exit(0); } }); } }); } }
但是问题来了,如果按Alt+F4关闭,那么设置会被保存,但直接dispose关闭程序,则不保存。这是因为没有触发关闭的事件。主动把一个关闭事件添加到事件队列中,然后再dispose就解决了这一问题
class CoverFrame extends JFrame { ... private JPopupMenu popupMenu = new JPopupMenu(); ... public CoverFrame() { ... // set up popup menus JMenuItem closeItem = new JMenuItem("Close"); closeItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { // make sure close event is catched WindowEvent wev = new WindowEvent(that, WindowEvent.WINDOW_CLOSING); Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev); //主动把一个关闭事件添加到事件队列中 dispose(); // close window } }); popupMenu.add(closeItem); ... } }颜色修改
这个功能其实也不难,主要就利用了Java中自带的选色窗口。不细说了,给代码片段了。同样要注意的是,同时设置CoverFrame的底色和ContentPane的底色。
class CoverFrame extends JFrame { ... private JPopupMenu popupMenu = new JPopupMenu(); ... public CoverFrame() { ... JMenuItem pickItem = new JMenuItem("Pick Color"); pickItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { Color newColor; setAlwaysOnTop(false); newColor = JColorChooser.showDialog(null, "pick your color", color); setAlwaysOnTop(onTop); if(newColor != null) { color = newColor; setBackground(color); getContentPane().setBackground(color); repaint(); } } }); popupMenu.add(pickItem); ... } }总结
周五花了一个下午写了这个程序,边学边做所以比较慢,又花了不少时间写这些东西,不过越写越感觉,只是一种心得的记录而已,应该没有什么参考价值。
完整的代码放在了
http://git.oschina.net/macuss...
两百多行不太多,思路这里基本介绍了,功能吧基本能用。
本来想把参考的帖子都致敬一下的,不过有点麻烦,不好意思了。反正也是个人日记而已。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67335.html
阅读 768·2021-09-30 09:46
阅读 3775·2021-09-03 10:45
阅读 3608·2019-08-30 14:11
阅读 2541·2019-08-30 13:54
阅读 2253·2019-08-30 11:00
阅读 2346·2019-08-29 13:03
阅读 1552·2019-08-29 11:16
阅读 3579·2019-08-26 13:52