简体   繁体   English

如何将窗户拉到前面?

[英]How to bring a window to the front?

We have a Java application that needs to be brought to the foreground when a telecontrol mechanism activates something in the application. 当远程控制机制激活应用程序中的某些内容时,我们需要将Java应用程序带到前台。

In order to get this, we have realized in the called method of the class which represents the frame of our application (extension of a JFrame ) following implementation: 为了得到这个,我们在类的被调用方法中实现了代表我们的应用程序的框架( JFrame扩展)在实现之后:

setVisible(true);
toFront();

Under Windows XP, this works the first time it is called, on the second time only the tab in the taskbar flashes, the frame doesn't come to the front anymore. 在Windows XP下,这在第一次调用时工作,第二次只有任务栏中的选项卡闪烁,框架不再出现在前面。 Same goes for Win2k. Win2k也是如此。 On Vista it seems to work fine. 在Vista上似乎工作正常。

Do you have any ideas? 你有什么想法?

A possible solution is: 可能的解决方案是:

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

I had the same problem with bringing a JFrame to the front under Ubuntu (Java 1.6.0_10). 在Ubuntu(Java 1.6.0_10)下将JFrame引入前端时遇到了同样的问题。 And the only way I could resolve it is by providing a WindowListener . 我能解决它的唯一方法是提供一个WindowListener Specifically, I had to set my JFrame to always stay on top whenever toFront() is invoked, and provide windowDeactivated event handler to setAlwaysOnTop(false) . 具体来说,每当调用toFront()时,我必须将我的JFrame设置为始终保持在顶部,并为setAlwaysOnTop(false)提供windowDeactivated事件处理程序。


So, here is the code that could be placed into a base JFrame , which is used to derive all application frames. 因此,这里是可以放入基础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);
}

Whenever your frame should be displayed or brought to front call frame.setVisible(true) . 每当你的框架应该显示或带到前面调用frame.setVisible(true)

Since I moved to Ubuntu 9.04 there seems to be no need in having a WindowListener for invoking super.setAlwaysOnTop(false) -- as can be observed; 由于我转移到Ubuntu 9.04,似乎没有必要使用WindowListener来调用super.setAlwaysOnTop(false) - 可以观察到; this code was moved to the methods toFront() and setVisible() . 此代码已移至方法toFront()setVisible()

Please note that method setVisible() should always be invoked on EDT. 请注意,应始终在EDT上调用方法setVisible()

Windows has the facility to prevent windows from stealing focus; Windows具有防止窗口窃取焦点的功能; instead it flashes the taskbar icon. 相反,它会闪烁任务栏图标。 In XP it's on by default (the only place I've seen to change it is using TweakUI, but there is a registry setting somewhere). 在XP中它默认是打开的(我看到改变它的唯一地方是使用TweakUI,但在某处有一个注册表设置)。 In Vista they may have changed the default and/or exposed it as a user accessible setting with the out-of-the-box UI. 在Vista中,他们可能已经更改了默认值和/或将其作为用户可访问的设置暴露在开箱即用的UI中。

Preventing windows from forcing themselves to the front and taking focus is a feature since Windows 2K (and I, for one, am thankful for it). 从Windows 2K开始,防止窗户强迫自己到前方并获得焦点是一个特征(而且我,我很感激它)。

That said, I have a little Java app I use to remind me to record my activities while working, and it makes itself the active window every 30 minutes (configurable, of course). 也就是说,我有一个小的Java应用程序,用来提醒我在工作时记录我的活动,它每30分钟就会成为活动窗口(当然可以配置)。 It always works consistently under Windows XP and never flashes the title bar window. 它始终在Windows XP下始终如一,并且永远不会闪烁标题栏窗口。 It uses the following code, called in the UI thread as a result of a timer event firing: 它使用以下代码,作为计时器事件触发的结果在UI线程中调用:

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

(the first line restores if minimized... actually it would restore it if maximized too, but I never have it so). (如果最小化,第一行恢复......实际上如果最大化也会恢复它,但我从来没有这样做)。

While I usually have this app minimized, quite often it's simply behind my text editor. 虽然我通常将这个应用程序最小化,但通常它只是在我的文本编辑器后面。 And, like I said, it always works. 并且,就像我说的,它总是有效的。

