王朝网络
分享
 
 
 

Swing破局:打造半透明窗口

王朝system·作者佚名  2008-05-31
宽屏版  字体: |||超大  

要生成一个半透明的成形窗口,而又要避免使用本地的编码,唯有灵活地应用screenshot(屏幕快照).

半透明窗口是大众对Swing最为渴求的特性之一. 也可以称之为定形窗口,这种窗口有一部分是透明的,可以透过它看到桌面背景和其它的程序.假如不通过JNI(java Native Interface 本地接口)Java是无法为我们生成一个半透明的窗口的(即使我们可以那样做,还得本地操作平台好支持半透明窗口才行).然而这些现状无法阻止我们对半透明窗口的渴求,通过一个我最喜欢的手段screenshot,我们可以欺骗性地实现这个目的.

仿造这样一个的半透明窗口的过程,主要的通过以下几点:

1.在窗口显示之前,先获得一个screenshot;

2.把上一步获取的屏幕快照,作为窗口的背景图

3.调整位置,以便于我们捕捉的screenshot和实际当前的屏幕完美结合,制造出一种半透明的假象.

刚刚说到的部分只是小儿科,重头戏在于,如何在移动或变化半透明窗口时,及时地更新screenshot,也就是及时更新半透明窗口的背景.

在开始我们的旅行之前,先生成一个类,让它继续 JPanel,我们用这个继续类来捕捉屏幕,并把捕捉的照片作为背景. 类的具体代码如下例6-1

例 6-1 。 半透明背景组件

public class TransparentBackground extends Jcomponent {

PRivate JFrame frame;

private Image background;

public TransparentBackground(JFrame frame) {

this.frame = frame;

updateBackground( );

}

/**

* @todo 获取屏幕快照后立即更新窗口背景

*/

public void updateBackground( ) {

try {

Robot rBT = 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( );

}

}

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);

}

}

首先,构造方法把一个reference保存到父的JFrame,然后调用updateBackground()方法,在这个方法中,我们可以利用java.awt.Robot类捕捉到整个屏幕,并把捕捉到的图像保存到一个定义了的放置背景的变量中. paintComponent()方法可以帮助我们获得窗口在屏幕上的绝对位置,并用刚刚得到的背景作为panel的背景图,同时这个背景图会因为panel位置的不同而作对应的移动,以使panel的背景和panel覆盖的那部分屏幕图像无缝重叠在一起,同时也就使panel和四周的屏幕关联起来.

我们可以通过下面这个main方法简单的运行一下,随便放置一些组件到panel上,再把panel放置到frame中显示.

public static void main(String[] args) {

JFrame frame = new JFrame("Transparent Window");

TransparentBackground bg = new TransparentBackground(frame);

bg.setLayout(new BorderLayout( ));

JButton button = new JButton("This is a button");

bg.add("North",button);

JLabel label = new JLabel("This is a label");

bg.add("South",label);

frame.getContentPane( ).add("Center",bg);

frame.pack( );

frame.setSize(150,100);

frame.show( );

}

通过这段代码,运行出的效果如下图6-1所示:

图6-1 展示中的半透明窗口

这段代码相当简单,却带有两个不足之处。首先,假如移动窗口,panel中的背景无法自动的更新,而paintComponent()只在改变窗口大小时被调用;其次,假如屏幕曾经发生过变化,那么我们制作的窗口将永远无法和和屏幕背景联合成整体。

谁也不想时不时地跑去更新screenshot,想想看,要找到隐藏于窗口后的东西,要获得一份新的screenshot,还要时不时的用这些screenshot来更新我们的半透明窗口,这些事情足以让用户无法安心工作。事实上,想要获取窗口之外的屏幕的变化几乎是不太可能的事,但多数变动都是发生在foreground窗口发生焦点变化或被移动之时。假如你接受这的观点(至少我接受这个观点),那么你可以只监控下面提到的几个事件,并只需在这几个事件被触发时,去更新screenshot。

public class TransparentBackground extends JComponent

implements ComponentListener, WindowFocusListener,

Runnable {

private JFrame frame;

private Image background;

private long lastupdate = 0;

public boolean refreshRequested = true;

public TransparentBackground(JFrame frame) {

this.frame = frame;

updateBackground( );

frame.addComponentListener(this);

frame.addWindowFocusListener(this);

new Thread(this).start( );

}

public void componentShown(ComponentEvent evt) { repaint( ); }

public void componentResized(ComponentEvent evt) { repaint( ); }

public void componentMoved(ComponentEvent evt) { repaint( ); }

public void componentHidden(ComponentEvent evt) { }

public void windowGainedFocus(WindowEvent evt) { refresh( ); }

public void windowLostFocus(WindowEvent evt) { refresh( ); }

首先,让我们的半透明窗口即panel实现ComponentListener接口,

WindowFocusListener接口和Runnable接口。Listener接口可以帮助我们捕捉到窗口的移动,大小变化,和焦点变化。实现Runnable接口可以使得panel生成一个线程去控制定制的repaint()方法。

ComponentListener接口带有四个component开头的方法。它们都可以很方便地调用repaint()方法,所以窗口的背景也就可以随着窗口的移动,大小的变化而相应地更新。还有两个是焦点处理的,它们只调用refresh(),如下示意:

public void refresh( ) {

if(frame.isVisible( )) {

repaint( );

refreshRequested = true;

lastupdate = new Date( ).getTime( );

}

}

public void run( ) {

try {

while(true) {

Thread.sleep(250);

long now = new Date( ).getTime( );

if(refreshRequested &&

((now - lastupdate) > 1000)) {

if(frame.isVisible( )) {

Point location = frame.getLocation( );

frame.hide( );

updateBackground( );

frame.show( );

frame.setLocation(location);

refresh( );

}

lastupdate = now;

refreshRequested = false;

}

}

} catch (Exception ex) {

p(ex.toString( ));

ex.printStackTrace( );

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有