2013-05-23 11 views
7

Ho un programma di rendering 3d che ruota il mondo attorno a un osservatore in base alla posizione del mouse sullo schermo. La quantità in radianti che il mondo è ruotato è definito da questa lineaCome posso impostare la posizione del mouse in una finestra tkinter

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

Dove xy [0] è la coordinata x del centro dello schermo

Ciò significa che l'importo che il campo osservatori di la vista può essere ruotata è limitata dalla distanza del mouse. Se potessi riportare il mouse al centro dello schermo, potrei risolvere questo problema. Qualche idea?

+0

Invece di muovere il puntatore, forse rendere la posizione del controllo del puntatore la velocità * * con cui il mondo gira - più lontano dal centro più veloce è la rotazione. – unutbu

+0

Questo è un grande suggerimento di unetbu, e usavo questo schema di controllo, ma non è facile da usare come volevo, quindi voglio qualcosa di simile a come è controllato uno sparatutto in prima persona – sam

risposta

7

La buona notizia è che c'è un modo per farlo.

La notizia intermedia è che non è ben documentato.

La cattiva notizia è che funziona solo su alcune piattaforme.

Le altre notizie intermedie sono che è possibile uscire da Tk su almeno alcune piattaforme.


Il modo per fare questo in Tcl/Tk è generando un evento <Motion> con -warp 1. La documentazione su questo è scarsa, e sparsi su poche pagine diverse (inizia da bind), ma i dettagli sono descritti here. Fondamentalmente, è proprio questo:

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

Quindi, come si fa da Tkinter?

Beh, event_generate non è documentato da nessuna parte, e nessuno dei due è l'evento <Motion>, o il parametro warp ... ma è abbastanza semplice da capire se si sa come mappe Tk a Tkinter:

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

E questo in effetti genera un evento, come puoi vedere legando <Motion>. Ecco un semplice programma di test:

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() 

eseguirlo, fare clic sulla finestra per assicurarsi che questa è stata attivata, spostare il cursore, e vedrete che stampare qualcosa di simile:

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

poi premere un tasto, e sarà stampare questo:

motion 50, 50 

che è grande ... se non che non può effettivamente essere in grado di spostare il cursore, nel qual caso tutto questo non fa altro che trucco Tk a pensare il cursore mosso.


Da scrematura vari forum, sembra che:

  • Mac: non funziona.
  • Windows: in genere funziona.
    • È necessario disporre di Tk 8.4. Qualcosa o successivo. Non sono riuscito a trovare il bug per questo, ma puoi contare su 8.4 con qualsiasi installazione binario ufficiale di Windows di Python 2.7 o 3.x +.
    • Inoltre, non è possibile eseguire un'app a schermo intero (che in genere non lo è, con Tk).
    • Su Vista e versioni successive, in alcuni casi non funzionerà. Questo potrebbe avere qualcosa a che fare con il fatto di non possedere la sessione desktop o di non essere una sessione di console locale, o potrebbe avere a che fare con l'amministratore o altri privilegi.
    • Se non funziona, è facile andare direttamente all'API Win32.
  • X11 (la maggior parte di Linux, * BSD, ecc): Di solito
    • tuo window manager non deve avere altri clienti disabili dalla deformazione del puntatore. Fortunatamente, non sembra essere una cosa comune da fare.
    • Se si verifica questo problema, non c'è modo di aggirarlo.
  • Altre piattaforme (iOS, Android, ecc.): Nessuna idea.

Per Mac, si desidera generare e inviare un evento NSMouseMoved. Il modo più semplice per farlo è con pyobjc (che è costruito in se si sta utilizzando Python di Apple, in caso contrario è necessario installarlo):

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) 

Per Windows, che si desidera chiamare il SetCursorPos API, o generare e invia un MOUSEEVENT. Il primo non funzionerà con, ad esempio, giochi DirectX; quest'ultimo potrebbe non funzionare con i desktop remoti. Per questo caso, probabilmente vuoi il primo. In entrambi i casi, il modo più semplice per farlo è quello di installare pywin32, e poi è solo:

win32api.SetCursorPos((50, 50)) 
+0

Questo sta funzionando per io su Windows 7. – Tim

+0

@Tim: Great! Ho fatto un po 'più di ricerca; lascia che aggiorni le cose. – abarnert

+0

Funziona come un fascino abernart! C'è un modo per farlo senza premere un tasto? il più vicino che ho ottenuto è quello di mettere la funzione root.event_generate nell'evento di movimento del mouse, ma che si aggiorna piuttosto lentamente – sam

Problemi correlati