2013-05-23 3 views
7

У меня есть программа 3D-рендеринга, которая вращает мир вокруг наблюдателя в зависимости от положения мыши на экране. Сумма в радианах, что мир вращается определяются этой линиейКак установить положение мыши в окне tkinter

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

Где х [0] является х координатами центра экрана

Это означает, что сумма, которую поле наблюдателей от вид может вращаться ограниченным расстоянием мыши. Если бы я мог заставить мышь вернуться в центр экрана, я мог бы решить эту проблему. Есть идеи?

+0

Вместо перемещения указателя, возможно, сделать положение элемента управления Пиковые * скорость *, с которой мир вращается - чем дальше от центра, тем быстрее вращение. – unutbu

+0

Это отличное предложение unetbu, и я использовал эту схему управления, но это не так удобно, как хотелось бы, поэтому мне нужно что-то похожее на то, как управляется игра с шутер от первого лица. – sam

ответ

7

Хорошей новостью является то, что есть способ сделать это.

Промежуточная новость заключается в том, что она плохо документирована.

Плохая новость заключается в том, что она работает только на некоторых платформах.

Другая промежуточная новость заключается в том, что вы можете выйти за пределы Tk по крайней мере на некоторых платформах.


Способ сделать это в Tcl/Tk является путем генерации <Motion> события с -warp 1. Документация по этому вопросу разрежена и разбросана по нескольким страницам (начинаются с bind), но детали описаны here. В основном это:

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) 

И это действительно генерирует событие, как вы можете видеть, привязывая <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 думать, курсор переехал.


С скользя различных форумов, это выглядит следующим образом:

  • Mac: Не работает.
  • Windows: Обычно работает.
    • У вас должен быть Tk 8.4.something или более поздний. Я не мог найти ошибку для этого, но вы можете рассчитывать на 8.4 с любой официальной бинарной установкой Windows для Python 2.7 или 3.x +.
    • Вы также не должны запускать полноэкранное приложение (которого вы обычно не используете, с Tk).
    • В Vista и позже, в некоторых случаях это не сработает. Это может иметь какое-то отношение к тому, чтобы не иметь сеанс рабочего стола или не являться сеансом локальной консоли, или, возможно, это связано с необходимостью использования Администратора или других привилегий.
    • Если это не сработает, легко перейти к API Win32.
  • X11 (большинство Linux, * BSD и т.д.): Обычно
    • Ваш оконный менеджер не должен иметь инвалид других клиентов коробления указателя. К счастью, это не похоже на обычное дело.
    • Если у вас есть эта проблема, ее нет.
  • Другие платформы (iOS, Android и т. Д.): Понятия не имею.

Для Mac вы хотите сгенерировать и отправить событие NSMouseMoved. Самый простой способ сделать это с pyobjc (который построен, если вы используете Python от Apple, в противном случае вы должны установить его):

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, вы хотите, чтобы вызвать SetCursorPos API, или генерировать и отправить MOUSEEVENT. Первый не будет работать, например, в играх DirectX; последний может не работать с удаленными рабочими столами. Для этого случая вам, вероятно, нужен первый. В любом случае, самый простой способ сделать это, чтобы установить pywin32, а затем это просто:

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

Это работает для меня в Windows 7. – Tim

+0

@Tim: Отлично! Я сделал немного больше исследований; позвольте мне обновить вещи. – abarnert

+0

Работает как очарование abernart! Есть ли способ сделать это без нажатия клавиши? самое близкое, что я получил, - это положить функцию root.event_generate в событие движения мыши, но это довольно медленно обновляется. – sam

Смежные вопросы