如何将我的应用程序带到前面?

Maw*_*awg 19 delphi delphi-xe2

我知道这是一个坏主意的所有原因.如果一个应用程序窃取输入焦点我不喜欢它,但这纯粹是个人使用,我希望它发生; 它不会打扰任何东西.

(对于好奇:我在NetBeans中运行单元测试,它生成一个日志文件.当我的后台应用程序看到日志文件的时间戳更改时,我希望它解析日志文件并转到前面显示结果).

这个问题没有帮助,也没有谷歌搜索.似乎BringToFront()长时间没有工作,我找不到任何替代方案.

有任何想法吗?

Ser*_*yuz 32

这是一个简单的东西似乎工作,测试了多个包含XP,Server2003,Vista,Server2008,W7的盒子.测试应用程序使用标准(或管理员)帐户运行,在前台写入时从记事本中窃取输入焦点.

var
  Input: TInput;
begin
  ZeroMemory(@Input, SizeOf(Input));
  SendInput(1, Input, SizeOf(Input)); // don't send anyting actually to another app..
  SetForegroundWindow(Handle);
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以进一步调整它以获得最小化的应用程序.

  • 谢谢!也适用于Windows 8.1. (2认同)

Ken*_*ite 17

你不能可靠地做到这一点.Windows XP有一个允许它的解决方法,但从那时起版本禁止它(见下面的注释).这在MSDN文档的备注部分中明确说明SetForegroundWindow:

系统限制哪些进程可以设置前景窗口.仅当满足下列条件之一时,进程才能设置前台窗口:

  • 该过程是前台过程.
  • 该过程由前台进程启动.
  • 该过程收到了最后一个输入事件.
  • 没有前台进程.
  • 正在调试前台进程.
  • 前景未锁定(请参阅LockSetForegroundWindow).
  • 前台锁定超时已到期(请参阅SystemParametersInfo中的SPI_GETFOREGROUNDLOCKTIMEOUT).
  • 没有菜单处于活动状态

当用户使用另一个窗口时,应用程序无法强制窗口到达前台.相反,Windows会闪烁窗口的任务栏按钮以通知用户.

请注意引用文档的最后一段,尤其是第一句.

这个问题

这纯粹是个人使用,我希望它发生; 它不会打扰任何东西.

是任何应用程序都可以尝试做同样的事情."纯粹个人使用"如何告诉您个人而不仅仅是任何申请?:-)

注意:当我单击帮助工具按钮时,我已经尝试了所有我能想到的将IDE的文档显示在前台,但我能得到的只是闪烁的任务栏按钮(我用户希望它这样做) .


who*_*ddy 12

我在我的一个应用程序中做了类似的事情,这个函数在xp/vista/w7中适用于我:

function ForceForegroundWindow(hwnd: THandle): Boolean;
const
  SPI_GETFOREGROUNDLOCKTIMEOUT = $2000;
  SPI_SETFOREGROUNDLOCKTIMEOUT = $2001;
var
  ForegroundThreadID: DWORD;
  ThisThreadID: DWORD;
  timeout: DWORD;
begin
  if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE);

  if GetForegroundWindow = hwnd then Result := True
  else
  begin
    // Windows 98/2000 doesn't want to foreground a window when some other
    // window has keyboard focus

    if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4)) or
      ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and
      ((Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and
      (Win32MinorVersion > 0)))) then
    begin
      Result := False;
      ForegroundThreadID := GetWindowThreadProcessID(GetForegroundWindow, nil);
      ThisThreadID := GetWindowThreadPRocessId(hwnd, nil);
      if AttachThreadInput(ThisThreadID, ForegroundThreadID, True) then
      begin
        BringWindowToTop(hwnd); // IE 5.5 related hack
        SetForegroundWindow(hwnd);
        AttachThreadInput(ThisThreadID, ForegroundThreadID, False);
        Result := (GetForegroundWindow = hwnd);
      end;
      if not Result then
      begin
        // Code by Daniel P. Stasinski
        SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @timeout, 0);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0),
          SPIF_SENDCHANGE);
        BringWindowToTop(hwnd); // IE 5.5 related hack
        SetForegroundWindow(hWnd);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(timeout), SPIF_SENDCHANGE);
      end;
    end
    else
    begin
      BringWindowToTop(hwnd); // IE 5.5 related hack
      SetForegroundWindow(hwnd);
    end;

    Result := (GetForegroundWindow = hwnd);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是不要窃取焦点,只是将窗口TOPMOST放在z缓冲区中:

procedure ForceForegroundNoActivate(hWnd : THandle);

begin
 if IsIconic(Application.Handle) then
  ShowWindow(Application.Handle, SW_SHOWNOACTIVATE);
 SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE);
 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE);
end;
Run Code Online (Sandbox Code Playgroud)

  • @KenWhite,此功能用于最终用户应用程序,它们混合使用XP和W7(UAC ON),我在受限制的环境中没有遇到任何问题 (2认同)
  • 另外,`SystemParametersInfo()`的第三个参数是`Pointer`,因此代码应该使用`nil`而不是`TObject(0)`. (2认同)

Edi*_*ičs 6

function WinActivate(const AWinTitle: string): boolean;
var
  _WindowHandle: HWND;
begin
  Result := false;
  _WindowHandle := FindWindow(nil, PWideChar(AWinTitle));
  if _WindowHandle <> 0 then
  begin
    if IsIconic(_WindowHandle) then
      Result := ShowWindow(_WindowHandle, SW_RESTORE)
    else
      Result := SetForegroundWindow(_WindowHandle);
  end;
end;

if WinActivate(self.Caption) then
  ShowMessage('This works for me in Windows 10');
Run Code Online (Sandbox Code Playgroud)


Who*_*ome 5

即使在 Windows7+8 操作系统中,这也应该有效。唯一的要求是应用程序本身可以调用函数。使用外部应用程序设置另一个进程的窗口前端比较棘手。

Application.Restore; // unminimize window, makes no harm always call it
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE);
SetWindowPos(self.Handle, HWND_TOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE);
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE);
Run Code Online (Sandbox Code Playgroud)

编辑好的,我发现了一个问题。应用程序被置于最前面,但焦点仍保留在原始应用程序中。使用此答案来解决问题,它的方法非常复杂,但复制粘贴可以解决问题。在调用 ForceForegroundWindow(wnd) 之前,您可能必须调用 Application.Restore 来取消最小化窗口。 /sf/answers/411972291/


Tob*_*oby 5

假设没有其他 StayOnTop 应用程序在运行,您可以暂时将表单 FormStyle 设置为 fsStayOnTop,然后执行应用程序还原和BringToFront,然后将表单样式更改回原来的样子。

tmpFormStyle := Application.MainForm.FormStyle;
Application.MainForm.FormStyle := fsStayOnTop;
Application.Restore; // optional
Application.BringToFront;
Application.MainForm.FormStyle := tmpFormStyle;
Run Code Online (Sandbox Code Playgroud)

同样,这仅在没有其他stayontop 应用程序时才有效。