如何将窗户带到前面?

Posted

技术标签:

【中文标题】如何将窗户带到前面?【英文标题】:How to bring a window to the front? 【发布时间】:2010-09-23 11:13:45 【问题描述】:

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

为了实现这一点,我们在代表我们应用程序框架的类的被调用方法中实现了以下实现(JFrame 的扩展):

setVisible(true);
toFront();

在 Windows XP 下,第一次调用它可以工作,第二次只有任务栏中的选项卡闪烁,框架不再出现在前面。 Win2k 也一样。在 Vista 上它似乎工作正常。

你有什么想法吗?

【问题讨论】:

你有这种行为的样本吗? 正确的答案是使用 invokeLater 在 EDT 上调用 toFront()。下面包含一个简单的答案,但这不是公认的答案。不过,它确实有效。完美。 我知道这是旧的,但这也发生在 OSX 上 我遇到了这个问题,但下面的答案似乎都没有解决它。我确定这是由于窗口不允许我为应用程序中的第一个窗口“窃取”焦点造成的。 【参考方案1】:

一个可能的解决方案是:

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

【讨论】:

也许应该首先启动invokeLater中的所有UI代码? ;) 在 KDE 4.9.5 上的 Java 7 中对我不起作用,该窗口仍会隐藏在其他程序下方。帮助我的是改变将窗户放在前面的顺序。不要隐藏一个窗口并显示第二个窗口,而是显示第二个窗口然后隐藏第一个窗口(JFrame)。 适用于在小程序中运行 Java 1.8 的 Windows 10 逆向方法是什么?【参考方案2】:

我在 Ubuntu (Java 1.6.0_10) 下将 JFrame 放在前面时遇到了同样的问题。我可以解决它的唯一方法是提供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 上调用。

【讨论】:

谢谢!同样相关的是这个问题:***.com/questions/2315560/… 由于 setDisposed() 方法,我无法编译它。找不到。 @ka3ak 这是一个受保护的设置器,可以在建议的 JFrame 基类中引入,以便跟踪处理框架的情况。需要调用 setDisposed(true) 来覆盖方法 dispose()。严格来说,这并不是每个人都需要的。 .setAlwaysOnTop(true); 是使用 JWindow 时唯一对我有用的。 setAlwaysOnTop(true) 是我让它在 Windows 10 下运行的唯一方法 - 谢谢!【参考方案3】:

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

自 Windows 2K 以来,防止窗口将自己强制放在前面并获得焦点是一项功能(我对此表示感谢)。

也就是说,我有一个小 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 中。经过一些调查和实验后,我不得不更新代码以覆盖窗口的 @ 987654323@ 方法这样做(结合上面的修改代码):

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 支持不允许窗口窃取焦点。我讨厌在我输入文档时发生这种情况。 我完全同意你不要窃取焦点,但在这种精确的情况下,用户希望应用程序出现在前面。但是更改注册表设置并更改完整的 Windows 行为会很不酷。 我猜super.setAlwaysOnTop(false); 是为了使窗口不总是在顶部,这是摆脱我们之前设置的true 所必需的前面的窗户,对吗?我问是因为使用您的代码,在我的情况下,窗口仍然始终位于顶部,这显然是我不想要的。在 Windows 10 上运行 jre1.8.0_66。 @Bram:是的,没错。我在相同版本的 Java 和 Windows 上运行代码,它并不总是在其他窗口之上。可能没有必要总是设置在最前面,但我认为否则 Windows 只会闪烁标题栏,至少在某些情况下是这样。 嗯,奇怪。你能看一下我链接到这个答案的类似问题吗?也许该代码更清楚地显示了问题:***.com/questions/34637597/…【参考方案4】:

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

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

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

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

【讨论】:

感谢 setExtendedState 提示。我将它与 toFront() 和 repaint() 解决方案一起使用,以将窗口置于前台,即使它已被最小化。 已确认:此解决方案适用于 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 中完美运行 :-)

【讨论】:

有点hacky,对我们有用,但只适用于第一次调用:-)。 (Kubuntu 12.04) - 其他解决方案确实失败了 这是唯一适用于我 (Windows Server 2012 R2) 的解决方案,用于解决 JFrame(登录)已打开但在用户单击它之前没有焦点的问题。【参考方案6】:

我测试了你的答案,只有 Stefan Reich's one 为我工作。虽然我无法将窗口恢复到以前的状态(最大化/正常)。我发现这个突变更好:

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

那是setState 而不是setExtendedState

【讨论】:

【参考方案7】:

这个简单的方法在 Windows 7 中非常适合我:

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

【讨论】:

repaint() 不是必需的,invokeLater() 做到了。谢谢。【参考方案8】:

我发现跨平台没有不一致的最简单方法:

setVisible(假); setVisible(true);

【讨论】:

会导致一些闪烁,不是吗?不过很好很简单:) 不适用于我的后台进程。如果从前台进程调用,窗口也会在第一次刷新时出现白色。不能用于屏幕抓取。 可以通过检查窗口是否图标化来避免闪烁【参考方案9】:

当你 .toFront() 一个 JFrame 时发生的规则在 windows 和 linux 中是相同的:

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

但是:

-> 新窗口自动获得焦点

所以让我们利用它!你想把一个窗口带到前面,怎么做?嗯:

    创建一个空的非用途窗口 显示它 等待它出现在屏幕上(setVisible 会这样做) 显示时,为您实际希望将焦点带到的窗口请求焦点 隐藏空窗口,销毁它

或者,在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 上不起作用,两个窗口都闪烁(如果我不隐藏第二个)。 创意。覆盖时不适用于我在 Win7 上的后台进程。新框架没有出现在顶部。较旧的 JDK 6u21。【参考方案10】:

为避免窗口在隐藏后返回可见时失去焦点,只需:

setExtendedState(JFrame.NORMAL);

像这样:

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

【讨论】:

【参考方案11】:

在 toFront() 方法的 javadoc 中有许多 caveats 可能会导致您的问题。

不过我还是猜一猜,当“只有任务栏中的选项卡闪烁”时,应用程序是否被最小化了?如果是这样,javadoc 中的以下行可能适用:

“如果此窗口可见,则将此窗口置于最前面并可能使其成为焦点窗口。”

【讨论】:

以上是关于如何将窗户带到前面?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 NSWindow 带到前面和当前空间?

JavaFX 如何将对话框/警报带到屏幕前面

如何将停靠在选项卡中的 CDockablePane 带到前面

如何将 SKSpriteNode 放在前面?

如何在swift 4中将表格视图控制器前面的按钮带到? [重复]

如何将 PyQt QProcess 窗口置于前面?