Как вывести окно на передний план?


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

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

setVisible(true);
toFront();

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

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

11 84

11 ответов:

возможный вариант:

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

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

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

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

тем не менее, у меня есть небольшое приложение 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, этот код, кажется, работает нормально.

вот метод, который действительно работает (протестирован на Windows Vista): D

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

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

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

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

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

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

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

setVisible (false); setVisible (true);

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

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

что это setState вместо setExtendedState.

правила, регулирующие то, что происходит, когда вы .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);
  }
});

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

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

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

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

setExtendedState(JFrame.NORMAL);

вот так:

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