-1

I borrowed some code from another thread I found on this website, but when I tried to form a program around it, I found that it can only be used once. Repeated code doesn't work.

import tkinter as tk

def keyDetect(event):
    root.destroy()
    if event.char == event.keysym:
        print(event.char)
    elif len(event.char) == 1:
        print(event.keysym, event.char)
    else:
        print(event.keysym)


root = tk.Tk()
root.bind_all('<Key>', keyDetect)
root.withdraw()
root.mainloop()

print('1')
root = tk.Tk()
root.bind_all('<Key>', keyDetect)
print('2')
root.withdraw()
print('3')
root.mainloop()
print('4')

Using the 4 prints above shows where the problem is, "3" is printed but "4" isn't.

Community
  • 1
  • 1
Toby Smith
  • 1,505
  • 2
  • 15
  • 24

1 Answers1

2

Calling Tk.mainloop() starts Tkinter's main event loop. This is an infinite loop that will continue until the main window is destroyed (closed). So, your program will not execute any lines following root.mainloop() until the loop exits.

An analogy would be:

print('3')
while True:
    pass
print('4')

Note however that Tkinter's loop is doing a lot more than just passing. It is handling events, keeping the main window open, etc.

  • Yes, the loop will be exited by destroying the main window. This can be accomplished by doing `root.quit()`. –  Jan 16 '15 at 23:43
  • I added `root.quit()` after `root.mainloop()` but nothing changed. Is that what you meant? – Toby Smith Jan 16 '15 at 23:47
  • No, not exactly. Like I said in my answer, the lines after `root.mainloop()` will not be executed until the loop exits. In order to do what you want, you would need to hook `root.quit` up to a button or do `root.after(1, root.quit)` just before you call `root.mainloop()`. But I don't know why you are destroying the window just after you create it. If you don't need the window just yet, then simply don't call `root.mainloop()` until you are ready for it. –  Jan 16 '15 at 23:51
  • Hmm, ok. Well how would you use tkinter (or anything else) to detect keystrokes in more than one place? – Toby Smith Jan 16 '15 at 23:59
  • 1
    I'm not sure what you mean by that. If you need multiple windows, you can use the [`Toplevel`](http://effbot.org/tkinterbook/toplevel.htm) class to create children windows. Or, if you need multiple instances of your program, you can have another Python script launch them in a loop. If you are trying to build a global keyboard hook however, that is a lot more involved. You can find some info [here](http://effbot.org/tkinterbook/toplevel.htm) and you may want to check out [pyHook](https://pypi.python.org/pypi/pyHook). –  Jan 17 '15 at 00:06
  • What about `root.destroy()` in there? It's not infinite then –  Jan 17 '15 at 00:09
  • 1
    @Defalt - `root.destroy()` never gets executed because the OP is calling `root.withdraw()`. This hides the main window, so it will never receive any key press events. If the `root.withdraw()` lines are removed, the program will no longer run continuously because you can destroy the windows by clicking a key when they have focus. –  Jan 17 '15 at 00:15