在使用PyGame时处理KeyboardInterrupt
我写了一个小的Python应用程序,使用PyGame来显示一些简单的图形。
在我的应用程序中,有一个比较简单的PyGame循环,像这样:
stopEvent = Event()
# Just imagine that this eventually sets the stopEvent
# as soon as the program is finished with 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()
这个循环在正常情况下运行得很好;如果PyGame窗口被关闭,应用程序就会关闭;如果应用程序完成了它的任务,应用程序也会关闭。
我遇到的问题是,如果我在Python控制台按下Ctrl-C,应用程序会抛出一个KeyboardInterrupt
,但是它仍然继续运行。
所以我的问题是:我在更新循环中做错了什么,怎么才能让KeyboardInterrupt
导致应用程序终止呢?
2 个回答
2
补充一下Alex的回答,你可能想要对所有异常都这样处理,这样可以确保如果主线程因为任何原因失败,线程会被关闭,而不仅仅是因为键盘中断。
你还需要把异常处理的部分移到外面,以避免竞争条件。比如,在调用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()
在finally中这样做会更清晰:你可以立刻看出,无论你怎么退出这个代码块,事件总是会被设置。(我假设设置事件两次是没问题的。)
如果你不想在键盘错误时显示堆栈跟踪,你应该捕获这个错误并处理掉,但要确保只在最外层的代码中这样做,以确保异常能够完全传播出去。
3
你可以考虑把最后的循环改成这样:
while not stopEvent.isSet():
try:
for event in pygame.event.get():
if event.type == pygame.QUIT:
stopEvent.set()
except KeyboardInterrupt:
stopEvent.set()
也就是说,要确保你能捕捉到键盘中断,并把它们当作退出事件来处理。