3

背景情報

Java バージョン 1.6.0_26を使用して Swing でツール/パレット ウィンドウ (「フローティング」ウィンドウとも呼ばれます) を構築したいと考えています。私は JWindow が最良の選択だと思いました。また、Swing のドキュメントでは、そのような目的で JWindow を使用することを指摘しています (オーナー フレームを持つフローティング ウィンドウには、装飾も Windows タスクバー エントリもありません)。

私のフローティング ツール ウィンドウのコンテンツは、JButtons や JTextFields などの他のいくつかのコンポーネントで構成されています。

問題

フローティング ツール ウィンドウをクリックすると、オーナー ウィンドウ (JFrame、私の「メイン アプリケーション ウィンドウ」) がときどき「ちらつき」ます。「ちらつき」は、所有者ウィンドウが数ミリ秒間フォーカスを失っているように見え、その後フォーカスを取り戻し、ウィンドウの無効化/有効化を非常に高速に行います (focus-lost や window などのウィンドウ イベントは発生しないことに注意してください)。 -非アクティブ化)。

Windows 7 64 ビットおよび Windows XP でこれをテストしました。

ビデオとサンプルコード

問題を明確にするために (説明するのは少し難しいです)、ビデオを撮影しました。フローティング ツール ウィンドウを繰り返しクリックすると、オーナー ウィンドウの「ちらつき」が見られます。

  • http://goo.gl/wVEqJ (.MOV ビデオ形式、再生するには Quicktime が必要だと思います)

問題を再現するための簡単なサンプル コードもまとめました (このコードはビデオで使用されています)。

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

これまでの進捗

また、フローティング ツール ウィンドウの "Window.setFocusableWindowState" を false に設定しようとしました。false の場合、「ちらつき」はなく、問題はなくなりました。そのメソッドの JavaDoc は次のように指摘しています。

Window のフォーカス可能状態を false に設定することは、アプリケーションが AWT に対してフローティング パレットまたはツールバーとして使用される Window を識別するための標準的なメカニズムであり、したがって、フォーカス不可能な Window であるべきです。」

しかし、もちろん、フローティング ツール ウィンドウで JTextField を使用することはできません。これは、フォーカスできないためです (フローティング ツール ウィンドウのテキスト フィールドは珍しいかもしれませんが、私の場合は必須です)。

「ちらつき」効果は、何らかの形でフォーカス管理と関係があると思います...一瞬、フローティングツールウィンドウがフォーカスを取得し、所有者ウィンドウから離れてから戻ってきます。確信はないけど; 補足: フローティング ツール ウィンドウのテキスト フィールドにフォーカスがある場合、オーナー ウィンドウは有効なままになります (これは正しい動作です)。

JWindow をフローティング ツール ウィンドウとして使用し、テキスト フィールドをコンテンツとして使用できるようにするための簡単な解決策があることを願っています。

本当にありがとうございました。

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 に答える