How to run python program in background to keep active window the same

狂风中的少年 提交于 2021-02-05 08:00:09

问题


I have written a program that will change the foreground window to 85% of the monitor's dimensions and to run successfully the foreground window needs to remain the same.

I have put the python script (.pyw) into a batch file (running pythonw) and created a shortcut to the batch file on the desktop with a shortcut to run it quickly. I also made it run the batch file minimized but it still switches the foreground window to the minimized command prompt.

Per the python code below I am using pywin32 for the window manipulation. I get the information for the monitor because I have a three monitor setup so need to take into account the coordinates of the appropriate monitor.

#! python

import win32api
import win32gui
import win32con

monitors = win32api.EnumDisplayMonitors()
monitorsDict = {}
hwnd = win32gui.GetForegroundWindow()
currentWindowDimensions = win32gui.GetWindowRect(hwnd)
monitorInFocus = str(win32api.MonitorFromWindow(hwnd))

for i in range(len(monitors)):
    monitorsDict[str(monitors[i][0])] = monitors[i][2]

maxWidth = (monitorsDict[monitorInFocus][2]-monitorsDict[monitorInFocus][0]) * .85
maxHeight = (monitorsDict[monitorInFocus][3]-monitorsDict[monitorInFocus][1]) * .85
x = int(currentWindowDimensions[0])
y = int(currentWindowDimensions[1])
newWidth = int(maxWidth + x)
newHeight = int(maxHeight + y)
newDimensions = (x, y, newWidth, newHeight)

win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, x, y, newWidth, newHeight, 0)

The batch file is below:

C:\path\to\pythonw\executable\pythonw.exe C:\path\to\pyw\script\WindowSizing.pyw

I was under the impression that if I run pythonw rather than python it would run the script in the background without opening a command prompt window but this does not appear to be happening. Because the command prompt is the foreground window the script changes the size of the command prompt window and then closes it resulting in no change to the window I wanted to resize.

Is there something in the pywin32 module that would allow me to get the handle for the previous foreground window? Alternatively, is there a way to run the python script silently so the foreground window does not change?


回答1:


Although pythonw does run the script in the background without opening a command prompt window, your batch file does (even if this window is minimized). So you'll have to find the window that was active before your batch file was executed.
We use the EnumWindows function to iterate over our normal (i.e. visible and with a title) windows. The previous window is the second one in the enumeration. However, if you run the python script from a batch file, the command prompt window (as explained above) will be the previous window, so the one we're looking for is the third one in the enumeration.

#! python

import win32api
import win32gui
import win32con

monitors = win32api.EnumDisplayMonitors()
monitorsDict = {}

window_counter = [0]
def enumWindowsProc(hwnd, param):
    if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowTextLength(hwnd) > 0:
        window_counter[0] += 1
        print(win32gui.GetWindowText(hwnd))
        if window_counter[0] == 3:
           window_counter[0] = hwnd
           return False
    return True

try:
   win32gui.EnumWindows(enumWindowsProc,window_counter)
except:
   pass

hwnd = window_counter[0]
currentWindowDimensions = win32gui.GetWindowRect(hwnd)
monitorInFocus = str(win32api.MonitorFromWindow(hwnd))

for i in range(len(monitors)):
    monitorsDict[str(monitors[i][0])] = monitors[i][2]

maxWidth = (monitorsDict[monitorInFocus][2]-monitorsDict[monitorInFocus][0]) * .85
maxHeight = (monitorsDict[monitorInFocus][3]-monitorsDict[monitorInFocus][1]) * .85
x = int(currentWindowDimensions[0])
y = int(currentWindowDimensions[1])
newWidth = int(maxWidth + x)
newHeight = int(maxHeight + y)
newDimensions = (x, y, newWidth, newHeight)
win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, x, y, newWidth, newHeight, 0)

EnumWindows calls the callback function pass to it until this returns False. Unfortunately there's a bug in the win32 implementation: when the callback returns False, EnumWindows return 0 and this 0 is mistakenly considered an error and python will raise a run time error. A workaround is ignoring this error (as shown here) or just never return False and thus enumerate the windows list till the very end although we've already found our window.

Instead of using a batch file, there's a more elegant way to invoke your script without creating an extra batch file: in the shortcut on your desktop, you can just insert the one line C:\path\to\pythonw\executable\pythonw.exe C:\path\to\pyw\script\WindowSizing.pyw as the target. But remember, in this case we need to look for window number 2 instead of 3, so it'll be C:\path\to\pythonw\executable\pythonw.exe C:\path\to\pyw\script\WindowSizing.pyw.

I tested both approaches (batch file and direct shortcut target) on Windows 7 and both work fine, invocated by short cut key or by clicking on the icon on the desktop.



来源:https://stackoverflow.com/questions/57231459/how-to-run-python-program-in-background-to-keep-active-window-the-same

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!