Как вывести окно на фасад?

У нас есть приложение Java, которое нужно вывести на передний план, когда механизм телеуправления активирует что-то в приложении.

Чтобы получить это, мы реализовали в вызываемом методе класса, который представляет собой фрейм нашего приложения (расширение JFrame), следующую реализацию:

setVisible(true);
toFront();

В Windows XP это работает при первом вызове, во второй раз мигает только вкладка на панели задач, рамка больше не выходит на передний план. То же самое и с Win2k. В Vista вроде нормально работает.

Есть ли у вас какие-либо идеи?

у вас есть образец такого поведения?

OscarRyz 23.12.2008 00:20

Правильный ответ - вызвать в toFront() по EDT, используя invokeLater. Ниже приведен простой ответ, но это не принятый ответ. Но это действительно работает. Прекрасно.

Erick Robertson 27.03.2011 05:15

Я знаю, что это устарело, но такое бывает и в OSX.

ferdil 10.01.2012 15:09

У меня возникла эта проблема, но, похоже, ни один из приведенных ниже ответов не решает ее. Я уверен, что это вызвано тем, что окна не позволяют мне «украсть» фокус для моего первого окна в приложении.

Craig Warren 25.01.2012 20:37
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
90
4
152 411
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

В javadoc есть множество предостережения для метода toFront (), которые могут вызывать вашу проблему.

Но все равно погадаю, когда "мигает только вкладка в панели задач", приложение свернуто? В таком случае может применяться следующая строка из javadoc:

«Если это Окно видно, переносит это Окно на передний план и может сделать его окном в фокусе».

В Windows есть возможность предотвращать перехват фокуса окнами; вместо этого мигает значок на панели задач. В XP он включен по умолчанию (единственное место, где я видел, чтобы изменить его, - это TweakUI, но где-то есть параметр реестра). В Vista они могли изменить значение по умолчанию и / или выставить его как доступную пользователю настройку с помощью готового пользовательского интерфейса.

Предотвращение того, чтобы окна выдвигались вперед и фокусировались, - это функция, появившаяся со времен Windows 2K (и я, например, благодарен за это).

Тем не менее, у меня есть небольшое Java-приложение, которое я использую, чтобы напоминать мне о записи моих действий во время работы, и оно делает себя активным окном каждые 30 минут (конечно, настраиваемым). Он всегда стабильно работает под Windows XP и никогда не мигает в окне заголовка. Он использует следующий код, вызываемый в потоке пользовательского интерфейса в результате срабатывания события таймера:

if (getState()!=Frame.NORMAL) { setState(Frame.NORMAL); }
toFront();
repaint();

(первая строка восстанавливается, если свернута ... на самом деле она восстановит ее, если она развернута, но у меня этого никогда не было).

Хотя обычно это приложение свернуто, довольно часто оно просто находится за моим текстовым редактором. И, как я уже сказал, это всегда работает.

У меня есть представление о том, в чем может быть ваша проблема - возможно, у вас есть состояние гонки с вызовом setVisible (). toFront () может быть недействительным, если окно фактически не отображается при его вызове; У меня раньше была эта проблема с requestFocus (). Возможно, вам потребуется поместить вызов toFront () в прослушиватель пользовательского интерфейса для события, активируемого окном.

2014-09-07: В какой-то момент вышеуказанный код перестал работать, возможно, на Java 6 или 7. После некоторых исследований и экспериментов мне пришлось обновить код, чтобы переопределить метод toFront окна, сделайте это (вместе с измененным кодом из того, что указано выше):

setVisible(true);
toFront();
requestFocus();
repaint();

...

public @Override void toFront() {
    int sta = super.getExtendedState() & ~JFrame.ICONIFIED & JFrame.NORMAL;

    super.setExtendedState(sta);
    super.setAlwaysOnTop(true);
    super.toFront();
    super.requestFocus();
    super.setAlwaysOnTop(false);
}

Что касается Java 8_20, этот код, похоже, работает нормально.

+1 за поддержку, не позволяющую окнам красть фокус. Ненавижу, когда такое случается, когда я печатаю документ.

Ken Paul 23.11.2008 05:00

Я полностью согласен с вами против кражи фокуса, но именно в этом случае пользователь ожидает, что приложение выйдет на первый план. Но было бы нехорошо изменить настройки реестра и полностью изменить поведение Windows.

boutta 24.11.2008 10:30

Я предполагаю, что super.setAlwaysOnTop(false); так устроен, что окно не всегда наверху, что необходимо, чтобы избавиться от true, который мы установили ранее, чтобы вывести окно на передний план, верно? Я спрашиваю, потому что с вашим кодом в моем случае окно все еще всегда наверху, чего я, очевидно, не хочу. Запуск jre1.8.0_66 в Windows 10.

Bram Vanroy 06.01.2016 15:20

