Как запустить программу на python в фоновом режиме, чтобы сохранить активное окно неизменным

#python #pygame

#python #пакетный файл

Вопрос:

Я написал программу, которая изменит окно переднего плана на 85% от размеров монитора, и для успешного запуска окно переднего плана должно оставаться неизменным.

Я поместил скрипт python (.pyw) в пакетный файл (под управлением pythonw) и создал ярлык для пакетного файла на рабочем столе с ярлыком для его быстрого запуска. Я также заставил его запустить свернутый пакетный файл, но он по-прежнему переключает окно переднего плана на свернутую командную строку.

Согласно приведенному ниже коду python, я использую pywin32 для управления окнами. Я получаю информацию для монитора, потому что у меня настроено три монитора, поэтому необходимо учитывать координаты соответствующего монитора.

 #! 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)
 

Пакетный файл находится ниже:

 C:pathtopythonwexecutablepythonw.exe C:pathtopywscriptWindowSizing.pyw
 

У меня создалось впечатление, что если я запущу pythonw, а не python, он запустит скрипт в фоновом режиме, не открывая окно командной строки, но, похоже, этого не происходит. Поскольку командная строка является окном переднего плана, сценарий изменяет размер окна командной строки, а затем закрывает его, что не приводит к изменению размера окна, которое я хотел изменить.

Есть ли что-нибудь в модуле pywin32, что позволило бы мне получить дескриптор для предыдущего окна переднего плана? В качестве альтернативы, есть ли способ запустить скрипт python в автоматическом режиме, чтобы окно переднего плана не менялось?

Ответ №1:

Хотя pythonw скрипт запускается в фоновом режиме без открытия окна командной строки, ваш пакетный файл выполняет (даже если это окно свернуто). Поэтому вам нужно будет найти окно, которое было активным до выполнения вашего пакетного файла.
Мы используем функцию EnumWindows для перебора наших обычных (т. Е. Видимых и с заголовком) окон. Предыдущее окно является вторым в перечислении. Однако, если вы запустите скрипт python из пакетного файла, окно командной строки (как объяснено выше) будет предыдущим окном, поэтому то, которое мы ищем, является третьим в перечислении.

 #! 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 вызовы функции обратного вызова передаются ей до тех пор, пока это не вернется False . К сожалению, в реализации win32 есть ошибка: когда возвращается обратный False EnumWindows вызов, return 0 и это 0 ошибочно считается ошибкой, и python выдает ошибку времени выполнения. Обходным путем является игнорирование этой ошибки (как показано здесь) или просто никогда не возвращаться False и, таким образом, перечислять список окон до самого конца, хотя мы уже нашли наше окно.

Вместо использования пакетного файла есть более элегантный способ вызвать ваш скрипт без создания дополнительного пакетного файла: в ярлыке на рабочем столе вы можете просто вставить одну строку C:pathtopythonwexecutablepythonw.exe C:pathtopywscriptWindowSizing.pyw в качестве цели. Но помните, что в этом случае нам нужно искать окно с номером 2 вместо 3, так оно и будет C:pathtopythonwexecutablepythonw.exe C:pathtopywscriptWindowSizing.pyw .

Я протестировал оба подхода (командный файл и цель прямого ярлыка) в Windows 7, и оба работают нормально, вызываются короткой клавишей или щелчком по значку на рабочем столе.