2015-05-12 4 views
8

Я пытаюсь написать программу, которая находит окно, ища его название. Как только он найдет окно, он попытается вывести его на передний план. Для этого я использую API win32gui. Я могу заставить его работать по большей части, но по какой-то причине он не работает, если диспетчер задач находится впереди. У меня есть следующий образец кода.Python win32gui Функция SetAsForegroundWindow не работает должным образом

import win32gui, win32con 
import re, traceback 
from time import sleep 

class cWindow: 
    def __init__(self): 
     self._hwnd = None 

    def BringToTop(self): 
     win32gui.BringWindowToTop(self._hwnd) 

    def SetAsForegroundWindow(self): 
     win32gui.SetForegroundWindow(self._hwnd) 

    def Maximize(self): 
     win32gui.ShowWindow(self._hwnd, win32con.SW_MAXIMIZE) 

    def setActWin(self): 
     win32gui.SetActiveWindow(self._hwnd) 

    def _window_enum_callback(self, hwnd, wildcard): 
     '''Pass to win32gui.EnumWindows() to check all the opened windows''' 
     if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) != None: 
      self._hwnd = hwnd 

    def find_window_wildcard(self, wildcard): 
     self._hwnd = None 
     win32gui.EnumWindows(self._window_enum_callback, wildcard) 


def main(): 
    sleep(5) 
    try:  
     wildcard = ".*Building Operation WorkStation.*" 
     cW = cWindow() 
     cW.find_window_wildcard(wildcard) 
     cW.Maximize() 
     cW.BringToTop() 
     cW.SetAsForegroundWindow() 

    except: 
     f = open("log.txt", "w") 
     f.write(traceback.format_exc()) 
     print traceback.format_exc() 
main() 

Я собрал это вместе из нескольких источников в Интернете. Похоже, что он работает по большей части, но для некоторых окон, таких как диспетчер задач, он будет работать иногда, но не сработает. Когда он не работает должным образом, все, что я заметил, это значок приложения, который мигает желтым. Есть ли правильный способ сделать это, чтобы убедиться, что окно, которое меня интересует, установлено на переднем плане в 100% случаев? Я не уверен, что это актуально, но я использую Windows 7 Professional (32-разрядный) с Service Pack 1.

ответ

4

Я нашел решение: если taskmanager, то убить его. Я добавил метод cWindow:

def kill_task_manager(self): 
    # Here I use your method to find a window because of an accent in my french OS, 
    # but you should use win32gui.FindWindow(None, 'Task Manager complete name'). 
    wildcard = 'Gestionnaire des t.+ches de Windows' 
    self.find_window_wildcard(wildcard) 
    if self._hwnd: 
     win32gui.PostMessage(self._hwnd, win32con.WM_CLOSE, 0, 0) # kill it 
     sleep(0.5) # important to let time for the window to be closed 

этот метод только после cW = cWindow() вызова.

Другая ошибка ловушки, чтобы предотвратить это исключение в SetAsForegroundWindow:

error: (0, 'SetForegroundWindow', 'No error message is available') 

просто отправить ключ альт перед вызовом win32gui:

# Add this import 
import win32com.client 

# Add this to __ini__ 
self.shell = win32com.client.Dispatch("WScript.Shell") 

# And SetAsForegroundWindow becomes 
def SetAsForegroundWindow(self): 
    self.shell.SendKeys('%') 
    win32gui.SetForegroundWindow(self._hwnd) 

Наконец, если я могу, не сравнить != None но is not None. Более вещий;)

Это полный код:

# coding: utf-8 

import re, traceback 
import win32gui, win32con, win32com.client 
from time import sleep 


class cWindow: 
    def __init__(self): 
     self._hwnd = None 
     self.shell = win32com.client.Dispatch("WScript.Shell") 

    def BringToTop(self): 
     win32gui.BringWindowToTop(self._hwnd) 

    def SetAsForegroundWindow(self): 
     self.shell.SendKeys('%') 
     win32gui.SetForegroundWindow(self._hwnd) 

    def Maximize(self): 
     win32gui.ShowWindow(self._hwnd, win32con.SW_MAXIMIZE) 

    def setActWin(self): 
     win32gui.SetActiveWindow(self._hwnd) 

    def _window_enum_callback(self, hwnd, wildcard): 
     '''Pass to win32gui.EnumWindows() to check all the opened windows''' 
     if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None: 
      self._hwnd = hwnd 

    def find_window_wildcard(self, wildcard): 
     self._hwnd = None 
     win32gui.EnumWindows(self._window_enum_callback, wildcard) 

    def kill_task_manager(self): 
     wildcard = 'Gestionnaire des t.+ches de Windows' 
     self.find_window_wildcard(wildcard) 
     if self._hwnd: 
      win32gui.PostMessage(self._hwnd, win32con.WM_CLOSE, 0, 0) 
      sleep(0.5) 

