惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
小众软件
小众软件
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
Apple Machine Learning Research
Apple Machine Learning Research
F
Fortinet All Blogs
罗磊的独立博客
爱范儿
爱范儿
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
D
Docker
C
CXSECURITY Database RSS Feed - CXSecurity.com
Spread Privacy
Spread Privacy
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
G
GRAHAM CLULEY
A
About on SuperTechFans
C
Cisco Blogs
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
B
Blog
Project Zero
Project Zero
V
V2EX
K
Kaspersky official blog
P
Privacy International News Feed
博客园 - 叶小钗
I
Intezer
T
Threatpost
The GitHub Blog
The GitHub Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V
Vulnerabilities – Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 【当耐特】
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
S
Schneier on Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
F
Full Disclosure
The Cloudflare Blog
P
Palo Alto Networks Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tenable Blog

博客园 - 空空色色

转一篇,CentOS后台服务配置 linux kernel 2.6.36 编译升级 linux的UPNP支持(转) UPNP协议细节(转) UPnp协议 from wikipedia 考察智力zz JScollPane以及JPanel相关 bmp文件格式 java中对图象文件的处理(读写以及转换) Java媒体框架(JMF),个人很欣赏.... 常用颜色对照表 YUV/YIQ色彩空间的转换 java中的数据库程序应用 A*以及迭代加深的A*算法(IDA*) 我的兄弟们之袋鼠篇 深度优先状态搜索法 我的兄弟们之温J篇 java中的图象处理技术基础 经典搜索算实现之一,广度优先.
关于Swing实现透明窗体的。我也很喜欢,收藏!
空空色色 · 2006-12-12 · via 博客园 - 空空色色

       Editor's note: The following example from Swing Hacks is one of the book's most visually daring hacks--mimicking the arbitrarily shaped window you might see in an native MP3 player skin. The hack here is necessitated by the fact that Java doesn't support non-rectangular windows, so the only option to make this work is for the Java window to be aware of what's under it, and to handle the imaging of areas within the window's rectangle but not within its arbitrary shape. Read on for how this is accomplished.

figure Hack 41

Create translucent and shaped windows, while avoiding native code, with clever use of a screenshot.

One of the most commonly requested Swing features is transparent windows. Also called shaped windows, these are windows that have transparent portions, allowing the desktop background and other programs to shine through. Java doesn't provide any way of creating transparent windows without using the Java Native Interface (JNI) (and even then the native platform must support transparency as well), but that's not going to stop us. We can cheat using one of my favorite techniques, the screenshot.

The process of faking a transparent window is basically:

  1. Take a screenshot before the window is shown.

  2. Use that screenshot as the background of the window.

  3. Adjust the position so that the screenshot and the real screen line up, creating the illusion of transparency.

This is the easy part. The hard part is updating the screenshot when the window moves or changes.

To start off, create a JPanel subclass that can capture the screen and paint it as the background, as shown in Example 6-1

Example 6-1. A transparent background component

public   class  TransparentBackground  extends  Jcomponent { 
    
private  JFrame frame; 
    
private  Image background;public  TransparentBackground(JFrame frame) {
    
this .frame  =  frame;
    updateBackground( );
}
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 );
}

First, the constructor saves a reference to the parent JFrame; then it calls updateBackground( ), which captures the entire screen using java.awt.Robot. createScreenCapture( ), and saves the capture in the background variable. paintComponent( ) gets the panel's absolute position on screen and then fills the panel with the background image, shifted to account for the panel's location. This makes the fake background image line up with the real background, giving the appearance of transparency.

You can run this with a simple main( ) method, dropping a few components onto the panel and putting it into a 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( );
}

The code produces a window that looks like Figure 6-1.

The code is pretty simple, but it has two big flaws. First, if the window is moved, the background won't be refreshed automatically. paintComponent( ) only gets called when the user resizes the window. Second, if the screen ever changes, it won't match up with the background anymore.