@ Брэм: Да, это правильно. Я запускаю код в одной и той же версии Java и Windows, и он не всегда оказывается поверх других окон. Возможно, нет необходимости устанавливать всегда сверху, но я думаю, что в противном случае Windows просто мигает строкой заголовка, по крайней мере, при некоторых условиях.

Lawrence Dol 09.01.2016 04:43

Хм, странно. Не могли бы вы взглянуть на аналогичный вопрос, в котором я ссылаюсь на этот ответ? Возможно, этот код более ясно показывает проблему: stackoverflow.com/questions/34637597/…

Bram Vanroy 09.01.2016 15:12

@ Брэм: Аааа. Я имеют видел, как это произошло. Я предполагаю, что если текущее окно получает пользовательский ввод между моментом вызова toFront и фактическим отображением, оно будет делать то, что вы описываете; фокус ввода остается в окне за ним. У меня такое случается, когда я кодирую. Временами это раздражает, потому что новое окно выглядит как будто имеет фокус. У меня даже была ситуация, когда ввод ключа отправляется в окна и то и другое. То, что я видел, похоже на ошибку в Windows, поскольку это только начало происходить в Win 10 и, похоже, попытка остановить кражу фокуса, пошла не так.

Lawrence Dol 11.01.2016 05:44
Ответ принят как подходящий

Возможное решение:

java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        myFrame.toFront();
        myFrame.repaint();
    }
});

Возможно, стоит сначала запустить ВСЕ код пользовательского интерфейса внутри invokeLater? ;)

java.is.for.desktop.indeed 15.08.2011 13:12

У меня не работало в Java 7 на KDE 4.9.5, окно все равно скрывалось под другими программами. Мне помогло изменение порядка вывода окон на фасад. Вместо того, чтобы скрывать одно окно и отображать второе окно, покажите второе окно, а затем скройте первое окно (JFrame).

Lekensteyn 13.01.2013 03:23

Работает с Windows 10 под управлением Java 1.8 в апплете

Elliott 13.04.2016 23:57

Каким был бы обратный метод?

Cardinal System 25.02.2018 05:12

У меня была такая же проблема с выводом JFrame на передний план под Ubuntu (Java 1.6.0_10). И единственный способ решить эту проблему - предоставить WindowListener. В частности, мне пришлось настроить свой JFrame так, чтобы он всегда оставался наверху при вызове toFront(), и предоставить обработчик событий windowDeactivated для setAlwaysOnTop(false).


Итак, вот код, который можно поместить в базовый JFrame, который используется для получения всех фреймов приложения.

@Override
public void setVisible(final boolean visible) {
  // make sure that frame is marked as not disposed if it is asked to be visible
  if (visible) {
      setDisposed(false);
  }
  // let's handle visibility...
  if (!visible || !isVisible()) { // have to check this condition simply because super.setVisible(true) invokes toFront if frame was already visible
      super.setVisible(visible);
  }
  // ...and bring frame to the front.. in a strange and weird way
  if (visible) {
      toFront();
  }
}

@Override
public void toFront() {
  super.setVisible(true);
  int state = super.getExtendedState();
  state &= ~JFrame.ICONIFIED;
  super.setExtendedState(state);
  super.setAlwaysOnTop(true);
  super.toFront();
  super.requestFocus();
  super.setAlwaysOnTop(false);
}

Всякий раз, когда ваша рамка должна быть отображена или вынесена на первый план, звоните frame.setVisible(true).

Поскольку я перешел на Ubuntu 9.04, похоже, нет необходимости в наличии WindowListener для вызова super.setAlwaysOnTop(false) - как можно заметить; этот код был перенесен в методы toFront() и setVisible().

Обратите внимание, что метод setVisible() всегда следует вызывать в EDT.

Спасибо! Также связан этот вопрос: stackoverflow.com/questions/2315560/…

rogerdpack 19.08.2010 01:48

Он не компилируется мной из-за метода setDisposed (). Ничего не найдено.

ka3ak 16.03.2013 21:23

@ ka3ak Это защищенный установщик, который может быть введен в предлагаемый базовый класс JFrame, чтобы отслеживать ситуацию с удаляемым фреймом. Метод dispose () необходимо переопределить вызовом setDisposed (true). Строго говоря, это необходимо не всем.

01es 17.03.2013 01:16

.setAlwaysOnTop(true); был единственным, который работал у меня при использовании JWindow.

DGolberg 13.02.2014 23:26
setAlwaysOnTop(true) - единственный способ запустить его под Windows 10 - спасибо!
Hartmut Pfarr 25.10.2018 12:33

Самый простой способ, который я нашел, не имеет противоречий между платформами:

setVisible (ложь); setVisible (правда);

вызывает некоторое мигание, не так ли? красиво и просто :)

rogerdpack 12.07.2011 20:39

не работал для моего фонового процесса. Также окно становится белым для первого обновления, если вызывается из процесса переднего плана. Нельзя использовать для захвата экрана.

DragonLord 24.01.2014 02:42

моргания можно избежать, проверив, отображается ли окно в виде значков или нет

totaam 02.11.2014 13:08

