2011-06-10 53 views
14

我正在實施任務欄替換,碼頭式應用程序切換程序樣式程序。它使用OpenGL做了一些獨特的東西,並且使用鍵盤快捷鍵,所以它的設置方式,窗口並不總是有焦點。我想實現它,以便我可以將任意窗口放在前臺,就像任務欄或ALT-TAB程序一樣。Windows 7:無論其他窗口有什麼焦點,如何將窗口置於前面?

但是,我的代碼只是簡單地導致應用程序圖標在任務欄中閃爍。 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) 
+2

好的,但有很多應用程序能夠做到這一點。這顯然是可能的,我發現教程告訴我如何。我的問題是,我在做什麼導致教程中的代碼無法工作? – jmite 2011-06-10 22:28:55

+0

你爲什麼不從這些教程中選擇一些代碼並運行它? – 2011-06-10 22:33:29

+1

這就是我所做的。我發佈的代碼幾乎是教程中的確切代碼,在python包裝中(請參閱我發佈的兩個鏈接)。我問是否有人能說出爲什麼我的代碼沒有按照頁面所說的做,或者有更好的方法來做。 – jmite 2011-06-10 22:39:48

回答

6

我已經有一些代碼已經運行多年,一直回到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); 
+0

它將它帶到上面,但鍵盤焦點不在我們的頂部窗口中。 – Noitidart 2016-07-02 08:54:47

1

SetForegroundWindow函數的文檔解釋說,這其實是預期的行爲;流程不應該能夠「偷走」焦點。但是,可以調整您的代碼,使其無論如何都能正常工作。

看一看的LockSetForegroundWindow此言一節:它解釋

系統將自動啓用呼叫如果用戶按下ALT鍵SetForegroundWindow [..]

您可以利用此通過在調用SetForegroundWindow之前使程序模擬使用SendInput函數按下Alt鍵來執行此操作。

5

據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),現在適用於所有情況。
+2

您必須在調用SetWindowPos函數之前恢復窗口。 Delphi應用程序可以使用「Application.Restore;」函數來取消最小化。尋找ShowWindow(句柄,SW_RESTORE)python調用。即使窗口已經顯示,每次只要調用它就不會造成傷害。 – Whome 2013-12-20 16:04:35

9

我不喜歡這些使用win32gui的建議,因爲您無法通過pip輕鬆安裝。所以這裏是我的解決方案:

首先,通過pip安裝pywinauto。如果您使用的是Python 2.7.9或2分支上的較新版本,或者Python 3.4.0或3分支中的較新版本,則已安裝pip。對於其他人,更新Python來得到它(或者你可以手動下載並運行this script,如果你必須運行Python的舊版本進行安裝。)

只需在命令行中(而不是從內Python)的運行這個:

pip install pywinauto 

下,進口從pywinauto需要的東西:

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

最後,它只是一個實際的行:

SetForegroundWindow(find_window(title='taskeng.exe'))