Pygame时钟应用窗口关闭异常问题排查及解决方案咨询
Python模拟时钟窗口关闭异常解决方案
问题根源
你的代码中clock_hands函数包含一个无限while True循环,且内部使用time.sleep(1)阻塞程序。当点击时区按钮后,这个嵌套循环会抢占程序控制权,导致主循环无法处理pygame.QUIT事件,最终引发系统异常。
修复方案
重构代码,将指针更新逻辑整合到主事件循环中,用Pygame的时间机制替代time.sleep,确保事件始终能被处理:
修改后的完整代码
import pygame import sys import math from datetime import datetime import pytz size = 500 pygame.init() screen = pygame.display.set_mode((size, size)) pygame.display.set_caption("CLOCK") font = pygame.font.SysFont("Arial", 20) clock = pygame.time.Clock() FPS = 60 # 初始化时区时间 tz_London = pytz.timezone("Europe/London") datetime_London = datetime.now(tz_London) starting_hour_London = int(datetime_London.strftime("%H")) now = datetime.now() starting_hour_Warsaw = int(now.strftime("%H")) starting_minute = int(now.strftime("%M")) starting_second = int(now.strftime("%S")) # 计算初始角度 angle_second = int(((starting_second/60) * 360) - 90) angle_minute = ((starting_minute/60) * 360) - 90 angle_hour_Warsaw = None angle_hour_London = None if starting_hour_Warsaw in range(0, 12): angle_hour_Warsaw = ((starting_hour_Warsaw/12) * 360 + (starting_minute * 0.5) + (starting_second * (1/120))) - 90 else: angle_hour_Warsaw = (((starting_hour_Warsaw - 12) / 12) * 360 + (starting_minute * 0.5) + (starting_second * (1 / 120))) - 90 if starting_hour_London in range(0, 12): angle_hour_London = ((starting_hour_London / 12) * 360 + (starting_minute * 0.5) + (starting_second * (1 / 120))) - 90 else: angle_hour_London = (((starting_hour_London - 12) / 12) * 360 + (starting_minute * 0.5) + (starting_second * (1 / 120))) - 90 # 当前选中的时区角度 current_tz_angle = None def drawing_clock(): screen.fill((0, 0, 0)) pygame.draw.circle(screen, (255, 0 ,0), (size/2, size/2), 200, 10) lenght = 190 offset = 150 starting_pos = (size/2,size/2) angles = [0, 90, 180, 270] # 绘制刻度 for angle in angles: x = starting_pos[0] + int(math.cos(math.radians(angle))) * lenght y = starting_pos[1] + int(math.sin(math.radians(angle))) * lenght pygame.draw.line(screen, (255, 0, 0), starting_pos, (x, y), 10) for angle in angles: x = starting_pos[0] + int(math.cos(math.radians(angle))) * offset y = starting_pos[1] + int(math.sin(math.radians(angle))) * offset pygame.draw.line(screen, (0, 0, 0), starting_pos, (x, y), 10) angles_2 = [30,60, 120, 150, 210, 240, 300, 330] for angle in angles_2: x = starting_pos[0] + math.cos(math.radians(angle)) * lenght y = starting_pos[1] + math.sin(math.radians(angle)) * lenght pygame.draw.line(screen, (255, 0, 0), starting_pos, (x, y), 5) for angle in angles_2: x = starting_pos[0] + math.cos(math.radians(angle)) * (offset+25) y = starting_pos[1] + math.sin(math.radians(angle)) * (offset+25) pygame.draw.line(screen, (0, 0, 0), starting_pos, (x, y), 10) # 绘制按钮 pygame.draw.circle(screen, (255, 0, 0), (size / 8, size / 8), 40, 5) pygame.draw.circle(screen, (255, 0, 0), ((size / 8)*7, size / 8), 40, 5) button_London = font.render("London", False, (255, 255, 255)) button_London_rect = button_London.get_rect(center = (size/8, size/8)) screen.blit(button_London, button_London_rect) button_Warsaw = font.render("Warsaw", False, (255, 255, 255)) button_Warsaw_rect = button_Warsaw.get_rect(center = ((size/8)*7, size/8)) screen.blit(button_Warsaw, button_Warsaw_rect) def draw_clock_hands(): global angle_second, angle_minute, current_tz_angle lenght_sec = 180 lenght_min = 150 lenght_hours = 120 start_pos = (size/2, size/2) # 绘制秒针 x = start_pos[0] + math.cos(math.radians(angle_second)) * lenght_sec y = start_pos[1] + math.sin(math.radians(angle_second)) * lenght_sec pygame.draw.line(screen, (255, 0, 0), start_pos, (x, y), 5) # 绘制分针 x_2 = start_pos[0] + math.cos(math.radians(angle_minute)) * lenght_min y_2 = start_pos[1] + math.sin(math.radians(angle_minute)) * lenght_min pygame.draw.line(screen, (0, 255, 0), start_pos, (x_2, y_2), 5) # 绘制时针(如果选中时区) if current_tz_angle is not None: x_3 = start_pos[0] + math.cos(math.radians(current_tz_angle)) * lenght_hours y_3 = start_pos[1] + math.sin(math.radians(current_tz_angle)) * lenght_hours pygame.draw.line(screen, (0, 0, 255), start_pos, (x_3, y_3), 5) # 记录上次更新秒针的时间 last_second_update = pygame.time.get_ticks() while True: current_time = pygame.time.get_ticks() # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.MOUSEBUTTONDOWN: x, y = pygame.mouse.get_pos() # 检测伦敦按钮点击 if (size/8)-20 < x < (size/8)+20 and (size/8)-20 < y < (size/8)+20: current_tz_angle = angle_hour_London # 检测华沙按钮点击 elif ((size/8)*7)-20 < x < ((size/8)*7)+20 and (size/8)-20 < y < (size/8)+20: current_tz_angle = angle_hour_Warsaw # 每秒更新一次指针 if current_time - last_second_update >= 1000: angle_second += 6 if angle_second >= 360: angle_second = 0 angle_minute += 0.1 if angle_minute >= 360: angle_minute = 0 if current_tz_angle is not None: current_tz_angle += (30/3600) if current_tz_angle >= 360: current_tz_angle = 0 last_second_update = current_time # 重绘整个界面 drawing_clock() draw_clock_hands() pygame.display.update() clock.tick(FPS)
关键修改说明
- 移除嵌套循环:将
clock_hands中的无限循环逻辑整合到主循环,确保事件处理不被阻塞 - 替换time.sleep:用
pygame.time.get_ticks()追踪时间间隔,实现非阻塞式的每秒更新 - 全屏重绘:每次循环重新绘制整个时钟背景,替代手动擦除指针的复杂逻辑,避免画面残留
- 状态化管理:用
current_tz_angle变量维护当前选中的时区状态,无需单独函数启动循环 - 完善退出逻辑:确保
pygame.quit()在退出前被调用,释放资源
内容的提问来源于stack exchange,提问作者Kamil Gryboś
相关产品推荐
相关产品推荐

