如何把窗户放到前面?


90

我们有一个Java应用程序,当远程控制机制激活该应用程序中的某些内容时,需要将其置于前台。

为了实现这一点,我们已经在该类的被调用方法中实现了该方法,该方法表示实现后我们应用程序的框架(扩展为JFrame):

setVisible(true);
toFront();

在Windows XP下,此功能在首次调用时有效,第二次仅任务栏上的选项卡闪烁时,框架不再位于最前面。Win2k也是如此。在Vista上似乎工作正常。

你有什么想法?


您是否有这种行为的样本?
OscarRyz

3
正确的答案是使用调用toFront()EDT invokeLater。下面包含一个简单的答案,但这不是公认的答案。确实可以。完美。
Erick Robertson

我知道这很旧,但是在OSX上也会发生
ferdil 2012年

我遇到了这个问题,但是下面的答案似乎都无法解决。我确定这是由于Windows不允许我在应用程序中的第一个窗口“隐藏”焦点引起的。
克雷格·沃伦

Answers:


69

可能的解决方案是:

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

8
也许一个人应该首先在invokeLater内部启动所有UI代码?;)
java.is.for.desktop.indeed,2011年

2
在KDE 4.9.5的Java 7中对我不起作用,该窗口仍将隐藏在其他程序下方。帮助我改变了将窗户移到最前面的顺序。而不是隐藏一个窗口并显示第二个窗口,而是显示第二个窗口,然后隐藏第一个窗口(JFrame)。
Lekensteyn

1
可在运行于applet中运行Java 1.8的Windows 10上运行
Elliott

逆方法是什么?
红衣主教-恢复莫妮卡

33

JFrame在Ubuntu(Java 1.6.0_10)下将a 置于最前面时,我遇到了同样的问题。我唯一可以解决此问题的方法是提供一个WindowListener。具体来说,我必须将自己设置JFrame为始终toFront()被调用,始终保持在最前面,并向提供windowDeactivated事件处理程序setAlwaysOnTop(false)


因此,这是可以放置在base中的代码,该代码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)来覆盖。严格来说,这并不是每个人都需要的。
2013年

1
.setAlwaysOnTop(true);使用JWindow时,这是唯一对我有用的工具。
DGolberg 2014年

setAlwaysOnTop(true)是让它在Windows 10下运行的唯一方法-谢谢!
Hartmut P.

22

Windows具有防止Windows窃取焦点的功能。而是闪烁任务栏图标。在XP中,默认情况下它处于打开状态(我看到的唯一更改它的地方是使用TweakUI,但是某处有一个注册表设置)。在Vista中,他们可能已经更改了默认设置和/或使用即用型UI将其公开为用户可访问的设置。

自Windows 2K以来,防止Windows强迫自己进入焦点并成为焦点是一项功能(我对此很感激)。

就是说,我有一个小Java应用程序,用于提醒我记录工作时的活动,它使自己每30分钟成为活动窗口(当然是可配置的)。它在Windows XP下始终能够始终如一地工作,并且不会闪烁标题栏窗口。它使用以下代码,由于计时器事件触发而在UI线程中调用了以下代码:

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

(如果最小化,第一行将还原。实际上,如果最大化也将还原它,但我从来没有这样)。

虽然我通常将此应用程序最小化,但通常它只是在我的文本编辑器后面。而且,就像我说的那样,它始终有效。

我确实对您的问题可能有个想法-也许您通过setVisible()调用遇到了竞争状况。除非窗口实际在调用时显示,否则toFront()可能无效。我之前在requestFocus()中遇到过此问题。您可能需要在窗口激活的事件上将toFront()调用放入UI侦听器中。

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表示支持不允许Windows夺取焦点。我讨厌在键入文档时发生这种情况。
Ken Paul

1
我完全同意您的观点,但在这种情况下,用户希望应用程序排在最前面。但是,更改注册表设置和更改完整的Windows行为将很不爽。
08年

我猜super.setAlwaysOnTop(false);是这样的,所以窗口并不总是在最上面,这是摆脱true我们先前设置的将窗口置于最前面的必要的,对吗?我问是因为对于您的代码,就我而言,窗口始终始终位于顶部,这显然是我不希望的。在Windows 10上运行jre1.8.0_66
布拉姆Vanroy

@布拉姆:是的,这是正确的。我在同一版本的Java和Windows上运行代码,但它并不总是总是位于其他窗口之上。可能不必总是始终放在最前面,但我认为,至少在某些情况下,Windows只会闪烁标题栏。
劳伦斯·多尔

嗯,很奇怪。您能看看我链接到该答案的类似问题吗?也许这代码显示更清晰的问题:stackoverflow.com/questions/34637597/...
布拉姆Vanroy

11

这是一种真正有效的方法(在Windows Vista上测试):D

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

fullscreen变量指示您是希望应用程序全屏运行还是在窗口中运行。

这不会使任务栏闪烁,而是将窗口可靠地移到前面。


感谢setExtendedState提示。我将它与toFront()和repaint()解决方案一起使用,即使窗口已最小化,也可以将窗口置于前景。

1
确认:此解决方案在WindowsXP中有效,使用toFront会导致任务栏中的消息闪烁。谢谢!
埃里克·林道厄

5

j,在Fedora KDE 14中,您的所有方法都不对我有用。

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)2015年

4

我测试了您的答案,只有Stefan Reich的答案对我有用。尽管我无法将窗口还原到以前的状态(最大化/正常)。我发现这种突变更好:

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

这是setState不是setExtendedState


3

我发现最简单的方法在各个平台之间没有不一致之处:

setVisible(false); setVisible(true);


1
引起一些闪烁,不是吗?不错,很简单:)
rogerdpack

不适用于我的后台进程。如果从前台进程调用,则第一次刷新时窗口也会变成白色。不能用于屏幕抓取。
DragonLord

可以通过检查窗口是否已图标化来避免闪烁
totaam 2014年

2

在Windows和Linux中,当您对JFrame .toFront()进行控制时,所发生的事情的规则是相同的:

->如果现有应用程序的窗口当前是焦点窗口,则焦点交换到请求的窗口->如果不是,则该窗口仅在任务栏中闪烁

但是:

->新窗口自动获得焦点

因此,让我们利用这个!您想把窗户放到前面,该怎么做?好 :

  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上不起作用,两个窗口都闪烁(如果我不隐藏第二个窗口)。
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);
            }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.