【问题标题】:Python: Can bring window to front but cannot set focus (win32gui.SetForegroundWindow)Python:可以将窗口置于前面但无法设置焦点(win32gui.SetForegroundWindow)
【发布时间】:2022-10-06 16:20:14
【问题描述】:

每次用户按 F2(在任何应用程序中)时,我的程序都会弹出一个窗口。

我正在使用pynput 捕获 F2 按钮(工作正常)

我正在使用tkinter 创建弹出窗口(工作正常)

我正在使用win32gui.SetForegroundWindow(windowHandel)tkinter 窗口置于前面并设置焦点。还有问题。

如果按下 F2 时选择了 python 窗口,则一切正常,tkinter 窗口都移到前面并获得焦点。

但是 - 如果在我按 F2 时选择了任何其他窗口,tkinter 窗口确实会移到前面,但它没有被选中(即聚焦)。

这是代码中的相关部分(在下面找到完整代码):

while not windowFound and counter < MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW:

   try:
      windowHandel = win32gui.FindWindow(None, windowName)
      win32gui.SetForegroundWindow(windowHandel)
   except:
      windowFound = False
   else:
      print(\"Success, Window found on the \" + str(counter + 1) + \" tries\")
      windowFound = True

找了一会儿答案,发现有人说这个可以用win32process解决。所以我尝试添加:

windowHandelID, _ = win32process.GetWindowThreadProcessId(windowHandel)
win32process.AttachThreadInput(win32api.GetCurrentThreadId(), windowHandelID, True)
win32gui.SetFocus(windowHandel)

然而,它导致了同样的行为。

下面是完整的(简化的,没有退出条件的)代码。 尝试在 python 聚焦时按 F2。

然后尝试在聚焦任何其他窗口(例如记事本)时按 F2。 您会看到,在一种情况下,您可以开始写作,tkinter 窗口将接收输入,而在另一种情况下,您仍然需要单击该窗口。

我将不胜感激任何帮助或建议。

import pyautogui  # For keyboard shortcuts and moving the cursor and selecting the window
import time  # For the delay function
from pynput import keyboard  # For catching keyboard strokes
import tkinter  # GUI
import threading  # For Threading
import win32gui  # For Setting Focus on the Flipper Window
import win32process
import win32api

# Resetting Variables / Settings
start_flipping_text_sequence = False
ContinueThreads = True
SearchForFlipperWindow = False
window_name = \"tk\"
MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW = 10


# This function runs in a separate thread
def selectFlipperWindow(windowName):

    # Since the thread runs constantly, it will only start looking for the flipper window when this variable is True
    global SearchForFlipperWindow

    # How many loops should the program go through before it gives up on finding the window
    global MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW

    # While program was not ended
    while True:

        # This is False, unless F2 is pressed
        if SearchForFlipperWindow:

            # Did the program find the flipper window
            windowFound = False
            counter = 0

            while not windowFound and counter < MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW:

                try:
                    windowHandel = win32gui.FindWindow(None, windowName)
                    win32gui.SetForegroundWindow(windowHandel)
                except:
                    windowFound = False
                else:
                    print(\"Success, Window found on the \" + str(counter + 1) + \" tries\")

                    windowHandelID, _ = win32process.GetWindowThreadProcessId(windowHandel)
                    win32process.AttachThreadInput(win32api.GetCurrentThreadId(), windowHandelID, True)
                    win32gui.SetFocus(windowHandel)
                    windowFound = True

                counter += 1
                time.sleep(0.1)

            SearchForFlipperWindow = False

        time.sleep(0.1)


# Execute functions based on the clicked key
def on_press(key):
    global start_flipping_text_sequence

    # If the user pressed the F2 key
    if key == keyboard.Key.f2:
        start_flipping_text_sequence = True

def okButton():
    root.destroy()

def enter(event):
    okButton()

# Assigning event to function
listener = keyboard.Listener(on_press=on_press)

# initiating listener
listener.start()

# Start a thread for searching for the flipper window
selectWindowThread = threading.Thread(target=selectFlipperWindow, args=(window_name,))
selectWindowThread.start()

while 1 == 1:
    time.sleep(.05)

    if start_flipping_text_sequence:

        SearchForFlipperWindow = True

        root = tkinter.Tk()

        tk_window_input = tkinter.Entry(root, width=100)
        tk_window_input.pack(padx=20)
        tk_window_input.focus()

        # Binds the OK button to the okButton function above
        tk_window_ok = tkinter.Button(root, width=20, text=\"OK\", command=okButton)
        tk_window_ok.pack(pady=20)

        # Binds the \"Enter\" keyboard key to the \"enter\" event above
        tk_window_input.bind(\'<Return>\', enter)

        # the main looper of the tkinter window
        # runs until root.destroy() to executed above
        root.mainloop()

        start_flipping_text_sequence = False

```

    标签: python


    【解决方案1】:

    您看到的是 Windows 中的故意限制。 Raymond Chen 在文章Foreground activation permission is like love: You can’t steal it, it has to be given to you 中描述了该限制。 SetForegroundWindow 文档的备注部分提供了有关限制的更多技术细节。

    有一些方法可以免除限制。 Raymond Chen 在文章Pressing a registered hotkey gives you the foreground activation love 中描述了一种很好的方法。

    以下代码显示了另一种绕过限制的奇怪方法:

    kbd.press(keyboard.Key.alt)
    try:
        win32gui.SetForegroundWindow(windowHandel)
    finally:
        kbd.release(keyboard.Key.alt)
    

    kbd 是这样创建的:

    from pynput.keyboard import Controller
    kbd = Controller()
    

    以下是此解决方法为何有效的解释:link

    摆脱这种变通方法的一个好方法可能是要求用户按 Alt-F2 以切换到您的应用程序。

    祝你编码好运 ;-)

    【讨论】:

      猜你喜欢
      • 2012-08-18
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 1970-01-01
      • 2011-09-17
      • 2011-03-20
      • 2012-07-08
      • 2011-11-04
      相关资源
      最近更新 更多