Как вывести окно на фронт? - PullRequest
86 голосов
/ 21 ноября 2008

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

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

setVisible(true);
toFront();

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

У вас есть идеи?

Ответы [ 11 ]

67 голосов
/ 23 декабря 2008

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

java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        myFrame.toFront();
        myFrame.repaint();
    }
});
33 голосов
/ 27 февраля 2009

У меня была такая же проблема с выводом 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.

21 голосов
/ 22 ноября 2008

В 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, этот код работает нормально.

11 голосов
/ 15 сентября 2011

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

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

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

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

5 голосов
/ 13 сентября 2011

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: -)

4 голосов
/ 09 марта 2012

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

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

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

4 голосов
/ 10 мая 2011

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

    private void BringToFront() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if(jFrame != null) {
                    jFrame.toFront();
                    jFrame.repaint();
                }
            }
        });
    }
3 голосов
/ 02 ноября 2010

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

SetVisible (ложь); SetVisible (истина);

2 голосов
/ 24 июня 2011

Правила, определяющие, что происходит, когда вы .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);
  }
});
0 голосов
/ 30 декабря 2014

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

setExtendedState(JFrame.NORMAL);

Вот так:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...