如何将窗户拉到前面?

时间:2008-11-21 15:00:40

标签: java windows swing awt

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

为了得到这个,我们已经在类的被调用方法中实现了代表我们的应用程序的框架(JFrame的扩展)在实现之后:

setVisible(true);
toFront();

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

你有什么想法吗?

11 个答案:

答案 0 :(得分:67)

可能的解决方案是:

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

答案 1 :(得分:33)

在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()

请注意,应始终在EDT上调用方法setVisible()

答案 2 :(得分:21)

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

自从Windows 2K以来,防止窗户强迫自己到前方并获得焦点是一个功能(而我,我很感激它)。

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

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

(如果最小化,第一行恢复......实际上如果最大化也会恢复它,但我从来没有这样做。)

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

我确实知道你的问题可能是什么 - 也许你有一个setVisible()调用的竞争条件。除非在调用窗口时实际显示窗口,否则toFront()可能无效;我之前遇到过requestFocus()这个问题。您可能需要在窗口激活事件的UI侦听器中放置toFront()调用。

2014-09-07:在某个时间点,上述代码停止工作,可能是在Java 6或7中。经过一些调查和实验,我不得不更新代码以覆盖窗口{ {1}}方法执行此操作(结合上述修改后的代码):

toFront

从Java 8_20开始,这段代码似乎运行正常。

答案 3 :(得分:11)

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

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

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

这不会使任务栏闪烁,但可以可靠地将窗口置于前方。

答案 4 :(得分: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中完美运行: - )

答案 5 :(得分:4)

这种简单的方法在Windows 7中完全适用于我:

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

答案 6 :(得分:3)

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

调用setVisible(假); 调用setVisible(真);

答案 7 :(得分:3)

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

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

这是setState而不是setExtendedState

答案 8 :(得分:2)

管理.toFront()JFrame时发生的事情的规则在windows和linux中是相同的:

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

但是:

- >新窗口自动获得焦点

所以让我们利用这个!你想给前面带一个窗口,怎么做?好吧:

  1. 创建一个空的非用途窗口
  2. 显示
  3. 等待它出现在屏幕上(setVisible就是这样)
  4. 显示时,请求您实际想要将焦点带到
  5. 的窗口的焦点
  6. 隐藏空窗口,将其销毁
  7. 或者,在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);
      }
    });
    

答案 9 :(得分:0)

在forFront()方法的javadoc中有很多caveats,这可能会导致您的问题。

但无论如何,当“只有任务栏中的选项卡闪烁”时,我会猜测,应用程序是否已最小化?如果是这样,javadoc中的以下行可能适用:

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

答案 10 :(得分:0)

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

setExtendedState(JFrame.NORMAL);

像这样:

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