Windows 7: как вывести окно на передний план, независимо от того, какое другое окно имеет фокус? - PullRequest
16 голосов
/ 11 июня 2011

Я реализую замену панели задач, подобную док-станции программу в стиле переключения приложений. Он делает некоторые уникальные вещи с OpenGL и с горячими клавишами, поэтому при настройке окно не всегда имеет фокус. Я хотел бы реализовать это так, чтобы я мог вывести произвольное окно на передний план, так же как панель задач или программа ALT-TAB.

Однако мой код просто заставляет значок приложения мигать на панели задач. В документации Windows API сказано, что это то, что должно произойти, но я ищу способ обойти это.

Я адаптировал свой код из следующих примеров, в которых говорится, что присоединение к потоку переднего плана должно позволить вам установить окно переднего плана. Вот сайты:

http://www.voidnish.com/Articles/ShowArticle.aspx?code=dlgboxtricks

http://invers2008.blogspot.com/2008/10/mfc-how-to-steal-focus-on-2kxp.html

Мой код выглядит следующим образом. Обратите внимание, что он использует оболочки win32 для python (self.hwnd - это дескриптор окна, которое я хочу вывести на передний план):

fgwin = win32gui.GetForegroundWindow()
fg = win32process.GetWindowThreadProcessId(fgwin)[0]
current = win32api.GetCurrentThreadId()
if current != fg:
    win32process.AttachThreadInput(fg, current, True)
    win32gui.SetForegroundWindow(self.hwnd)
    win32process.AttachThreadInput(fg, win32api.GetCurrentThreadId(), False)

Однако, если мое окно не является окном переднего плана (что обычно не происходит), это просто заставляет значок программы мигать.

Я неправильно делаю нить? Есть ли другой способ обойти это? Я полагаю, что должно быть, так как есть много переключателей приложений, которые, кажется, могут сделать это просто отлично.

Я пишу это на python, но если есть решение на другом языке, я буду использовать обертки или делать все необходимое для запуска и запуска.

Заранее спасибо!

РЕДАКТИРОВАТЬ: Я был бы открыт для способа заставить его работать только на моем конкретном компьютере, то есть способ, чтобы на моей машине, способ для любого приложения, чтобы сосредоточиться. *

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

win32gui.SystemParametersInfo(win32con.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, win32con.SPIF_SENDWININICHANGE | win32con.SPIF_UPDATEINIFILE)

Ответы [ 6 ]

10 голосов
/ 16 февраля 2015

Мне не нравятся эти предложения использования win32gui, потому что вы не можете легко установить это через pip.Итак, вот мое решение:

Сначала установите pywinauto через pip.Если вы используете Python 2.7.9 или более новую версию в ветви 2, или Python 3.4.0 или более новую версию из ветви 3, pip уже установлена.Для всех остальных обновите Python, чтобы получить его (или вы можете вручную загрузить и установить его, запустив этот скрипт , если вам нужно запустить более старую версию Python.)

Просто запустите это изкомандная строка (не из Python):

pip install pywinauto

Затем импортируйте то, что вам нужно, из pywinauto:

from pywinauto.findwindows    import find_window
from pywinauto.win32functions import SetForegroundWindow

Наконец, это всего лишь одна фактическая строка:

SetForegroundWindow(find_window(title='taskeng.exe'))
7 голосов
/ 10 мая 2012

У меня был некоторый код, который выполнялся годами, вплоть до Windows 95. При двойном щелчке по значку в системном трее приложений я всегда использовал функции Win32 API, такие как BringWindowToTop и SetForegroundWindow, чтобы привести окна моего приложения в на переднем плане. Все это перестало работать так, как задумано в Windows 7, где мое окно ввода оказалось бы позади других окон, а значок окна мигал в строке состояния. «Работа вокруг», с которой я придумал, заключалась в следующем; и, похоже, работает на всех версиях Windows.

//-- show the window as you normally would, and bring window to foreground.
//   for example;
::ShowWindow(hWnd,SW_SHOW); 
::BringWindowToTop(hWnd);
::SetForegroundWindow(hWnd);

//-- on Windows 7, this workaround brings window to top
::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
6 голосов
/ 01 ноября 2013

Согласно nspire, я пробовал его решение с python 2.7 и W8, и оно работает как шарм, , даже если окно свернуто *.

win32gui.ShowWindow(HWND, win32con.SW_RESTORE)
win32gui.SetWindowPos(HWND,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)  
win32gui.SetWindowPos(HWND,win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)  
win32gui.SetWindowPos(HWND,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_SHOWWINDOW + win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
  • Изначально это было , если окно не свернуто , но благодаря комментарию Whome win32gui.ShowWindow(HWND, win32con.SW_RESTORE) теперь оно работает во всех ситуациях.
3 голосов
/ 13 июня 2011

Если вы используете горячие клавиши, используйте RegisterHotKey. Как говорит Раймонд Чен (статья в блоге-компаньоне, уже связанная с Крисом), «Нажатие зарегистрированной горячей клавиши дает вам любовь к активации на переднем плане» .

1 голос
/ 12 июня 2011

Документация для функции SetForegroundWindow объясняет, что это на самом деле предполагаемое поведение; процессы не должны быть в состоянии «украсть» фокус. Тем не менее, ваш код можно настроить так, чтобы он все равно работал.

Посмотрите на раздел замечаний LockSetForegroundWindow: он объясняет

Система автоматически разрешает вызовы SetForegroundWindow, если пользователь нажимает клавишу ALT [..]

Вы можете использовать это поведение, заставив вашу программу имитировать нажатие клавиши Alt с помощью функции SendInput перед вызовом SetForegroundWindow.

0 голосов
/ 08 февраля 2019

Вот так я начал работать:

import win32gui
from win32con import (SW_SHOW, SW_RESTORE)

def get_windows_placement(window_id):
    return win32gui.GetWindowPlacement(window_id)[1]

def set_active_window(window_id):
    if get_windows_placement(window_id) == 2:
        win32gui.ShowWindow(window_id, SW_RESTORE)
    else:
        win32gui.ShowWindow(window_id, SW_SHOW)
    win32gui.SetForegroundWindow(window_id)
    win32gui.SetActiveWindow(window_id)
...