【问题标题】:Windows 7: how to bring a window to the front no matter what other window has focus?Windows 7:无论其他哪个窗口有焦点,如何将一个窗口放在前面?
【发布时间】:2011-09-12 20:20:06
【问题描述】:

我正在实现一个任务栏替换,类似于停靠栏的应用程序切换器样式程序。它使用 OpenGL 和键盘快捷键做一些独特的事情,所以它的设置方式,窗口并不总是有焦点。我想实现它,以便我可以将任意窗口带到前台,就像任务栏或 ALT-TAB 程序一样。

但是,我的代码只是使应用程序图标在任务栏中闪烁。 Windows API 文档说这是应该发生的,但我正在寻找解决此问题的方法。

我根据以下示例调整了我的代码,这些示例表明附加到前台线程应该允许您设置前台窗口。以下是网站:

http://www.voidnish.com/Articles/ShowArticle.aspx?code=dlgboxtricks

http://invers2008.blogspot.com/2008/10/mfc-how-to-steal-focus-on-2kxp.html

我的代码如下所示。请注意,它使用的是 python 的 win32 包装器(self.hwnd 是我要放在前面的窗口的句柄):

fgwin = win32gui.GetForegroundWindow()
fg = win32process.GetWindowThreadProcessId(fgwin)[0]
current = win32api.GetCurrentThreadId()
if current != fg:
    win32process.AttachThreadInput(fg, current, True)
    win32gui.SetForegroundWindow(self.hwnd)
    win32process.AttachThreadInput(fg, win32api.GetCurrentThreadId(), False)

但是,除非我的窗口是前台窗口(通常不是),否则只会导致程序的图标闪烁。

我的线程连接错误吗?还有其他方法可以解决这个问题吗?我认为一定有,因为那里有很多应用程序切换器似乎能够很好地做到这一点。

我正在用 python 编写这个,但如果有其他语言的解决方案,我将使用包装器或做任何必要的事情来启动和运行它。

提前致谢!

编辑:我愿意接受一种让它只在我的特定计算机上工作的方法,即一种在我的机器上启用任何应用程序集中注意力的方法。

【问题讨论】:

  • 好的,但是有很多应用程序可以做到这一点。这显然是可能的,我发现教程告诉我如何。我的问题是,我在做什么导致教程中的代码不起作用?
  • 这就是我所做的。我发布的代码几乎是教程中的确切代码,在 python 包装器中(在我发布的两个链接中亲自查看)。我在问是否有人能说出为什么我的代码没有按照页面所说的那样做,或者是否有更好的方法来做到这一点。
  • 我实际上是在重写任务栏,使该指南完全不足。无论如何,解决方案已在上面发布,它是一行代码,因此 Windows API 显然不会阻止您这样做。
  • @David 有合法的用例。例如,如果您想在用户双击某个链接时将焦点从您的应用程序传递到另一个应用程序。如果您重新打开“其他”应用程序,那么它将获得焦点,但如果它已经在运行并且您不想启动新进程,则只需将旧进程放在前面。但是,我不会更改用户计算机上的设置。 nspire 的回答很完美

标签: python windows winapi mfc


【解决方案1】:

我不喜欢这些使用win32gui 的建议,因为您无法通过pip 轻松安装它。所以这是我的解决方案:

首先,通过pip 安装pywinauto。如果您使用的是 Python 2.7.9 或 2 分支的更新版本,或者 Python 3.4.0 或 3 分支的更新版本,则已安装 pip。对于其他所有人,请更新 Python 以获取它(或者,如果您必须运行旧版本的 Python,您可以通过运行 this script 手动下载并安装它。)

只需从命令行运行(而不是在 Python 中):

pip install pywinauto

接下来,从pywinauto导入你需要的东西:

from pywinauto.findwindows    import find_window
from pywinauto.win32functions import SetForegroundWindow

最后,它只是一个实际的行:

SetForegroundWindow(find_window(title='taskeng.exe'))

【讨论】:

  • python 3.6 on windows throws: ImportError: cannot import name 'SetForegroundWindow ,fixed with from win32gui import SetForegroundWindow
  • @PedroLobito - 我明确表示不要使用 win32gui - 我的解决方案说要使用 pywinauto。你应该已经导入了SetForegroundWindowfrom pywinauto.win32functions
  • 事实上,您的答案在 python 3.6 上不起作用。 pywinauto 很大程度上基于 win32gui,没有它就无法正常加载,所以我看不出不使用它的意义。
【解决方案2】:

我的一些代码已经运行了多年,一直追溯到 Windows 95。双击应用程序系统托盘图标时,我总是使用 Win32 API 函数,例如 BringWindowToTop 和 SetForegroundWindow 将我的应用程序窗口带到前景。这一切都停止在 Windows 7 上按预期工作,我的输入窗口最终将位于其他窗口之后,并且窗口图标将在状态栏上闪烁。我想出的“解决方法”是这样的;它似乎适用于所有版本的 Windows。

//-- show the window as you normally would, and bring window to foreground.
//   for example;
::ShowWindow(hWnd,SW_SHOW); 
::BringWindowToTop(hWnd);
::SetForegroundWindow(hWnd);

//-- on Windows 7, this workaround brings window to top
::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);

【讨论】:

  • 它把它带到顶部,但键盘焦点不在我们的顶部窗口中。
【解决方案3】:

根据 nspire 的说法,我已经用 python 2.7 和 W8 尝试过他的解决方案,它就像一个魅力,即使窗口被最小化 *.