def main(): 
    sleep(5) 
    try: 
     wildcard = ".*Building Operation WorkStation.*" 
     cW = cWindow() 
     cW.kill_task_manager() 
     cW.find_window_wildcard(wildcard) 
     cW.BringToTop() 
     cW.Maximize() 
     cW.SetAsForegroundWindow() 

    except: 
     f = open("log.txt", "w") 
     f.write(traceback.format_exc()) 
     print(traceback.format_exc()) 


if __name__ == '__main__': 
    main() 

Источники: how do I close window with handle using win32gui in Python и win32gui.SetActiveWindow() ERROR : The specified procedure could not be found.

5

Примечание: Следующая дело только убедившись, что окна всегда поверх всех окон, таких как Диспетчер задач скрыты перед активацией окна - это предполагает, что сама активация часть работает отлично, который не может быть дело. Условия, в которых процесс разрешен для вызова функции Windows API SetForegroundWindow, перечислены here.


Task Manager является особенным в двух отношениях:

  • По умолчанию он настроен на отображение всегда на верхней, т.е. выше всех других окон.
  • Даже при том, что выключен (Options > Always on Topбесконтрольно), вы можете еще сделать его отображения на вершине других всегда-на-верху окна (что-то, что обычные окна, казалось бы, не может сделать).

Ваш код:

  • является работа - в моих тестах - в том смысле, что целевое окно не станет активным.
  • is не, работающий в том смысле, что окно диспетчера задач остается в верхней части окна (максимально).
    • , даже пытаясь сделать вашим окном, окно всегда на верх, а также не поможет, к сожалению.

В частности проверка на наличие в окне диспетчера задач и свести к минимуму это вариант, но учтите, что там может быть другие окна всегда поверх всех окон, так для надежного решения, которое вы имеете чтобы определить все открытые окна всегда поверх всех окон и свести к минимуму их:

следующая старается выявить все окна всегда поверх всех окон, кроме панели задач и кнопки Пуск и минимизирует (эффективно скрыть s) любые такие окна.

Новые методы: hide_always_on_top_windows и _window_enum_callback_hide.

import win32gui, win32con 
import re, traceback 
from time import sleep 

class cWindow: 
    def __init__(self): 
     self._hwnd = None 

    def SetAsForegroundWindow(self): 
     # First, make sure all (other) always-on-top windows are hidden. 
     self.hide_always_on_top_windows() 
     win32gui.SetForegroundWindow(self._hwnd) 

    def Maximize(self): 
     win32gui.ShowWindow(self._hwnd, win32con.SW_MAXIMIZE) 

    def _window_enum_callback(self, hwnd, regex): 
     '''Pass to win32gui.EnumWindows() to check all open windows''' 
     if self._hwnd is None and re.match(regex, str(win32gui.GetWindowText(hwnd))) is not None: 
      self._hwnd = hwnd 

    def find_window_regex(self, regex): 
     self._hwnd = None 
     win32gui.EnumWindows(self._window_enum_callback, regex) 

    def hide_always_on_top_windows(self): 
     win32gui.EnumWindows(self._window_enum_callback_hide, None) 

    def _window_enum_callback_hide(self, hwnd, unused): 
     if hwnd != self._hwnd: # ignore self 
      # Is the window visible and marked as an always-on-top (topmost) window? 
      if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE) & win32con.WS_EX_TOPMOST: 
       # Ignore windows of class 'Button' (the Start button overlay) and 
       # 'Shell_TrayWnd' (the Task Bar). 
       className = win32gui.GetClassName(hwnd) 
       if not (className == 'Button' or className == 'Shell_TrayWnd'): 
        # Force-minimize the window. 
        # Fortunately, this seems to work even with windows that 
        # have no Minimize button. 
        # Note that if we tried to hide the window with SW_HIDE, 
        # it would disappear from the Task Bar as well. 
        win32gui.ShowWindow(hwnd, win32con.SW_FORCEMINIMIZE) 

def main(): 
    sleep(5) 
    try:  
     regex = ".*Building Operation WorkStation.*" 
     cW = cWindow() 
     cW.find_window_regex(regex) 
     cW.Maximize() 
     cW.SetAsForegroundWindow() 

    except: 
     f = open("log.txt", "w") 
     f.write(traceback.format_exc()) 
     print(traceback.format_exc()) 
main() 
+0

В случае, если не так: 'win32gui.GetWindowLong (HWND, win32con.GWL_EXSTYLE) и win32con.WS_EX_TOPMOST' быть' win32gui.GetWindowLong (HWND, win32con.GWL_EXSTYLE & win32con.WS_EX_TOPMOST) '? Твоя попытка собрать их вместе? – IronManMark20

+0

@ IronManMark20: 'win32gui.GetWindowLong (hwnd, win32con.GWL_EXSTYLE)' возвращает битное поле, а '& win32con.WS_EX_TOPMOST' проверяет, установлен ли определенный бит. То, что вы делаете, вероятно, приводит к тому, что недопустимый флаг передается 'GetWindowLong'. – mklement0

+1

Получил. Это выглядело не так. Благодарю. – IronManMark20