我有一个 3d 渲染程序,它根据鼠标在屏幕上的位置围绕观察者旋转世界。世界旋转的弧度值由这条线定义
glob.worldx=-(w.winfo_pointerxy()[0]-xy[0])/250
其中 xy[0] 是屏幕中心的 x 坐标
这意味着观察者视野可以旋转的量受到鼠标可以移动的距离的限制。如果我能让鼠标回到屏幕中心,我就能解决这个问题。有任何想法吗?
好消息是有办法做到这一点。
中间消息是它没有很好的记录。
坏消息是它只适用于某些平台。
另一个中间消息是,您至少可以在某些平台上跳出 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 认为光标移动了。
从浏览各种论坛,它看起来像:
对于 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,您想要调用SetCursorPos
API,或者生成并发送 MOUSEEVENT。前者不适用于 DirectX 游戏等;后者可能不适用于远程桌面。对于这种情况,您可能需要前者。无论哪种方式,最简单的方法是安装pywin32
,然后就是:
win32api.SetCursorPos((50, 50))
对于任何有兴趣将光标移动到屏幕上的绝对位置的人(使用@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 窗口。请注意,此函数会创建一个刷新两次的新窗口,因此它可能会很慢并且用户可能会注意到创建的窗口。