Python - Check for keypresses without using 100% cpu Python - Check for keypresses without using 100% cpu tkinter tkinter

Python - Check for keypresses without using 100% cpu


You want to catch key events, instead of polling for the current keyboard state.

See Events and Bindings in the TkInter docs, which has a simple example that does exactly what you want (plus, it's cross-platform instead of Win32-only).

And this is generally an issue with all GUI programming (and network servers, for that matter), and the answer is always the same. You don't directly use non-blocking "check for current X status" calls usefully, with or without threads. In the main thread, you ask the event loop "call my function when X status changes", or you create a background thread and make a blocking "wait forever until X happens" call.

The Wikipedia page on Event loop actually has a pretty good description of this.


Looking at your edited version, you've got a completely new problem now:

class Application(Frame):    def __init__(self, master=None):        Frame.__init__(self, master)        self.pack()        coords = StringVar()        Label(master=self, textvariable=coords).pack()        def GetCoords():            coords.set(str(win32api.GetCursorPos()))        root.bind_all("<Scroll_Lock>", self.GetCoords)

GetCoords is a local function defined inside Application.__init__. But you're trying to use it as if it were a method of Application. You can't do self.GetCoords unless GetCoords is a method of self. That's exactly what the error message AttributeError: Application instance has no attribute 'GetCoords' means.

But you can just pass the local function GetCoords, just by taking out the self. prefix. I'm not sure this will do what you think (because I'm not sure whether you can close over a StringVar like that or not), but… try it and see.

Alternatively, you can make GetCoords a method just by moving it out of the def __init__ and giving it a self parameter. Then you can access self.GetCoords, and get a bound method, which you can pass exactly as you're trying to. However, in that case, it won't be able to access coords anymore, since that's a local variable inside __init__. To fix that, change that local variable into a member variable, by using self.coords everywhere in __init__ and GetCoords (and anywhere else) instead of coords.