要生成一個(gè)半透明的成形窗口,而又要避免使用本地的編碼,唯有靈活地應(yīng)用screenshot(屏幕快照).
半透明窗口是大眾對(duì)Swing最為渴求的特性之一. 也可以稱之為定形窗口,這種窗口有一部分是透明的,可以透過(guò)它看到桌面背景和其它的程序.假如不通過(guò)JNI(java Native Interface 本地接口)Java是無(wú)法為我們生成一個(gè)半透明的窗口的(即使我們可以那樣做,還得本地操作平臺(tái)好支持半透明窗口才行).然而這些現(xiàn)狀無(wú)法阻止我們對(duì)半透明窗口的渴求,通過(guò)一個(gè)我最喜歡的手段screenshot,我們可以欺騙性地實(shí)現(xiàn)這個(gè)目的.
仿造這樣一個(gè)的半透明窗口的過(guò)程,主要的通過(guò)以下幾點(diǎn):
1.在窗口顯示之前,先獲得一個(gè)screenshot;
2.把上一步獲取的屏幕快照,作為窗口的背景圖
3.調(diào)整位置,以便于我們捕捉的screenshot和實(shí)際當(dāng)前的屏幕完美結(jié)合,制造出一種半透明的假象.
剛剛說(shuō)到的部分只是小兒科,重頭戲在于,如何在移動(dòng)或變化半透明窗口時(shí),及時(shí)地更新screenshot,也就是及時(shí)更新半透明窗口的背景.
在開始我們的旅行之前,先生成一個(gè)類,讓它繼續(xù) JPanel,我們用這個(gè)繼續(xù)類來(lái)捕捉屏幕,并把捕捉的照片作為背景. 類的具體代碼如下例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( ));
// 此方法沒(méi)有申明過(guò),因?yàn)闊o(wú)法得知上下文。因?yàn)椴挥绊憟?zhí)行效果,先注釋掉它
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);
}
}
首先,構(gòu)造方法把一個(gè)reference保存到父的JFrame,然后調(diào)用updateBackground()方法,在這個(gè)方法中,我們可以利用java.awt.Robot類捕捉到整個(gè)屏幕,并把捕捉到的圖像保存到一個(gè)定義了的放置背景的變量中. paintComponent()方法可以幫助我們獲得窗口在屏幕上的絕對(duì)位置,并用剛剛得到的背景作為panel的背景圖,同時(shí)這個(gè)背景圖會(huì)因?yàn)閜anel位置的不同而作對(duì)應(yīng)的移動(dòng),以使panel的背景和panel覆蓋的那部分屏幕圖像無(wú)縫重疊在一起,同時(shí)也就使panel和四周的屏幕關(guān)聯(lián)起來(lái).
我們可以通過(guò)下面這個(gè)main方法簡(jiǎn)單的運(yùn)行一下,隨便放置一些組件到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( );
}
通過(guò)這段代碼,運(yùn)行出的效果如下圖6-1所示:
圖6-1 展示中的半透明窗口
這段代碼相當(dāng)簡(jiǎn)單,卻帶有兩個(gè)不足之處。首先,假如移動(dòng)窗口,panel中的背景無(wú)法自動(dòng)的更新,而paintComponent()只在改變窗口大小時(shí)被調(diào)用;其次,假如屏幕曾經(jīng)發(fā)生過(guò)變化,那么我們制作的窗口將永遠(yuǎn)無(wú)法和和屏幕背景聯(lián)合成整體。
誰(shuí)也不想時(shí)不時(shí)地跑去更新screenshot,想想看,要找到隱藏于窗口后的東西,要獲得一份新的screenshot,還要時(shí)不時(shí)的用這些screenshot來(lái)更新我們的半透明窗口,這些事情足以讓用戶無(wú)法安心工作。事實(shí)上,想要獲取窗口之外的屏幕的變化幾乎是不太可能的事,但多數(shù)變動(dòng)都是發(fā)生在foreground窗口發(fā)生焦點(diǎn)變化或被移動(dòng)之時(shí)。假如你接受這的觀點(diǎn)(至少我接受這個(gè)觀點(diǎn)),那么你可以只監(jiān)控下面提到的幾個(gè)事件,并只需在這幾個(gè)事件被觸發(fā)時(shí),去更新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實(shí)現(xiàn)ComponentListener接口,
WindowFocusListener接口和Runnable接口。Listener接口可以幫助我們捕捉到窗口的移動(dòng),大小變化,和焦點(diǎn)變化。實(shí)現(xiàn)Runnable接口可以使得panel生成一個(gè)線程去控制定制的repaint()方法。
ComponentListener接口帶有四個(gè)component開頭的方法。它們都可以很方便地調(diào)用repaint()方法,所以窗口的背景也就可以隨著窗口的移動(dòng),大小的變化而相應(yīng)地更新。還有兩個(gè)是焦點(diǎn)處理的,它們只調(diào)用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( );
}
}
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注