win32gui.ShowWindow(HWND, win32con.SW_RESTORE)
win32gui.SetWindowPos(HWND,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)  
win32gui.SetWindowPos(HWND,win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)  
win32gui.SetWindowPos(HWND,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_SHOWWINDOW + win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
  • 原来是如果窗口没有被最小化,但是感谢Whome的评论win32gui.ShowWindow(HWND, win32con.SW_RESTORE),它现在适用于所有情况。

【讨论】:

  • 您必须在调用 SetWindowPos 函数之前恢复窗口。 Delphi 应用程序可以使用“Application.Restore;”函数来最小化。寻找 ShowWindow(handle, SW_RESTORE) python 调用。每次调用它都不会造成伤害,即使窗口已经显示。
【解决方案4】:

如果您要实现热键,请使用RegisterHotKey。正如 Raymond Chen 所说(克里斯已经链接的博客文章的配套文章),"Pressing a registered hotkey gives you the foreground activation love"

【讨论】:

  • 这很酷,但不能完美运行。就像用户在 Win10 中右键单击 Windows 任务栏一样。 SystemParametersInfo 的 @jmite 解决方案有效。
【解决方案5】:

SetForegroundWindow 函数的文档解释说,这实际上是预期的行为;流程不应该能够“窃取”焦点。但是,可以调整您的代码以使其正常工作。

看看LockSetForegroundWindow的备注部分:它解释了

如果用户按下 ALT 键[..],系统会自动启用对 SetForegroundWindow 的调用

您可以通过使用SendInput 函数让您的程序在调用SetForegroundWindow 之前模拟按下Alt 键来利用此行为。

【讨论】:

    【解决方案6】:

    迟到的答案,但您可以使用:

    import win32gui
    hwnd = win32gui.FindWindowEx(0,0,0, "Window Title")
    win32gui.SetForegroundWindow(hwnd)
    

    【讨论】:

    • 没那么晚,只有9年:P
    【解决方案7】:

    这就是我的工作方式:

    import win32gui
    from win32con import (SW_SHOW, SW_RESTORE)
    
    def get_windows_placement(window_id):
        return win32gui.GetWindowPlacement(window_id)[1]
    
    def set_active_window(window_id):
        if get_windows_placement(window_id) == 2:
            win32gui.ShowWindow(window_id, SW_RESTORE)
        else:
            win32gui.ShowWindow(window_id, SW_SHOW)
        win32gui.SetForegroundWindow(window_id)
        win32gui.SetActiveWindow(window_id)
    

    【讨论】:

    • 像魅力一样工作。 (2019/08) 并且键盘处于活动状态
    【解决方案8】:

    我在上面看到了一些很棒的答案,但需要额外的功能,其中窗口名称将是一个更灵活的参数。失败时返回 false:

    from win32gui import IsWindowVisible, GetWindowText, EnumWindows,\
    ShowWindow, SetForegroundWindow, SystemParametersInfo
    
    #Sub-Functions
    def window_enum_handler(hwnd, resultList):
        if IsWindowVisible(hwnd) and GetWindowText(hwnd) != '':
            resultList.append((hwnd, GetWindowText(hwnd)))
    
    #Prime-Functions
    def winFocus(partial_window_name):
        SystemParametersInfo(8193, 0, 2 | 1)
        handles=[]
        EnumWindows(window_enum_handler, handles)
        for i in handles:
            if str(partial_window_name).upper() in str(i[1]).upper():
                ShowWindow(i[0], 3)
                SetForegroundWindow(i[0])
                return True
        print(partial_window_name + " was not found")
        return False
    
    winFocus("not existing window")
    winFocus("ChroME")
    

    【讨论】:

      【解决方案9】:

      这个答案建立在上面的@nspire 和@nergeia 之上,并包含一种方法来查找窗口句柄 (https://www.blog.pythonlibrary.org/2014/10/20/pywin32-how-to-bring-a-window-to-front/) 到一个便利函数中:

      def raise_window(my_window):
      
          import win32con
          import win32gui
      
          def get_window_handle(partial_window_name):
      
              # https://www.blog.pythonlibrary.org/2014/10/20/pywin32-how-to-bring-a-window-to-front/
      
              def window_enumeration_handler(hwnd, windows):
                  windows.append((hwnd, win32gui.GetWindowText(hwnd)))
      
              windows = []
              win32gui.EnumWindows(window_enumeration_handler, windows)
      
              for i in windows:
                  if partial_window_name.lower() in i[1].lower():
                      return i
                      break
      
              print('window not found!')
              return None
      
          # https://stackoverflow.com/questions/6312627/windows-7-how-to-bring-a-window-to-the-front-no-matter-what-other-window-has-fo
      
          def bring_window_to_foreground(HWND):
              win32gui.ShowWindow(HWND, win32con.SW_RESTORE)
              win32gui.SetWindowPos(HWND, win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
              win32gui.SetWindowPos(HWND, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
              win32gui.SetWindowPos(HWND, win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_SHOWWINDOW + win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
      
          hwnd = get_window_handle(my_window)
      
          if hwnd is not None:
              bring_window_to_foreground(hwnd[0])
      
      
      raise_window('Untitled - notepad')
      

      【讨论】:

        猜你喜欢
        • 2015-04-03
        • 1970-01-01
        • 1970-01-01
        • 2021-11-28
        • 1970-01-01
        • 2012-08-18
        • 2012-08-05
        • 2021-07-15
        相关资源
        最近更新 更多