#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. Спасибо