39

Is there a way to get the position of the mouse and set it as a var?

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Kyle Pfromer
  • 1,485
  • 1
  • 15
  • 26

4 Answers4

50

You could set up a callback to react to <Motion> events:

import Tkinter as tk
root = tk.Tk()

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

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

I'm not sure what kind of variable you want. Above, I set local variables x and y to the mouse coordinates.

If you make motion a class method, then you could set instance attributes self.x and self.y to the mouse coordinates, which could then be accessible from other class methods.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Could i return it as a var? – Kyle Pfromer Apr 08 '14 at 01:07
  • Well, nothing receives the return value of the callback, so it would not be useful to return it from `motion`. – unutbu Apr 08 '14 at 01:11
  • Could i set the x,y as a var in the function? – Kyle Pfromer Apr 08 '14 at 01:14
  • Get the following error with above script tkinter.TclError: no display name and no $DISPLAY environment variable – Bachalo Jul 03 '14 at 13:59
  • The problem with this is that if you're trying to use `self.x` and `self.y` in another event handler, it'll be the mouse position at the time of the previous event, which could be off by quite a distance. If the current event doesn't have pointer position, I think Bryan Oakley's answer is a better solution. – abarnert Nov 26 '14 at 19:43
47

At any point in time you can use the method winfo_pointerx and winfo_pointery to get the x,y coordinates relative to the root window. To convert that to absolute screen coordinates you can get the winfo_pointerx or winfo_pointery, and from that subtract the respective winfo_rootx or winfo_rooty

For example:

root = tk.Tk()
...
x = root.winfo_pointerx()
y = root.winfo_pointery()
abs_coord_x = root.winfo_pointerx() - root.winfo_rootx()
abs_coord_y = root.winfo_pointery() - root.winfo_rooty()
Chris Emerson
  • 13,041
  • 3
  • 44
  • 66
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • This is handy when you want to fetch the tab_id of a ttk::notebook tab that was clicked on from inside of a toplevel grab (the notebook is external to the toplevel widget). – Kumba Jun 29 '17 at 03:29
  • 1
    This seems to be the better answer. – Haboryme Jul 02 '17 at 16:57
  • 7
    It seems relative and absolute coords are mixed up – jfs Apr 02 '18 at 21:21
  • I think this is a better solution for making tooltips that will appear after 1 seconds in mouse pointer's coordinates. Bind solution gets the first coordinates of mouse when moved and waits 1 seconds. Even if mouse was moved to somewhere else, tooltip is appearing in first position. – Yılmaz Alpaslan Jun 03 '21 at 18:11
6

I would like to improve Bryan's answer, as that only works if you have 1 monitor, but if you have multiple monitors, it will always use your coordinates relative to your main monitor. in order to find it relative to both monitors, and get the accurate position, then use vroot, instead of root, like this

root = tk.Tk()
...
x = root.winfo_pointerx()
y = root.winfo_pointery()
abs_coord_x = root.winfo_pointerx() - root.winfo_vrootx()
abs_coord_y = root.winfo_pointery() - root.winfo_vrooty()
Tyler Silva
  • 411
  • 6
  • 14
  • I don't know if it's that I don't have a second monitor, but `.winfo_vrootx()` and `.winfo_vrooty()` both report 0, no matter where my mouse is. Should I combine this with `.winfo_rootx()` and `.winfo_rootx()`? – ego-lay atman-bay May 06 '23 at 02:50
5

Personally, I prefer to use pyautogui, even in combination with Tkinter. It is not limited to Tkinter app, but works on the whole screen, even on dual screen configuration.

    import pyautogui
    x, y = pyautogui.position()

In case you want to save various positions, add an on-click event.
I know original question is about Tkinter.

JOM
  • 51
  • 1
  • 2