I do have an idea on what your problem could be - perhaps you have a race condition with the setVisible() call. 我确实知道你的问题可能是什么 - 也许你有一个setVisible()调用的竞争条件。 toFront() may not be valid unless the window is actually displayed when it is called; 除非在调用窗口时实际显示窗口,否则toFront()可能无效; I have had this problem with requestFocus() before. 我之前遇到过requestFocus()这个问题。 You may need to put the toFront() call in a UI listener on a window activated event. 您可能需要在窗口激活事件的UI侦听器中放置toFront()调用。

2014-09-07: At some point in time the above code stopped working, perhaps at Java 6 or 7. After some investigation and experimentation I had to update the code to override the window's toFront method do this (in conjunction with modified code from what is above): 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);
}

As of Java 8_20, this code seems to be working fine. 从Java 8_20开始,这段代码似乎运行正常。

Here's a method that REALLY works (tested on Windows Vista) :D 这是一种真正有效的方法(在Windows Vista上测试):D

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

The fullscreen variable indicates if you want the app to run full screen or windowed. 全屏变量指示您是希望应用程序全屏运行还是窗口运行。

This does not flash the task bar, but bring the window to front reliably. 这不会闪烁任务栏,但可以将窗口可靠地拉到前面。

Hj, all methods of yours are not working for me, in Fedora KDE 14. I have a dirty way to do bring a window to front, while we're waiting for Oracle to fix this issue. 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);
      }
    }
  }

  //...

}

And, this works perfectly in my Fedora KDE 14 :-) 并且,这在我的Fedora KDE 14中完美运行:-)

This simple method worked for me perfectly in Windows 7: 这个简单的方法在Windows 7中完美适用于我:

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

I tested your answers and only Stefan Reich's one worked for me. 我测试了你的答案,只有Stefan Reich的一个为我工作。 Although I couldn't manage to restore the window to its previous state (maximized/normal). 虽然我无法将窗口恢复到以前的状态(最大化/正常)。 I found this mutation better: 我发现这个突变更好:

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

That is setState instead of setExtendedState . 这是setState而不是setExtendedState

Simplest way I've found that doesn't have inconsistency across platforms: 最简单的方法我发现跨平台没有不一致性:

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

The rules governing what happens when you .toFront() a JFrame are the same in windows and in linux : 管理.toFront()JFrame时发生的事情的规则在windows和linux中是相同的:

-> if a window of the existing application is currently the focused window, then focus swaps to the requested window -> if not, the window merely flashes in the taskbar - >如果现有应用程序的窗口当前是焦点窗口,则焦点交换到请求的窗口 - >如果没有,窗口只会在任务栏中闪烁

BUT : 但是:

-> new windows automatically get focus - >新窗口自动获得焦点

So let's exploit this ! 所以让我们利用这个! You want to bring a window to the front, how to do it ? 你想给前面带一个窗口,怎么做? Well : 好 :

  1. Create an empty non-purpose window 创建一个空的非用途窗口
  2. Show it 展示下
  3. Wait for it to show up on screen (setVisible does that) 等待它出现在屏幕上(setVisible这样做)
  4. When shown, request focus for the window you actually want to bring the focus to 显示时,请求您实际想要将焦点带到的窗口的焦点
  5. hide the empty window, destroy it 隐藏空窗口,摧毁它

Or, in java code : 或者,在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);
  }
});

To avoid the window losing focus when its returning to visible after being hidden all that is needed is: 为了避免窗口在被隐藏后返回可见时失去焦点所需要的是:

setExtendedState(JFrame.NORMAL);

Like so: 像这样:

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

There are numerous caveats in the javadoc for the toFront() method which may be causing your problem. 对于toFront()方法,javadoc中有许多警告可能会导致您的问题。

But I'll take a guess anyway, when "only the tab in the taskbar flashes", has the application been minimized? 但无论如何,当“只有任务栏中的选项卡闪烁”时,我会猜测应用程序是否已最小化? If so the following line from the javadoc may apply: 如果是这样,javadoc的以下行可能适用:

"If this Window is visible, brings this Window to the front and may make it the focused Window." “如果此窗口可见,则将此窗口置于前面,并使其成为焦点窗口。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM