Як піднести вікно спереду?


90

У нас є програма Java, яку потрібно висувати на перший план, коли механізм телеконтролю активує щось у програмі.

Щоб отримати це, ми реалізували у викликаному методі класу, який представляє фрейм нашої програми (розширення a JFrame), наступну реалізацію:

setVisible(true);
toFront();

В ОС Windows XP це працює при першому виклику, вдруге блимає лише вкладка на панелі завдань, кадр більше не виходить на передню панель. Те саме стосується і Win2k. На Vista це, здається, працює нормально.

У вас є ідеї?


у вас є зразок такої поведінки?
OscarRyz

3
Правильна відповідь - зателефонувати toFront()за допомогою EDT invokeLater. Нижче наведено просту відповідь, але це не прийнята відповідь. Однак це працює. Прекрасно.
Ерік Робертсон,

Я знаю, що це старе, але це трапляється і на OSX
Ферділ

Я відчуваю цю проблему, але, здається, жодна з наведених нижче відповідей не вирішує її. Я впевнений, що це спричинено тим, що вікна не дозволяють мені «Викрасти» Фокус для мого першого вікна у програмі.
Крейг Уоррен,

Відповіді:


69

Можливим рішенням є:

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

8
Можливо, спочатку слід запустити ВСЕ код інтерфейсу всередині invokeLater? ;)
java.is.for.desktop. введено

2
Не працював у мене в Java 7 на KDE 4.9.5, вікно все одно буде ховатися під іншими програмами. Мені допомогло зміна порядку виведення вікон на передню панель. Замість того, щоб приховувати одне вікно та показувати друге вікно, покажіть друге вікно, а потім приховуйте перше вікно (JFrame).
Лекенштейн

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.


Дякую! Також в зв'язку це питання: stackoverflow.com/questions/2315560 / ...
rogerdpack

Він не компілюється мною через метод setDisposed (). Не вдається знайти.
ka3ak

1
@ ka3ak Це захищений сеттер, який може бути введений до запропонованого базового класу JFrame для відстеження ситуації з утилізованим фреймом. Метод dispose () потрібно було б замінити викликом setDisposed (true). Це не строго кажучи, потрібно всім.
01es

1
.setAlwaysOnTop(true);Був єдиним, який працював на мене при використанні JWindow.
DGolberg

setAlwaysOnTop(true)це єдиний спосіб запустити його під Windows 10 - дякую!
Хартмут П.

22

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.
бутта

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

@Bram: Так, це правильно. Я запускаю код на одній версії 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 (), щоб вивести вікно на передній план, навіть якщо воно було зведене до мінімуму.
грабувати

1
Підтверджено: це рішення працює в WindowsXP, використання toFront призводить до миготливого повідомлення на панелі завдань. Дякую!
Ерік Ліндауер,

5

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

Це було єдине рішення, яке працювало у мене (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()це зробив. Дякую.
Матьє

4

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

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

Тобто setStateзамість setExtendedState.


3

Найпростіший спосіб, який я виявив, що не має невідповідності між платформами:

setVisible (false); 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);
            }
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.