Handling KeyboardInterrupt when working with PyGame
I have written a small Python application where I use PyGame for displaying some simple graphics.
I have a somewhat simple PyGame loop going in the base of my application, like so:
stopEvent = Event()
# Just imagine that this eventually sets the stopEvent
# as soon as the program is finished with开发者_Python百科 its task.
disp = SortDisplay(algorithm, stopEvent)
def update():
""" Update loop; updates the screen every few seconds. """
while True:
stopEvent.wait(options.delay)
disp.update()
if stopEvent.isSet():
break
disp.step()
t = Thread(target=update)
t.start()
while not stopEvent.isSet():
for event in pygame.event.get():
if event.type == pygame.QUIT:
stopEvent.set()
It works all fine and dandy for the normal program termination; if the PyGame window gets closed, the application closes; if the application finishes its task, the application closes.
The trouble I'm having is, if I Ctrl-C in the Python console, the application throws a KeyboardInterrupt
, but keeps on running.
The question would therefore be: What have I done wrong in my update loop, and how do I rectify it so a KeyboardInterrupt
causes the application to terminate?
What about changing your final loop to...:
while not stopEvent.isSet():
try:
for event in pygame.event.get():
if event.type == pygame.QUIT:
stopEvent.set()
except KeyboardInterrupt:
stopEvent.set()
i.e., make sure you catch keyboard interrupts and treat them just the same as a quit event.
Amending Alex's answer, note that you probably want to do this on all exceptions, to ensure that you shut down the thread if the main thread fails for any reason, not just KeyboardInterrupt.
You also need to move the exception handler out, to avoid race conditions. For example, there might be a KeyboardInterrupt while calling stopEvent.isSet().
try:
t = Thread(target=update)
t.start()
while not stopEvent.isSet():
for event in pygame.event.get():
if event.type == pygame.QUIT:
stopEvent.set()
finally:
stopEvent.set()
Doing this in finally makes it clearer: you can tell immediately that the event will always be set regardless of how you exit this code block. (I'm assuming setting the event twice is harmless.)
If you don't want to show a stack trace on KeyboardError you should catch it and swallow it, but be sure to do that only in your outermost code to be sure the exception is propagated out fully.
精彩评论