web-dev-qa-db-ja.com

Windows 7:他のどのウィンドウにフォーカスがあるかに関係なく、ウィンドウを前面に移動する方法は?

タスクバーの置き換え、ドックのようなアプリケーションスイッチャースタイルのプログラムを実装しています。 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

私のコードは次のようになります。 python(self.hwndは前面に表示したいウィンドウのハンドル)にwin32ラッパーを使用していることに注意してください):

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)
18
jmite

Windows 95までさかのぼって、何年も実行されているコードがいくつかあります。アプリケーションのシステムトレイアイコンをダブルクリックすると、常にBringWindowToTopやSetForegroundWindowなどのWin32 API関数を使用して、アプリケーションウィンドウを前面に表示しました。これはすべてWindows7で意図したとおりに機能しなくなり、入力ウィンドウが他のウィンドウの後ろに表示され、ウィンドウアイコンがステータスバーで点滅しました。私が思いついた「回避策」はこれでした。そしてそれは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);
7
nspire

pipを介して簡単にインストールできないため、win32guiを使用するというこれらの提案は好きではありません。だからここに私の解決策があります:

まず、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

最後に、これは実際の1行です。

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

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)、これで、すべての状況で機能します。
6
nergeia

ホットキーを実装している場合は、 RegisterHotKey を使用します。レイモンド・チェンが言っているように(クリスによってすでにリンクされているものへのコンパニオンブログ記事)、 「登録されたホットキーを押すとフォアグラウンドアクティベーションの愛が得られます」

3
Ben Voigt

SetForegroundWindow 関数のドキュメントでは、これは実際には意図された動作であると説明されています。プロセスはフォーカスを「盗む」ことができないはずです。ただし、とにかく機能するようにコードを調整することは可能です。

LockSetForegroundWindow の備考セクションをご覧ください:説明しています

ユーザーがALTキーを押すと、システムはSetForegroundWindowへの呼び出しを自動的に有効にします[..]

SendInputを呼び出す前に、 SetForegroundWindow 関数を使用してAltキーを押すことをプログラムにシミュレートさせることで、この動作を利用できます。

1
Frerich Raabe

これは私が私の仕事をさせた方法です:

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)
1
JahBless

上記でいくつかのすばらしい答えを見ましたが、ウィンドウ名がより柔軟なパラメーターになる追加の機能が必要でした。失敗するとfalseを返します。

from win32gui import IsWindowVisible, GetWindowText, EnumWindows,\
ShowWindow, SetForegroundWindow, SystemParametersInfo

#Sub-Functions
def window_enum_handler(hwnd, resultList):
    if IsWindowVisible(hwnd) and GetWindowText(hwnd) != '':
        resultList.append((hwnd, GetWindowText(hwnd)))

#Prime-Functions
def winFocus(partial_window_name):
    SystemParametersInfo(8193, 0, 2 | 1)
    handles=[]
    EnumWindows(window_enum_handler, handles)
    for i in handles:
        if str(partial_window_name).upper() in str(i[1]).upper():
            ShowWindow(i[0], 3)
            SetForegroundWindow(i[0])
            return True
    print(partial_window_name + " was not found")
    return False

winFocus("not existing window")
winFocus("ChroME")