You really don't want to update the screenshot often, though, because that involves hiding the window, taking a new screenshot, and then reshowing the window—all of which is disconcerting to the user. Actually detecting when the rest of the desktop changes is almost impossible, but most changes happen when the foreground window changes focus or moves. If you accept this idea (and I do), then you can watch for those events and only update the screenshot when that happens:

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

First, make the panel, TransparentWindow, implement ComponentListener, WindowFocusListener, and Runnable. The listener interfaces will let the panel catch events indicating that the window has moved, been resized, or the focus changes. Implementing Runnable will let the panel create a thread to handle custom repaint( )s.

The implementation of ComponentListener involves the four methods beginning with component. They each simply call repaint( ) so that the background will be updated whenever the user moves or resizes the window. Next are the two window focus handlers, which just call refresh( ), as shown here:

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


refresh( ) ensures that the frame is visible and schedules a repaint. It also sets the refreshRequested boolean to true and saves the current time, which will become very important shortly.

The run( ) method sleeps constantly, waking up every quarter-second to see if a refresh has been requested, and whether it has been more than a second since the last refresh. If more than a second has passed and the frame is actually visible, then run( ) will save the frame location, hide it, update the background, then put the frame back in place and call refresh( ). This ensures that the background is never updated more than needed.

So, why all of this rigmarole about using a thread to control refreshing? One word: recursion. The event handlers could simply call updateBackground( ) and repaint( ) directly, but hiding and showing the window to generate the screenshot would cause more focus-changed events. These would then trigger another background update, causing the window to hide again, and so on, creating an infinite loop. The new focus events are generated a few milliseconds after refresh( ) is processed, so simply checking for an isRecursing flag wouldn't stop a loop.

Additionally, any user action that would change the screen will probably create lots of events, not just one. It's just the last event that should trigger updateBackground( ), not the first. To handle all these issues, the code creates a thread that watches for repaint requests and only processes a new screenshot if it hasn't already been done in the last 1,000 milliseconds. If the user generates events continuously for five seconds (searching for that lost browser window, for example), then only when everything else has settled down for a second will the refresh actually happen. This ensures that users won't have a window disappear out from under them while they are moving things around.

Another annoyance is that the window still has its border, which sort of ruins the effect of having a transparent background. Unfortunately, removing the borders with setUndecorated(true) would also remove the titlebar and window controls. This probably isn't too much of a problem, though, because the types of applications that typically use shaped windows usually have draggable backgrounds [Hack #34].

Here's a simple test program to put this into action:

public   static   void  main(String[] args) {
    JFrame frame 
=   new  JFrame( " Transparent Window " );
    frame.setUndecorated(
true );
    
    TransparentBackground bg 
=   new  TransparentBackground(frame);
    bg.snapBackground( );
    bg.setLayout(
new  BorderLayout( ));

   JPanel panel 

=   new  JPanel( ) {
        
public   void  paintComponent(Graphics g) { 
            g.setColor(Color.blue);
            Image img 
=   new  ImageIcon( " mp3.png " ).getImage( ); 
            g.drawImage(img,
0 , 0 , null );
        }
    };
    panel.setOpaque(
false );

    bg.add(

" Center " ,panel);

    frame.getContentPane( ).add(

" Center " ,bg);
    frame.pack( );
    frame.setSize(
200 , 200 );
    frame.setLocation(
500 , 500 );
    frame.show( );
}

The code creates a faux MP3 player interface using a JPanel subclass and a PNG image with transparency. Note the call to frame.setUndecorated(true), which turns off the border and titlebar. The call to panel.setOpaque(false) turns off the default background (usually plain gray), allowing the screenshot background to shine through the transparent parts of the image (Figure 6-2). This produces a window that looks like Figure 6-3—a vision of Java programs to come?

Figure 6-2
Figure 6-2. Template for an MP3 player

Figure 6-3
Figure 6-3. Running the MP3 player