用Python切换窗口

3 投票
2 回答
21308 浏览
提问于 2025-04-17 19:09

我先说一下,我对Python的了解还很浅,希望我的问题能有个简单的解决办法。

我的程序需要在另一个窗口里执行一些简单的操作,所以我希望我的脚本能确保这个窗口是最大化并且处于活动状态,然后再执行后面的命令。没想到这比我想象的要复杂得多。

我觉得可以用win32gui这个库来实现,具体是通过find_window函数把窗口调到最前面。我以为我找到了答案,因为我看到之前有个问题讨论过这个:Python窗口激活

可惜我没法用那个解决方案的代码,或者说我没法调整它来解决我的问题,原因有几个:

- 那个用户定义的find_window函数只能通过窗口的类名来选择,而我不知道这个类名,也找不到,因为它只是一个用Java运行的游戏。我似乎无法把那行代码改成用我知道的窗口名称来工作,因为它不是“默认参数”。

- 我不想去列举所有窗口来找到它,因为我不太确定那样会怎么操作。

- 使用find_window_wildcard这个函数,虽然在那段代码里有写过,但它只能在窗口已经打开的情况下偶尔把窗口调到最前面。

- set_foreground()这个函数需要一个输入参数,但无论我怎么设置,总是报错,说我要么元素数量不对,要么窗口的句柄无效。

我知道我可能有点笨;不过如果能有一个清晰简洁的解决方案,或者至少对find_window/getwindow语法的好解释,那对我和其他遇到同样问题的人来说简直是救星。

2 个回答

1

这个用户定义的找窗口的方法,只能通过窗口的类名来选择。

用户的定义是把两个参数 class_namewindow_name 直接传给 win32gui.FindWindow(这个函数又调用了Win32的API函数 FindWindow)。所以,你只需要这样做:

windowmgr.find_window(None, 'My Window Name')

不过即使不是这样,你也不需要使用他的 find_window 函数;你应该很容易就能自己调用 win32gui.FindWindow

hwnd = win32gui.FindWindow(None, 'My Window Name')

如果你想要了解 FindWindow/EnumWindows 等的用法,试着看看它们的文档吗?那里有没有什么你不明白的地方?

与此同时:

……这个窗口的类名我不知道,也找不到,因为它只是一个用Java运行的游戏。

这个窗口是用Java运行有什么区别呢?无论是用C++、Java、.NET、Python还是其他语言,你都可以列出所有窗口并打印出它们的类名。或者使用Visual Studio/VS Express自带的工具,或者网上找到的任何免费的改进版本,比如 MS Spy++,它可以让你指向一个窗口并给出标题和类名。

我不想列出窗口来找,因为我不确定那是怎么工作的。

只需调用 windowmgr.find_window_wildcard(wildcard),并使用正则表达式,它会列出所有窗口并将它们的标题与正则表达式进行比较。

如果你想自己写代码来实现这个功能,可以写一个这样的函数:

def my_callback(hwnd, cookie):

现在,当你这样做时:

win32gui.EnumWindows(my_callback, some_cookie)

……它会对每个窗口调用你的 my_callback 函数,hwnd 是窗口(你可以将它传递给 win32gui 的函数,比如 GetWindowText),cookie 是你传入的同一个 some_cookie 值。(如果你不需要传入任何东西,就传 None,在你的回调函数中也不做任何处理。但你可以看到其他回答者是如何使用它来传递正则表达式的。)

与此同时:

使用 find_window_wildcard,按照脚本中的写法,确实有几次把窗口调到了前面,但只有在窗口已经打开的情况下,而且它只是不稳定地工作。

首先,如果窗口不存在,你是无法把它调到前面的。你怎么指望它能工作呢?

至于不稳定工作,我猜可能是有很多窗口符合你的通配符,程序会随机选择其中一个。可能不是你想要的那个。(它甚至可能是一个隐藏的窗口,所以你根本看不到任何变化。)

无论如何,你不需要使用 find_window_wildcard;如果你知道确切的名称,就直接用那个。当然,这个名称也可能不是唯一的(无论游戏的名称是什么,你都可以打开一个标题相同的邮件或记事本窗口……这也是为什么你要先尝试类名),但至少它比一些不明确的通配符更可能是唯一的。

那么,如果类名不是唯一的(更糟的是,它是一些特殊的“数字”类,比如 #32770 代表一个通用对话框),而窗口名也不是唯一的呢?你可以通过查看拥有该窗口的进程或模块(exe/dll)、父窗口等来更好地缩小范围。你需要查阅 win32gui 和/或 MSDN 文档(上面有链接),找出可能的尝试方法,并通过反复试验(也别忘了Spy工具)找到一种能够唯一指定窗口的方法。然后把它写成代码。

4

非常建议你去看看Swapypywinauto这两个页面。这两个工具可以帮助你在用户界面自动化方面做一些很酷的事情。

撰写回答