Использование JWindow для плавающего окна инструмента вызывает «мерцание» окна владельца при щелчке в плавающем окне - PullRequest
3 голосов
/ 11 февраля 2012

Справочная информация

Я хотел бы создать окно инструментов / палитр (также называемое "плавающим" окном) в Swing с Java Version 1.6.0_26 .Я думал, что JWindow - лучший выбор, а также документация Swing указывает на использование JWindow для таких целей (плавающее окно, которое имеет рамку владельца, не имеет декорации и не имеет входа в панель задач Windows).

MyСодержимое плавающего окна инструментов состоит из нескольких других компонентов, таких как JButtons, а также JTextFields.

Проблема

Когда я щелкаю в плавающем окне инструментов, окно владельца (JFrame, мое "главное окно приложения)иногда мерцает.«Мерцание» выглядит так, как будто окно владельца теряет фокус на несколько миллисекунд, а затем возвращает фокус обратно, что приводит к очень быстрому отключению / включению окна (обратите внимание, что событие окна не запускается, например, потеря фокуса или окно-деактивирован).

Я проверил это в 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 для плавающего окна инструмента.Если оно ложно, мерцания нет, проблема исчезла.JavaDoc для этого метода указывает:

Установка состояния фокусировки окна на false - это стандартный механизм для приложения, чтобы идентифицировать AWT окно, которое будет использоваться в качестве плавающей палитры или панели инструментов, итаким образом, должно быть окно без фокуса. "

Но тогда я не могу использовать JTextField в плавающем окне инструмента, конечно, потому что я не могу сфокусировать его (возможно, текстовое поле вплавающее окно инструмента необычно, но в моем случае это необходимо).

Я думаю, что эффект "мерцания" как-то связан с управлением фокусом ... на долю секунды плавающий инструментокно получает фокус, убирая его из окна владельца, а затем обратно. Но я не уверен, как примечание стороны: если текстовое поле в плавающем окне инструмента имеет фокус, окно владельца остается включенным (который являетсяправильное поведение).

Я надеюсь, что есть простое решение, так что я могу остаться с JWindow в качестве моего плавающего окна инструмента и с текстовыми полями как оно 's содержание - потому что, кроме описанной проблемы с «мерцанием», все прекрасно работает.

Я очень ценю любую помощь, большое спасибо!

Ответы [ 2 ]

2 голосов
/ 11 февраля 2012

Этот вариант кода показывает ту же проблему?(Примечание: я не заметил заметного мерцания, прежде чем начал его менять.)

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();
        }
    }
}
0 голосов
/ 26 июня 2012

Я думаю, что ошибка в http://bugs.sun.com/view_bug.do?bug_id=4109702 может быть связана.

В любом случае, вот исправление, которое, кажется, удаляет мерцание для меня (Java 1.6 в Windows XP):

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

Уловка, кажется, состоит в том, чтобы окно не было фокусируемым во время его показа.

...