且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在Tkinter窗口中设置鼠标位置

更新时间:2023-12-03 15:21:46

好消息是,有一种方法可以实现.

The good news is that there is a way to do it.

中间的消息是,它没有得到很好的记录.

The intermediate news is that it's not well documented.

坏消息是它仅在某些平台上有效.

The bad news is that it only works on some platforms.

另一个中间消息是,您至少可以在某些平台上走出Tk.

The other intermediate news is that you can step outside of Tk on at least some platforms.

在Tcl/Tk中执行此操作的方法是使用-warp 1生成一个<Motion>事件.有关此文档的文档很少,并且散布在几个不同的页面上(从开始bind ),但在此处中进行了详细说明.基本上就是这样:

The way to do this in Tcl/Tk is by generating a <Motion> event with -warp 1. The documentation on this is sparse, and scattered around a few different pages (start at bind), but the details are described here. Basically, it's just this:

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

那么,您如何从Tkinter做到这一点?

So, how do you do this from Tkinter?

好吧,event_generate在任何地方都没有记录,<Motion>事件或warp参数都没有……但是很容易弄清楚是否知道Tk如何映射到Tkinter:

Well, event_generate isn't documented anywhere, and neither is the <Motion> event, or the warp parameter… but it's pretty simple to figure out if you know how Tk maps to Tkinter:

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

这确实会生成一个事件,如通过绑定<Motion>可以看到的.这是一个简单的测试程序:

And this does indeed generate an event, as you can see by binding <Motion>. Here's a simple test program:

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

运行它,单击窗口以确保它具有焦点,将光标四处移动,您会看到它打印出如下内容:

Run it, click the window to make sure it has focus, move the cursor around, and you'll see it print out something like this:

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

然后按下一个键,它将打印出以下内容:

Then hit a key, and it'll print out this:

motion 50, 50

这很不错……除了它实际上可能无法移动光标之外,在这种情况下,所有这一切都使Tk误以为光标已经移动了.

Which is great… except that it may not actually be able to move your cursor, in which case all this does is trick Tk into thinking the cursor moved.

通过浏览各种论坛,看起来像:

From skimming various forums, it looks like:

  • Mac:不起作用.
    • Mac: Does not work.
      • You must have Tk 8.6.something or later (see issue 2926819). And you probably have 8.5.something.
      • But it's not hard to go right to the Cocoa API.
      • 您必须拥有Tk 8.4.some或更高版本.我找不到此错误,但您可以指望8.4使用Python 2.7或3.x +的任何官方Windows二进制安装.
      • 您也一定不能运行全屏应用程序(使用Tk时通常不可以).
      • 在Vista和更高版本上,在某些情况下它将无法正常工作.这可能与不拥有桌面会话或不是本地控制台会话有关,或者与需要管理员或其他特权有关.
      • 如果它不起作用,很容易直接转到Win32 API.
      • 您的窗口管理器一定不能禁止其他客户端扭曲指针.幸运的是,这似乎并不常见.
      • 如果您遇到此问题,则无法解决.

      对于Mac,您要生成并发送

      For Mac, you want to generate and send an NSMouseMoved event. The easy way to do this is with pyobjc (which is built in if you're using Apple's Python; otherwise you have to install it):

      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 ,然后就可以了:

      For Windows, you want to call the SetCursorPos API, or generate and send a MOUSEEVENT. The former will not work with, e.g., DirectX games; the latter may not work with remote desktops. For this case, you probably want the former. Either way, the easiest way to do this is to install pywin32, and then it's just:

      win32api.SetCursorPos((50, 50))