3

Background Information

I would like to build a tool/palette window (also called a "floating" window) in Swing with Java Version 1.6.0_26. I thought a JWindow is the best pick, and also the Swing documentation points out to use a JWindow for such purposes (floating window, which has an owner frame, has no decoration and no windows taskbar entry).

My floating tool window's content consists of several other components like JButtons and also JTextFields.

The problem

When I click into the floating tool window, the owner window (the JFrame, my "main application window") "flickers" occasionally. The "flicker" looks like the owner window is losing the focus for a few milliseconds and than gets the focus back, resulting in a very fast disabling/enabling of the window (note that no window event is fired, like focus-lost or window-deactivated).

I have tested this under Windows 7 64 Bit and Windows XP.

Video and example code

To clarify the problem (it is a bit difficult to explain), I've taken a video, there you can see the "flicker" of the owner window while I click onto the floating tool window repeatedly:

I also put together a simple example code to reproduce the problem (this code is used in the video):

import java.awt.*;
import javax.swing.*;

public class JWindowFlickerExample
{
    public JWindowFlickerExample()
    {
        // I know swing code should be executed on the EDT,
        // just wanted to keep it simple

        // Create and show the "main application window"
        JFrame frame = new JFrame( getClass().getSimpleName() );
        frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
        frame.setSize( 640, 480 );
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );

        // Create and show the "floating tool window"
        MyFloatingToolWindow testWindow = new MyFloatingToolWindow( frame );
        testWindow.setLocation( 400, 400 );
        testWindow.setVisible( true );
    }

    public static void main( String[] args )
    {
        new JWindowFlickerExample();
    }

    @SuppressWarnings( "serial" )
    private class MyFloatingToolWindow extends JWindow
    {
        public MyFloatingToolWindow( Window hostWindow )
        {
            super( hostWindow );

            // setFocusableWindowState( false );
            setSize( 300, 400 );
            setLayout( null );
            getContentPane().setBackground( Color.LIGHT_GRAY );

            JTextField textField = new JTextField();
            textField.setLocation( 50, 50 );
            textField.setSize( 70, 30 );

            add( textField );
        }
    }
}

Progress so far

I also tried to set "Window.setFocusableWindowState" to false for the floating tool window. If it is false, there is no "flicker", the problem is gone. The JavaDoc for that method points out:

Setting a Window's focusability state to false is the standard mechanism for an application to identify to the AWT a Window which will be used as a floating palette or toolbar, and thus should be a non-focusable Window."

But then I can't use a JTextField in the floating tool window of course, because I can't focus it (maybe a text field in a floating tool window is unusual, but in my case a must).

I guess the "flicker" effect has something to do with the focus management in some way... for the fraction of a second the floating tool window gets the focus, taking it away from the owner window and then back. But I'm not sure; as a side note: if the text field in the floating tool window has the focus, the owner window stays enabled (which is a correct behavior).

I hope there is an easy solution, one so that I can stay with the JWindow as my floating tool window and with text fields as it's content - because, apart from the described "flicker" problem, everything works great.

I really appreciate any help, thanks a lot!

4

2 回答 2

2

此代码变体是否显示相同的问题?(注意:在开始更改之前,我没有看到任何明显的闪烁。)

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class JWindowFlickerExample
{
    public JWindowFlickerExample()
    {
        // I know swing code should be executed on the EDT,
        // just wanted to keep it simple
        // SOMETIMES 'KEEPING IT SIMPLE' CAN CAUSE THE PROBLEM!

        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                // Create and show the "main application window"
                JFrame frame = new JFrame( getClass().getSimpleName() );
                frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
                frame.pack();
                frame.setSize( 640, 480 );
                frame.setLocationRelativeTo( null );
                frame.setVisible( true );

                // Create and show the "floating tool window"
                MyFloatingToolWindow testWindow = new MyFloatingToolWindow( frame );
                testWindow.setLocation( 400, 400 );
                testWindow.setVisible( true );
            }
        });
    }

    public static void main( String[] args )
    {
        new JWindowFlickerExample();
    }

    @SuppressWarnings( "serial" )
    private class MyFloatingToolWindow extends JWindow
    {
        public MyFloatingToolWindow( Window hostWindow )
        {
            super( hostWindow );

            JTextField textField = new JTextField(20);

            JPanel p = new JPanel(new GridLayout());
            p.setBackground( Color.GREEN );
            p.setBorder(new EmptyBorder(40,40,40,40));
            p.add(textField);
            add( p );

            pack();
        }
    }
}
于 2012-02-11T17:37:57.713 回答
0

我认为http://bugs.sun.com/view_bug.do?bug_id=4109702上的错误可能是相关的。

无论如何,这是一个似乎为我消除闪烁的修复程序(Windows XP 上的 Java 1.6):

window = new JWindow(parentFrame);
window.setFocusableWindowState(false);
window.addComponentListener(new ComponentAdapter() {
    @Override
    public void componentShown(ComponentEvent e) {
        window.setFocusableWindowState(true);
        // Putting the focus on the content pane means that the first
        // visible component isn't focused, but if the user tabs, they
        // will get to it.
        window.getContentPane().requestFocus();
    }
    @Override
    public void componentHidden(ComponentEvent e) {
        window.setFocusableWindowState(false);
    }
});

诀窍似乎是让窗口在显示时无法聚焦。

于 2012-06-26T16:22:19.953 回答