python - visual - Windows 7: ¿cómo llevar una ventana al frente sin importar qué otra ventana tenga foco?
visual studio install python (5)
La documentación de la función SetForegroundWindow
explica que este es realmente el comportamiento previsto; los procesos no deberían ser capaces de "robar" el foco. Sin embargo, es posible ajustar su código para que funcione de todos modos.
Eche un vistazo a la sección de comentarios de LockSetForegroundWindow
: explica
El sistema activa automáticamente las llamadas a SetForegroundWindow si el usuario presiona la tecla ALT [..]
Puede aprovechar este comportamiento haciendo que su programa simule presionar la tecla Alt usando la función SendInput
antes de llamar a SetForegroundWindow
.
Estoy implementando un programa de sustitución de aplicaciones, como el dock, como un conmutador de aplicaciones. Está haciendo algunas cosas únicas con OpenGL, y con los atajos de teclado, por lo que la forma en que está configurada, la ventana no siempre tiene foco. Me gustaría implementarlo de modo que pueda traer una ventana arbitraria al primer plano, al igual que lo haría una barra de tareas o un programa ALT-TAB.
Sin embargo, mi código simplemente hace que el icono de la aplicación parpadee en la barra de tareas. La documentación de la API de Windows dice que esto es lo que se supone que debe suceder, pero estoy buscando una forma de evitar esto.
He adaptado mi código de los siguientes ejemplos, que dicen que la vinculación al subproceso en primer plano debería permitirle establecer la ventana en primer plano. Aquí están los sitios:
http://www.voidnish.com/Articles/ShowArticle.aspx?code=dlgboxtricks
http://invers2008.blogspot.com/2008/10/mfc-how-to-steal-focus-on-2kxp.html
Mi código se ve así. Tenga en cuenta que está utilizando los wrappers win32 para python (self.hwnd es el identificador de la ventana que quiero mostrar al frente):
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)
Sin embargo, a menos que mi ventana sea la ventana de primer plano (que no suele ser así), esto solo hace que parpadee el icono del programa.
¿Estoy haciendo mal el hilo? ¿Hay alguna otra forma de evitar esto? Me imagino que debe haber, ya que hay muchos mezcladores de aplicaciones que parecen ser capaces de hacer esto bien.
Estoy escribiendo esto en python, pero si hay una solución en otro idioma, usaré wrappers o haré lo que sea necesario para ponerlo en funcionamiento.
¡Gracias por adelantado!
EDITAR: estaría abierto a una forma de hacerlo funcionar solo en mi computadora en particular, es decir, una forma de habilitar, en mi máquina, una forma para que cualquier aplicación se enfoque.
SOLUCIONADO: Lo que tienes que hacer es desactivar el bloqueo de primer plano. Resulta que fue tan fácil como esto:
win32gui.SystemParametersInfo(win32con.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, win32con.SPIF_SENDWININICHANGE | win32con.SPIF_UPDATEINIFILE)
Si está implementando teclas rápidas, use RegisterHotKey
. Como dice Raymond Chen (artículo de blog complementario al que ya tiene Chris), "presionar una tecla de acceso directo te da el amor de activación en primer plano" .
Según nspire, probé su solución con python 2.7 y W8, y funciona como un hechizo, incluso si la ventana está minimizada *.
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)
- Originalmente era si la ventana no se minimiza , pero gracias al comentario de
win32gui.ShowWindow(HWND, win32con.SW_RESTORE)
, ahora funciona en todas las situaciones.
No me gustan estas sugerencias de usar win32gui
porque no puedes instalarlo fácilmente a través de pip
. Así que aquí está mi solución:
Primero, instale pywinauto
vía pip
. Si tienes Python 2.7.9 o una versión más nueva en la rama 2, o Python 3.4.0 o una versión más nueva de la rama 3, pip
ya está instalado. Para todos los demás, actualice Python para obtenerlo (o puede descargarlo e instalarlo manualmente ejecutando este script , si debe ejecutar una versión anterior de Python).
Simplemente ejecute esto desde la línea de comando (no desde dentro de Python):
pip install pywinauto
A continuación, importa lo que necesites de pywinauto
:
from pywinauto.findwindows import find_window
from pywinauto.win32functions import SetForegroundWindow
Finalmente, es solo una línea real:
SetForegroundWindow(find_window(title=''taskeng.exe''))
He tenido algún código que se ha estado ejecutando durante años, desde Windows 95. Al hacer doble clic en el ícono de la bandeja del sistema de aplicaciones, siempre utilicé las funciones de la API de Win32, como BringWindowToTop y SetForegroundWindow, para poner las ventanas de mi aplicación en primer plano. Todo esto dejó de funcionar como estaba previsto en Windows 7, donde mi ventana de entrada terminaría detrás de otras ventanas y el icono de la ventana parpadearía en la barra de estado. El ''trabajo alrededor'' que se me ocurrió fue esto; y parece funcionar en todas las versiones de 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);