如何强制一个Java SWT程序"将自己移动到前台"?

16

目前使用swt,我有时希望程序可以任意将窗口提到前台(就像闹钟那样)。

通常以下方法是有效的(jruby):

@shell.setMinimized(false)
@shell.forceActive

如果窗口是被最小化的,这段代码会将其恢复到前台。

在任何时候创建新的窗口也会将其(新窗口)调至前台。

到目前为止一切都好,然而,如果窗口没有被最小化,上述代码只会在任务栏中闪烁应用程序的图标。实际上,第一次运行它会将其带到前台。之后,它只会在任务栏中闪烁。这是Windows系统。在Linux系统上,它似乎只会在任务栏中闪烁(Ubuntu默认)。

有人知道在Swt中有跨平台的方法可以让应用程序到前台吗?

看起来没有任何明确的方法可以通过使用forceActive、setActive、setMinimized(false)、setFocus、forceFocus和setVisible来完成这项工作。

我非常确定这是可能的(至少在Windows中),因为E Text Editor可以做到这一点。好吧,那不是Swt,但至少已知有其他一些应用程序可以做到

我在想,也许这就是Swt bug 192036

非常感谢。

相关:


看起来你链接的 SWT bug 完全 描述了你的问题,而且听起来他们无法修复它。 - Mike Daniels
我认为这确实是Windows的问题 - 发现得好。暂时的解决方法是先最小化一个shell,然后取消最小化它(或使用一些本地代码[通过ffi或jni]来forceForeGround它)。在Linux中,我不太确定问题是什么(只是在任务托盘中闪烁)。它可能在新版本的swt.jar >= 3.5中得到修复。https://bugs.eclipse.org/bugs/show_bug.cgi?id=244597 - rogerdpack
6个回答

6
这对我在Windows 7和Ubuntu上都有效:
private void bringToFront(final Shell shell) {
    shell.getDisplay().asyncExec(new Runnable() {
        public void run() {
            shell.forceActive();
        }
    });
}

6

这里展示了我在Windows下是如何做到的(使用ffi)。

一些有用的技巧:

在BringToFront.SetForegroundWindow(wanted)调用之后添加'sleep 0.1'(希望这个并不是真正必要的)。

在将窗口置于前景后,再添加shell.set_active。由于某种原因,forceActive不会调用setActive。

注意,setActive会进行user32.dll BringWindowToTop调用,并且需要在分离线程输入之前完成。

还要注意,如果您能按正确的顺序进行调用,您可能根本不需要使用线程输入hack (?)。

此处包含了如何正确执行此操作的几个好提示。

在Linux上,forceActive确实有效——但只有在您移动到其他几个窗口之前,然后就会在任务栏中闪烁(仅限于此)。猜测是swt的错误。

还有相关内容:

如何将窗口置于前景?

http://github.com/jarmo/win32screenshot/blob/master/lib/win32/screenshot/bitmap_maker.rb#L110 "set_foreground",似乎可以与xp和Windows 7通用。

[1] 需要将应用程序置于前景https://bugs.eclipse.org/bugs/show_bug.cgi?id=303710


4
这实际上是 Windows 的一个功能,可以通过 Tweak UI 工具(至少适用于 Windows XP)启用。启用后,操作系统会有意阻止窗口强制成为焦点窗口,以防止其“窃取焦点”。因此,抢占焦点的操作被改为仅闪烁任务栏图标——由于操作系统正在按用户请求故意转换操作,因此您无法做任何事情(这是一件好事)。
这可能是因为如此之多的应用程序滥用了置顶 API 和行为,这种行为既让用户感到恼火,又导致他们输入到错误的应用程序中。

如果你在谷歌上搜索forceForeGround,你会看到一个解决方法,好或坏都有可能(我猜这就是awt用于其toFront方法的方法,而swt似乎没有)。我同意应该谨慎使用forceActive :) - rogerdpack
1
是的,仍然有太多的应用程序会从后台弹出,窃取您在忙于输入其他内容时的输入。我以前就经历过数据丢失的情况。当我正在输入包含"Yes"选择器的其他东西时,后台应用程序会弹出“您是否要删除blah?”的提示。啊。 - Brian Knoblauch

3

Bug 192036 - Shell.forceActive doesn't raise a window above all other windows

@rogerdpack's 询问在Eclipse bug跟踪器上得到了回复,并给出以下简单方法达到我们需要的效果。

public void forceActive(Shell shell) {
    int hFrom = OS.GetForegroundWindow();

    if (hFrom <= 0) {
      OS.SetForegroundWindow(shell.handle);
      return;
    }

    if (shell.handle == hFrom) {
      return;
    }

    int pid = OS.GetWindowThreadProcessId(hFrom, null);
    int _threadid = OS.GetWindowThreadProcessId(shell.handle, null);

    if (_threadid == pid) {
      OS.SetForegroundWindow(shell.handle);
      return;
    }

    if (pid > 0) {
      if ( !OS.AttachThreadInput(_threadid, pid, true)) {
        return;
      }
      OS.SetForegroundWindow(shell.handle);
      OS.AttachThreadInput(_threadid, pid, false);
    }

    OS.BringWindowToTop(shell.handle);
    OS.UpdateWindow(shell.handle);
    OS.SetActiveWindow(shell.handle);
  }

不幸的是,这种解决方法在我的 Windows 10 版本上不起作用。 - stippi

2
private static void onTop(Shell shell) {
        int s = -1;
        Shell[] shells = display.getShells();
        for (int i = 0; i < shells.length; ++i) {
            if (!shells[i].equals(shell)) {
                shells[i].setEnabled(false);
                shells[i].update();
            } else {
                s = i;
            }
        }
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        for (int i = 0; i < shells.length; ++i) {
            if (i != s) {
                shells[i].setEnabled(true);
                shells[i].update();
            }
        }
    }

1

有一种方法可以使你最初尝试的东西工作。你实际上需要调用 shell.setMinimized(false),然后在此之后调用 shell.setActive() 来恢复 shell 的先前状态。但是,这仅在 shell 确实处于最小化状态时才起作用。因此,这是我的最终解决方案,如果 shell 还没有被最小化,则人为地将其最小化。代价是如果必须进行最小化,会有一个快速的动画。

shell.getDisplay().syncExec(new Runnable() {

    @Override
    public void run() {
        if (!shell.getMinimized())
        {
            shell.setMinimized(true);
        }
        shell.setMinimized(false);
        shell.setActive();
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接