Этот простой метод отлично работал у меня в Windows 7:

    private void BringToFront() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (jFrame != null) {
                    jFrame.toFront();
                    jFrame.repaint();
                }
            }
        });
    }

repaint() не нужен, это сделал invokeLater(). Спасибо.

Matthieu 24.08.2015 16:25

Правила, управляющие тем, что происходит, когда вы .toFront () JFrame, одинаковы в Windows и Linux:

-> если окно существующего приложения в настоящее время является окном в фокусе, то фокус переключается на запрошенное окно -> если нет, окно просто мигает на панели задач

НО :

-> новые окна автоматически получают фокус

Так что давайте воспользуемся этим! Хотите вывести окно вперед, как это сделать? Что ж :

  1. Создайте пустое нецелевое окно
  2. Покажи это
  3. Подождите, пока он не появится на экране (это делает setVisible)
  4. Когда отображается, запросите фокус для окна, на которое вы действительно хотите перевести фокус.
  5. спрячь пустое окно, уничтожь его

Или в Java-коде:

// unminimize if necessary
this.setExtendedState(this.getExtendedState() & ~JFrame.ICONIFIED);

// don't blame me, blame my upbringing
// or better yet, blame java !
final JFrame newFrame = new JFrame();
newFrame.add(new JLabel("boembabies, is this in front ?"));

newFrame.pack();
newFrame.setVisible(true);
newFrame.toFront();

this.toFront();
this.requestFocus();

// I'm not 100% positive invokeLater is necessary, but it seems to be on
// WinXP. I'd be lying if I said I understand why
SwingUtilities.invokeLater(new Runnable() {
  @Override public void run() {
    newFrame.setVisible(false);
  }
});

На Win7 не заработало, мигают оба окна (если не скрою 2-е).

NateS 17.08.2013 02:51

Творческий. Не работал для моего фонового процесса на Win7, когда он был покрыт. Новая рамка не подходит. Более старый JDK 6u21.

DragonLord 24.01.2014 02:47

Hj, все ваши методы у меня не работают в Fedora KDE 14. У меня есть грязный способ вывести окно на передний план, пока мы ждем, пока Oracle исправит эту проблему.

import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;

public class FrameMain extends javax.swing.JFrame {

  //...
  private final javax.swing.JFrame mainFrame = this;

  private void toggleVisible() {
    setVisible(!isVisible());
    if (isVisible()) {
      toFront();
      requestFocus();
      setAlwaysOnTop(true);
      try {
        //remember the last location of mouse
        final Point oldMouseLocation = MouseInfo.getPointerInfo().getLocation();

        //simulate a mouse click on title bar of window
        Robot robot = new Robot();
        robot.mouseMove(mainFrame.getX() + 100, mainFrame.getY() + 5);
        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);

        //move mouse to old location
        robot.mouseMove((int) oldMouseLocation.getX(), (int) oldMouseLocation.getY());
      } catch (Exception ex) {
        //just ignore exception, or you can handle it as you want
      } finally {
        setAlwaysOnTop(false);
      }
    }
  }

  //...

}

И это отлично работает в моей Fedora KDE 14 :-)

Немного хакерский, у нас работает, но только при первом звонке :-). (Kubuntu 12.04) - другое решение не удалось

user85155 21.09.2012 20:40

Это было единственное решение, которое сработало для меня (Windows Server 2012 R2) для проблемы, когда JFrame (вход в систему) открывается, но не имеет фокуса, пока пользователь не щелкнет по нему.

glenneroo 17.05.2016 18:36

Вот метод, который ДЕЙСТВИТЕЛЬНО работает (проверено в Windows Vista): D

   frame.setExtendedState(JFrame.ICONIFIED);
   frame.setExtendedState(fullscreen ? JFrame.MAXIMIZED_BOTH : JFrame.NORMAL);

Переменная полноэкранного режима указывает, хотите ли вы, чтобы приложение работало в полноэкранном или оконном режиме.

При этом панель задач не мигает, но окно надежно выводится на передний план.

Спасибо за совет setExtendedState. Я использовал его вместе с решениями toFront () и repaint (), чтобы вывести окно на передний план, даже если оно было свернуто.

rob 24.11.2011 04:16

Подтверждено: это решение работает в WindowsXP, использование toFront приводит к миганию сообщения на панели задач. Спасибо!

Eric Lindauer 22.05.2012 06:20

Я проверил ваши ответы и у меня работал только Штефана Райха. Хотя мне не удалось восстановить окно в его предыдущее состояние (развернутое / нормальное). Я нашел эту мутацию лучше:

view.setState(java.awt.Frame.ICONIFIED);
view.setState(java.awt.Frame.NORMAL);

То есть setState вместо setExtendedState.

Чтобы окно не потеряло фокус при его возвращении в видимое состояние после того, как оно было скрыто, все, что необходимо:

setExtendedState(JFrame.NORMAL);

Вот так:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});

Другие вопросы по теме