


版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、用 java 打造任意形状窗口和透明窗口转 用 java 打造任意形状窗口和透明窗口原文地址: .html图形界面开发对于 Java 来说并非它的长项,开发者经常会 碰到各种各样的限制,比如,如何打造一款任意形状的窗口? 如何可以透过窗口显示它覆盖下的内容?考虑到 Java 并没有被设计成支持以上的功能,所以,你能 得到的永远是方方正正的窗口,毫无新意,当然,我们可以 通过 JNI 调用本地代码来完成, 但是这就失去了 java 可移植 性的意义, 那么, 用纯粹的 java 代码如何实现以上两种功能 呢?下文提供了一个实现的参考预备知识:1. ,这个类是一个功能非常强大的类, 通过它 我们可
2、以控制鼠标和键盘的响应,不过这里,我们只需要用 到它的一个功能截屏,也就是得到当前屏幕的快照( screenshot )2. 我们可以通过调用一个 swing 组件的paintComponent(Graphics g) 方法用特定的 Graphics 为其 定制特殊的外观 首先声明的一点是,本文中的实现方法只是一个欺骗的手法, 因为要想实现前文中的功能, 我们几乎的重写一套 Swing 出 来,这里,简便的做法是,我们通过 robot 类来获得当前屏 幕的快照,然后贴在我们需要的窗口上,这样,不就实现了 透明的功能了吗?顺便提一下,几年前日本发明的隐形衣也 是依靠这种机制,这种衣服在身后附带一
3、套摄像机,然后即 时的将拍下的内容显示在衣服的正面,因此,当别人看过来时,仿佛就通过人和衣服看到了身后的场景A_A另外, 还要感谢 Joshua Chris leniz 的 Swing Hack 一书, 以 上充满创新的方法正来自他的书中 好咯,让我们具体看一下细节的处理:第一, 我们要得到当前屏幕的快照, 保存到一个 Image 对象 background 中:public void updateBackground() try Robot rbt = new Robot();Toolkit tk = Toolkit.getDefaultToolkit();Dimension dim = t
4、k.getScreenSize();color=Redbackground /color=rbt.createScreenCapture(new Rectangle(0, 0, (int) dim.getWidth(), (int) dim.getHeight(); catch (Exception ex) 第二,我们需要让窗口显示这个图像,也就是说,让窗口的 背景图像是这副图像,以达到透明的欺骗效果:public void paintComponent(Graphics g) Point pos = this.getLocationOnScreen();Point offset = new
5、Point(-pos.x, -pos.y);g.drawImage(color=Redbackground/color, offset.x,offset.y, null);在 swing hack 一书中, 作者也给出了他的实现, 然而, 运行 结果表明该实现存在很大的问题:窗口经常无法即时更新, 往往背景变了,窗口里显示的却还是以前的背景。仔细研究 了他的代码,我发现了问题的根结,同时也是这种实现技术 的关键要素如何让窗口在正确的时机里更新显示,下面, 我们会讨论这一点第三,更新窗口外观 前两步的操作,只能得到一副当前屏幕的快照,一旦背景变 化了,或者窗口移动了,变化大小了,那么我们制作的窗
6、口 将永远无法和和屏幕背景联合成整体,也就失去了透明的效 果;同时,我们也不可能每时每刻都调用 updateBackground() 方法获得最新的背景,可行的方法是, 通过对事件的监听来选择适当的时间来更新外观 我们应该可以达到这三点共识: 1。窗口移动或改变大小时,背景图像一般是不会发生变化 的,我们不需要得到新的屏幕快照,只用将以前得到的背景 中适当的部分贴到窗口上,调用 repaint ()方法就足已 2。要获得最新的屏幕快照,必须先将窗口隐藏起来,调用 updateBackground() 得到图像后再把窗口显示,我们可以 用 refresh 方法来表示refresh () fram
7、e.hide();updateBackground() ;frame.show();3。如果背景改变了,那么一定是别的 windows 程序获得了 或失去了事件焦点,也就是说我们关注的窗口将触发焦点得 失事件,这个时候需要调用 refresh() 得到最新的屏幕快照看到这里,你或许认为已经没有技术难点了,然而,此时才 是 我们最需要关注的地方 : 参看第三点,我们需要在窗口得失焦点时调用 refresh() 方 法;参看第一点,我们调用 refresh() 方法时需要先将窗口 隐藏,然后再显示。于是问题来了,在隐藏和显示窗口时, 同样会触发得失焦点事件,得失焦点事件又将触发新的隐藏 和显示窗口
8、事件(为了得到新的屏幕快照) ,这就使程序陷 入了死循环中,我们必须加以控制,使得第二次触发焦点得 失事件时不调用 refresh ()方法 作者的办法是加一个线程来控制,通过判断时间间隔长短来 决定是否调用 refresh ()方法,可是,这个条件是程序非常 的不稳定,因为往往调用时间会根据系统繁忙度而改变,使 得需要更新时不能更新,不需要更新的时候反而更新了 因此, 我决定采取新的解决方案, 能不能隐藏 /显示窗口时不 触发得失焦点事件呢? 解决方法很简单,我抛开了传统的 setVisible ()或者 show (), hide ()方法,而是使用 setLocation ()方法,因为
9、 调用 setLocation ()方法时窗口不会失去焦点,同时,只要 用类似 setLocation ( 2000 , 2000 )方法也同样可以轻 松的让窗口在屏幕中消失 下面是我的全部代码: WindowFocusListener private JFrame frame;private Boolean isHiding = false, isShowing = false, start = false;private Image background;private Point p;/获得当前屏幕快照public void updateBackground() try Robot rb
10、t = new Robot();Toolkit tk = Toolkit.getDefaultToolkit();Dimension dim = tk.getScreenSize();background = rbt.createScreenCapture(new Rectangle(0, 0, (int) dim.getWidth(), (int) dim.getHeight(); catch (Exception ex) / p(ex.toString();/ 此方法没有申明过 ,因为无法得知上下文 。因为不 影响执行效果 ,先注释掉它 ex.printStackTrace();/将窗口掉
11、离出屏幕以获得纯粹的背景图象public void refresh() if (start = true) this.updateBackground();frame.setLocation(p);if (p.x < 0 | p.y < 0)frame.setLocation(0, 0);this.repaint();public void componentHidden(ComponentEvent e) / /窗口移动时public void componentMoved(ComponentEvent e) / TODO Auto-generated metho
12、d stubthis.repaint();/窗口改变大小时public void componentResized(ComponentEvent e) / TODO Auto-generated method stubthis.repaint();public void componentShown(ComponentEvent e) / /窗口得到焦点后 ,用 refresh() 方法 更新界面public void windowGainedFocus(WindowEvent e) / refresh(); start = false;/窗口失去焦点后 ,将其移出屏幕 public void
13、 windowLostFocus(WindowEvent e) / if (frame.isShowing() = true) else start = true;p = frame.getLocation();frame.setLocation(-2000, -2000);public TestEvent(JFrame frame) super();this.frame = frame;updateBackground();this.setSize(200, 120);this.setVisible(true);frame.addComponentListener(this);frame.a
14、ddWindowFocusListener(this);/ TODO Auto-generated constructor stub/绘制外观 ,注意 ,其中 pos,offset 是 为了将特定部分的图象贴到窗口上public void paintComponent(Graphics g) Point pos = this.getLocationOnScreen();Point offset = new Point(-pos.x, -pos.y);g.drawImage(background, offset.x, offset.y, null);* param args*/public st
15、atic void main(String args) / TODO Auto-generated method stubtry /UIManager.setLookAndFeel(new SubstanceLookAndFeel();/UIManager.setLookAndFeel(new SmoothLookAndFeel();/UIManager.setLookAndFeel(new QuaquaLookAndFeel();UIManager.put("swing.boldMetal", false);if (System.getProperty("sub
16、stancelaf.useDecorations") = null) JFrame.setDefaultLookAndFeelDecorated(true);/JDialog.setDefaultLookAndFeelDecorated(true);SubstanceLookAndFeel.setCurrentTheme(new SubstanceLightAquaTheme();/ catch (Exception e) JFrame frame = new JFrame("Transparent Window"); TestEvent t = new Test
17、Event(frame);t.setLayout(new BorderLayout();JButton button = new JButton("This is a button");t.add("North", button);JLabel label = new JLabel("This is a label");t.add("South", label);frame.getContentPane().add("Center", t);frame.pack();frame.setSize(150, 100);frame.show();frame.setDefaultCloseOperati
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025建筑装饰工程施工合同乙种本(IV)
- 设备存放说明合同范本
- 员工调薪合同范本
- 住院医师规范化培训-骨科真题库-25
- 2025建筑工程水泥钢材采购合同
- 乡村菜园出租合同范本
- 护士护理工作计划
- 露营场景租赁合同范本
- 学校采购洗涤合同范本
- 二零二五版公司增资扩股协议
- 2025合同模板个人车位转让合同 范本
- 企业集团文件与档案管理制度
- 2024福建漳州市九龙江集团有限公司招聘10人笔试参考题库附带答案详解
- 公安审讯技巧课件
- 中国少数民族文化知到课后答案智慧树章节测试答案2025年春云南大学
- 西方教育史考题及答案
- 软件开发java笔试题及答案
- 小学综合实践三年级下册巧手工艺坊教学课件
- 2025年绍兴职业技术学院单招职业适应性测试题库带答案
- 2025年监理工程师考试《建设工程监理案例分析(水利工程)》综合案例题
- DB61T 5113-2024 建筑施工全钢附着式升降脚手架安全技术规程
评论
0/150
提交评论