Фрейм всегда только поверх моей программы

#java #swing #always-on-top

#java #качать #всегда на вершине

Вопрос:

Я пытаюсь создать что-то вроде панели инструментов в недекорированной рамке AlwaysOnTop. Таким образом, я хочу, чтобы мой фрейм был поверх моего основного фрейма, но не поверх фреймов из других программ. Я попробовал этот код :

 public class Test {
    private static JFrame mainFrame;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                mainFrame = new JFrame("test");
                mainFrame.setSize(800,600);
                mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                mainFrame.setVisible(true);

                A a = new A();
            }
        });
    }

    public static class A extends JDialog {

        public A() {
            super(mainFrame);
            setAlwaysOnTop(true);
            setFocusable(false);
            setSize(80,60);
            setVisible(true);
        }
    }
}
 

Но, несмотря на использование JDialog и уточнение владельца, фрейм остается на вершине других приложений (по крайней мере, с Ubuntu. Может быть, результат отличается от других ОС?)

РЕДАКТИРОВАТЬ: Хорошо, я попробовал этот код для своего диалогового окна :

 public static class A extends JDialog {

    public A(String name) {
        super(mainFrame, name);
        setAlwaysOnTop(true);
        setFocusable(false);
        setSize(80, 60);
        setVisible(true);

        mainFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowActivated(WindowEvent e) {
                A.this.setAlwaysOnTop(true);
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
                // A.this.setAlwaysOnTop(false);
                A.this.toBack();
            }
        });
    }
}
 

Проблема сейчас в том, что когда главное окно теряет фокус, диалоговое окно возвращает фокус обратно, и я не понимаю почему. Например, я запускаю свое приложение, пытаюсь переключиться на Firefox, появляется Firefox и закрывает мэйнфрейм, но диалоговое окно получает фокус и остается на экране. Теперь, если я снова выберу Firefox, диалоговое окно, наконец, правильно исчезнет. Не могли бы вы объяснить мне, почему диалог получает особое внимание?

Спасибо

Комментарии:

1. Я думаю, вам нужно будет прибегнуть к использованию какого-то встроенного взлома через JNI / JNA

2. class A extends JFrame ?

3. что произойдет, если вы удалите setAlwaysOnTop() ? Обычно ваш фрейм должен оставаться поверх других фреймов. Устанавливается setAlwaysOnTop() флаг для ОС

4. @JoopEggen: множественный JFrame: не очень хорошая практика GameDroids: я пробовал. Если я нажму на основной фрейм, мой диалог останется позади

Ответ №1:

Вы должны сделать так, чтобы ваше окно всегда было сверху, только когда родительское окно становится активированным. Что — то вроде этого:

 public class Test {
    private static JFrame mainFrame;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                mainFrame = new JFrame("test");
                mainFrame.setSize(800,600);
                mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                mainFrame.setVisible(true);

                final A a = new A();
                mainFrame.addWindowListener(new WindowAdapter() {
                    /**
                     * {@inheritDoc}
                     */
                    @Override
                    public void windowDeactivated(WindowEvent e) {
                        a.setAlwaysOnTop(false);
                    }

                    /**
                     * {@inheritDoc}
                     */
                    @Override
                    public void windowActivated(WindowEvent e) {
                        a.setAlwaysOnTop(true);
                    }
                });
            }
        });
    }

    public static class A extends JDialog {

        public A() {
            super(mainFrame);
            setAlwaysOnTop(true);
            setFocusable(false);
            setSize(80,60);
            setVisible(true);
        }
    }
}
 

Комментарии:

1. Звучит хорошо. Давайте попробуем это в моей реальной программе. Я дам вам знать.

2. ОК. Я попробовал ваш подход. это не работает с setAlwaysOnTop(false), но работает с toBack(). Тем не менее, у меня все еще есть небольшая проблема. Пожалуйста, посмотрите мою правку. И спасибо за вашу помощь !

3. @user1967800 когда кадр находится сверху, он крадет фокус. Поэтому вы должны установить для параметра AlwaysOnTop значение false.

4. toBack вызывает setAlwaysOnTop(false). Во всяком случае, я пытался, но ошибка осталась. Я думаю, это потому, что вызов toBack() выполняется слишком поздно. Вероятно, фокус перенесен из моего приложения в другое перед запуском события?

Ответ №2:

Хорошо, я нашел решение (не знаю, является ли это решением, но оно работает, так что …)

Я обнаружил setFocusableWindowState() , который идеально подходит для панелей инструментов. Кстати, я не знаю, имел ли какой-либо эффект мой предыдущий setFocusable (false).

Следующая проблема заключалась в том, что фокус становится очень странным с этим кодом: если я переключусь с MyApp на Firefox, вот что произойдет :

 focus : MyApp -> Firefox
execution of MyDialog.toFront()
focus : Firefox -> MyDialog
MyDialog not focusable !
focus : MyDialog -> MyApp !!!
 

результат: ничего не изменилось!

Итак, я, наконец, понял хитрости: сразу после MyDialog.toFront(), вы возвращаете фокус предыдущему владельцу. И единственным способом, который я нашел, чтобы сделать это без ошибок, было: mainFrame.toBack()

Окончательный код :

 public class Test {
    private static JFrame mainFrame;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                mainFrame = new JFrame("test");
                mainFrame.setSize(800,600);
                mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                mainFrame.setVisible(true);

                A a = new A();
            }
        });
    }

    public static class A extends JDialog {

        public A() {
            super(mainFrame);
            setAlwaysOnTop(true);
            setFocusableWindowState(false);
            setSize(80,60);
            setVisible(true);

            mainFrame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowActivated(WindowEvent e) {
                    A.this.setAlwaysOnTop(true);
                    A.this.toFront();
                }
                @Override
                public void windowDeactivated(WindowEvent e) {
                    A.this.setAlwaysOnTop(false);
                }
            });
        }
    }
}
 

Комментарии:

1. Я подтвердил это решение в Windows 10. Спасибо