14

画面上のマウスの位置に基づいて、オブザーバーを中心に世界を回転させる 3D レンダリング プログラムがあります。世界が回転するラジアンの量は、この行によって定義されます

    glob.worldx=-(w.winfo_pointerxy()[0]-xy[0])/250

xy[0] は画面の中心の x 座標です。

これは、観察者の視野を回転できる量が、マウスが移動できる距離によって制限されることを意味します。マウスを画面の中央に戻すことができれば、この問題を解決できます。何か案は?

4

2 に答える 2

16

良いニュースは、それを行う方法があるということです。

中間ニュースは、十分に文書化されていないということです。

悪いニュースは、一部のプラットフォームでしか機能しないことです。

その他の中間ニュースは、少なくともいくつかのプラットフォームで Tk の外に出ることができるということです。


Tcl/Tk でこれを行う方法は、 で<Motion>イベントを生成すること-warp 1です。これに関するドキュメントはまばらで、いくつかの異なるページ ( から開始) に散らばっていますbindが、詳細はここ で説明されています。基本的には、これだけです:

event generate . <Motion> -warp 1 -x 50 -y 50

では、Tkinter からこれを行うにはどうすればよいでしょうか。

まあ、event_generateどこにも文書化されておらず、<Motion>イベントもwarpパラメーターもありません...しかし、TkがTkinterにどのようにマップされるかを知っていれば、理解するのは非常に簡単です:

window.event_generate('<Motion>', warp=True, x=50, y=50)

binding でわかるように、これは実際にイベントを生成します<Motion>。簡単なテスト プログラムを次に示します。

from tkinter import *

root = Tk()

def key(event):
    root.event_generate('<Motion>', warp=True, x=50, y=50)

def motion(event):
    print('motion {}, {}'.format(event.x, event.y))

root.bind('<Key>', key)
root.bind('<Motion>', motion)
root.mainloop()

それを実行し、ウィンドウをクリックしてフォーカスがあることを確認し、カーソルを移動すると、次のような出力が表示されます。

motion 65, 69
motion 65, 70
motion 65, 71

次にキーを押すと、次のように出力されます。

motion 50, 50

これは素晴らしいことです... ただし、実際にはカーソルを移動できない場合があります。その場合、Tk をだましてカーソルが移動したと思わせるだけです。


さまざまなフォーラムをざっと見ると、次のようになります。

  • マック: 動作しません。
  • Windows: 通常は動作します。
    • Tk 8.4.something 以降が必要です。これに関するバグは見つかりませんでしたが、Python 2.7 または 3.x+ の公式の Windows バイナリ インストールで 8.4 を期待できます。
    • また、フルスクリーン アプリを実行していてはなりません (通常、Tk ではそうではありません)。
    • Vista以降では動作しない場合があります。これは、デスクトップ セッションを所有していないか、ローカル コンソール セッションではないことに関係している可能性があります。あるいは、管理者権限またはその他の権限が必要であることに関係している可能性があります。
    • それが機能しない場合は、Win32 API に直接アクセスするのは簡単です。
  • X11 (ほとんどの Linux、*BSD など): 通常
    • ウィンドウ マネージャーで、他のクライアントがポインターをゆがめるのを無効にしてはなりません。幸いなことに、それは一般的なことではないようです。
    • この問題が発生した場合、それを回避する方法はありません。
  • その他のプラットフォーム (iOS、Android など): わかりません。

Mac の場合、NSMouseMovedイベントを生成して送信します。これを行う簡単な方法はpyobjc次のとおりです (Apple の Python を使用している場合は組み込まれています。それ以外の場合は、インストールする必要があります)。

app = Foundation.NSApplication.sharedApplication()
event = Foundation.NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_(
    Foundation.NSMouseMoved, (50, 50), 0, 0,
    app.mainWindow().windowNumber(), None, 0, 0, 0.0)
app.sendEvent_(event)

Windows の場合、SetCursorPosAPI を呼び出すか、MOUSEEVENT を生成して送信します。前者は、たとえば DirectX ゲームでは機能しません。後者はリモート デスクトップでは機能しない場合があります。この場合、おそらく前者が必要です。いずれにせよ、これを行う最も簡単な方法は をインストールするpywin32ことです。

win32api.SetCursorPos((50, 50))
于 2013-05-23T01:43:28.057 に答える
1

カーソルを画面上の絶対位置に移動することに関心のある人向け (@abarnert の tkinter メソッドを使用):

# Moves the mouse to an absolute location on the screen
def move_mouse_to(x, y):
    # Create a new temporary root
    temp_root = tk.Tk()
    # Move it to +0+0 and remove the title bar
    temp_root.overrideredirect(True)
    # Make sure the window appears on the screen and handles the `overrideredirect`
    temp_root.update()
    # Generate the event as @abarnert did
    temp_root.event_generate("<Motion>", warp=True, x=x, y=y)
    # Make sure that tcl handles the event
    temp_root.update()
    # Destroy the root
    temp_root.destroy()

この関数は、他の tkinter ウィンドウに干渉してはなりません。この関数は、2 回更新される新しいウィンドウを作成するため、速度が遅くなり、作成されたウィンドウにユーザーが気付く可能性があることに注意してください。

于 2021-03-25T22:05:30.770 に答える