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

90

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

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

setVisible(true);
toFront();

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

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

Бутта
источник
у вас есть образец такого поведения?
OscarRyz
3
Правильный ответ - вызвать toFront()EDT с помощью invokeLater. Ниже приведен простой ответ, но это не принятый ответ. Однако это действительно работает. Отлично.
Эрик Робертсон,
Я знаю, что это
устарело
У меня возникла эта проблема, но, похоже, ни один из приведенных ниже ответов не решает ее. Я уверен, что это вызвано тем, что окна не позволяют мне «украсть» фокус для моего первого окна в приложении.
Крейг Уоррен

Ответы:

69

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

java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        myFrame.toFront();
        myFrame.repaint();
    }
});
что-то
источник
8
Возможно, стоит сначала запустить ВСЕ код пользовательского интерфейса внутри invokeLater? ;)
java.is.for.desktop.indeed
2
У меня не работало в Java 7 на KDE 4.9.5, окно все равно скрывалось под другими программами. Мне помогло изменение порядка вывода окон на фасад. Вместо того, чтобы скрывать одно окно и отображать второе окно, покажите второе окно, а затем скройте первое окно (JFrame).
Lekensteyn
1
Работает с Windows 10 под управлением Java 1.8 в апплете
Эллиотт,
Каким был бы обратный метод?
Кардинал - Восстановите Монику
33

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

01es
источник
Благодарность! Также связан этот вопрос: stackoverflow.com/questions/2315560/…
rogerdpack
Он не компилируется мной из-за метода setDisposed (). Ничего не найдено.
ka3ak
1
@ ka3ak Это защищенный установщик, который может быть введен в предлагаемый базовый класс JFrame для отслеживания ситуации с удалением кадра. Метод dispose () необходимо переопределить вызовом setDisposed (true). Строго говоря, это необходимо не всем.
01es
1
Это .setAlwaysOnTop(true);был единственный, который работал у меня при использовании JWindow.
DGolberg
setAlwaysOnTop(true)это единственный способ заставить его работать под Windows 10 - спасибо!
Хартмут П.
23

В 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
+1 за поддержку, не позволяющую окнам красть фокус. Ненавижу, когда такое случается, когда я печатаю документ.
Кен Пол,
1
Я полностью согласен с вами против кражи фокуса, но именно в этом случае пользователь ожидает, что приложение выйдет на первый план. Но было бы не круто изменить настройки реестра и полностью изменить поведение Windows.
boutta
Я предполагаю, что super.setAlwaysOnTop(false);это так, что окно не всегда сверху, что необходимо, чтобы избавиться от того, что trueмы установили ранее, чтобы вывести окно на передний план, верно? Я спрашиваю, потому что с вашим кодом в моем случае окно все еще всегда наверху, чего я, очевидно, не хочу. Запуск jre1.8.0_66 в Windows 10.
Брэм Ванрой, 06
@ Брэм: Да, это правильно. Я запускаю код в одной и той же версии Java и Windows, и он не всегда оказывается поверх других окон. Возможно, нет необходимости устанавливать всегда сверху, но я думаю, что иначе Windows просто мигает строкой заголовка, по крайней мере, при некоторых условиях.
Лоуренс Дол
Хм, странно. Не могли бы вы взглянуть на аналогичный вопрос, в котором я ссылаюсь на этот ответ? Возможно, этот код более четко показывает проблему: stackoverflow.com/questions/34637597/…
Брэм Ванрой
11

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

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

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

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

Стефан Райх
источник
Спасибо за подсказку setExtendedState. Я использовал его вместе с решениями toFront () и repaint (), чтобы вывести окно на передний план, даже если оно было свернуто.
rob
1
Подтверждено: это решение работает в WindowsXP, использование toFront приводит к миганию сообщения на панели задач. Благодарность!
Эрик Линдауэр
5

Эй, все ваши методы у меня не работают в 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
Это было единственное решение, которое сработало для меня (Windows Server 2012 R2) для проблемы, когда JFrame (вход в систему) открывается, но не фокусируется, пока пользователь не щелкнет по нему.
glenneroo
4

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

    private void BringToFront() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if(jFrame != null) {
                    jFrame.toFront();
                    jFrame.repaint();
                }
            }
        });
    }
Г-н Эд
источник
2
Это repaint()не нужно, invokeLater()он сделал это. Спасибо.
Matthieu
4

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

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

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

Ярекчек
источник
3

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

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

Богатый
источник
1
вызывает некоторое мигание, не так ли? красиво и просто :)
rogerdpack
не работал для моего фонового процесса. Также окно становится белым при первом обновлении, если вызывается из процесса переднего плана. Нельзя использовать для захвата экрана.
DragonLord
моргания можно избежать, проверив, отображается ли окно в виде значков или нет
totaam
2

Правила, определяющие, что происходит, когда вы .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
Творческий. Не работал для моего фонового процесса на Win7, когда он был покрыт. Новая рамка не подходит. Более старый JDK 6u21.
DragonLord
0

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

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

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

Брендан Кэшман
источник
0

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

setExtendedState(JFrame.NORMAL);

Вот так:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});
Мартин Сансоне - MiOEE
источник