如何把窗户摆在前面?
当遥控机制激活应用程序中的某些内容时,我们有一个Java应用程序需要被带到前台。
为了得到这个,我们已经在被调用的Class方法中实现了,它代表了我们的应用框架(JFrame的扩展)在实现之后:
setVisible(true); toFront();
在Windows XP下,第一次调用它时,第二次只有任务栏中的选项卡闪烁,框架不再出现在前面。 Win2k也一样。 在Vista上它似乎工作正常。
任何想法?
可能的解决scheme是:
java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { myFrame.toFront(); myFrame.repaint(); } });
我在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上调用。
Windows有防止窗口窃取焦点的function; 而是它闪烁任务栏图标。 在XP中,它默认情况下(唯一的地方,我已经看到改变它使用TweakUI,但有一个registry设置的地方)。 在Vista中,它们可能已经改变了默认设置,并且/或者将其作为用户可访问的设置用开箱即用的UI来暴露。
自Windows 2K(和我,其中一个,我非常感谢它),防止Windows强迫自己的前面,并采取了重点是一个function。
也就是说,我有一个小的Java应用程序,用于提醒我在工作时logging自己的活动,并且每隔30分钟将自己变成活动窗口(当然是可configuration的)。 它始终在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开始,这段代码似乎工作正常。
这是一个真正有效的方法(在Windows Vista上testing):D
frame.setExtendedState(JFrame.ICONIFIED); frame.setExtendedState(fullscreen ? JFrame.MAXIMIZED_BOTH : JFrame.NORMAL);
全屏variables指示您是否希望应用程序运行全屏或窗口。
这不会使任务栏闪烁,而是使窗口可靠地前移。
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中完美工作:-)
这个简单的方法在Windows 7中完美的工作:
private void BringToFront() { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { if(jFrame != null) { jFrame.toFront(); jFrame.repaint(); } } }); }
我testing了你的答案,只有Stefan Reich的一个人为我工作。 虽然我无法设法恢复到以前的状态(最大化/正常)的窗口。 我发现这个变异更好:
view.setState(java.awt.Frame.ICONIFIED); view.setState(java.awt.Frame.NORMAL);
这是setState
而不是setExtendedState
。
最简单的方法,我发现跨平台没有不一致:
调用setVisible(假); 调用setVisible(真);
规则pipe理当你.toFront()一个JFrame在Windows和Linux中是相同的:
– >如果现有应用程序的窗口当前是焦点窗口,则焦点交换到所请求的窗口 – >否则,窗口仅在任务栏中闪烁
但是:
– >新的窗口自动获得焦点
所以我们来利用这个! 你想把窗户带到前面,怎么做? 好 :
- 创build一个空的非目的窗口
- 展示下
- 等待它显示在屏幕上(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); } });
toFront()方法的javadoc中有许多警告 ,可能会导致您的问题。
但是,无论如何,当“只有任务栏中的标签闪烁”时,我会猜测,应用程序是否已经最小化? 如果是这样的话,那么可以使用javadoc中的以下行:
“如果这个窗口是可见的,把这个窗口放在前面,可以使它成为聚焦的窗口。
为了避免窗口在被隐藏后返回可见状态而失去焦点,所有需要的是:
setExtendedState(JFrame.NORMAL);
像这样:
defaultItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { showWindow(); setExtendedState(JFrame.NORMAL); } });