树莓派Python投票游戏界面停留与GPIO按键响应问题求助
问题原因
你现在的代码有3个核心错误,直接导致页面停留、按键响应逻辑失效:
- 把整个游戏流程全写在了GPIO中断回调函数里:RPi.GPIO的事件回调运行在独立子线程,和pygame的主线程UI渲染存在线程冲突,而且回调里嵌套多层无退出条件的
while True死循环,会直接打乱正常的页面流转顺序 - 用了不存在的API:RPi.GPIO没有
BUTTON_1.is_pressed这种调用方式,读取引脚电平必须用GPIO2.input(引脚编号)方法 - 页面等待逻辑没有阻塞控制:你写的等待按键的循环没有正确的跳出判断,跑起来之后会直接滑过所有页面,没法停在投票页等输入
修复思路
不要在GPIO中断回调里写任何UI、流程跳转逻辑,回调只负责做「按键被按下」的标记。所有页面渲染、状态跳转全放在pygame主线程实现,用状态机标记当前所处的页面阶段,每个阶段只做对应操作:
- 介绍页状态:持续渲染介绍页,检测到任意按键按下就切到第一题投票状态
- 投票页状态:持续渲染当前投票题页面,检测到对应按键按下就更新投票计数,切到单题结果状态
- 单题结果状态:渲染当前题的投票结果,停留固定时长后自动切到下一题投票状态;如果已经是最后一题就切到总榜状态
- 总榜状态:渲染全量统计结果,停留固定时长后自动切回介绍页状态
修复后的代码框架
import RPi.GPIO as GPIO2 import time import pygame # 硬件配置 BUTTON_1 = 3 BUTTON_2 = 5 BOUNCE_TIME = 200 GPIO2.setmode(GPIO2.BOARD) GPIO2.setup(BUTTON_1, GPIO2.IN, pull_up_down=GPIO2.PUD_UP) GPIO2.setup(BUTTON_2, GPIO2.IN, pull_up_down=GPIO2.PUD_UP) # pygame初始化 pygame.init() WIDTH = 1900 HEIGHT = 1000 display = pygame.display.set_mode((WIDTH, HEIGHT)) clock = pygame.time.Clock() # 资源加载 intro = pygame.image.load('intro.png') voting_pages = [pygame.image.load('voting1.png')] # 后续可以加voting2.png、voting3.png... result_show_time = 3000 # 单题结果停留3秒,单位毫秒 final_show_time = 5000 # 总榜停留5秒,单位毫秒 # 全局状态标记 key_pressed = None # 取值:None/BUTTON_1/BUTTON_2 current_state = "INTRO" # 状态:INTRO/VOTING/RESULT/FINAL current_vote_index = 0 state_start_tick = 0 vote_counts = [] # 存每道题两个选项的票数 # 按键回调:只做按键标记,不写任何业务逻辑 def button_callback(channel): global key_pressed # 消抖判断,确保按键是按下状态 if GPIO2.input(channel) == GPIO2.LOW: key_pressed = channel GPIO2.add_event_detect(BUTTON_1, GPIO2.FALLING, callback=button_callback, bouncetime=BOUNCE_TIME) GPIO2.add_event_detect(BUTTON_2, GPIO2.FALLING, callback=button_callback, bouncetime=BOUNCE_TIME) try: while True: # 处理pygame内置退出事件 for event in pygame.event.get(): if event.type == pygame.QUIT: raise KeyboardInterrupt # 清空画布 display.fill((125,125,125)) # 状态机流转 if current_state == "INTRO": # 渲染介绍页 display.blit(intro, (0,0)) # 检测到任意按键,切到第一题投票 if key_pressed in (BUTTON_1, BUTTON_2): key_pressed = None current_vote_index = 0 vote_counts = [[0,0] for _ in voting_pages] current_state = "VOTING" state_start_tick = pygame.time.get_ticks() elif current_state == "VOTING": # 渲染当前投票题页面 display.blit(voting_pages[current_vote_index], (0,0)) # 检测投票按键 if key_pressed == BUTTON_1: key_pressed = None vote_counts[current_vote_index][0] += 1 # 这里加渲染第一题选1的结果页逻辑 current_state = "RESULT" state_start_tick = pygame.time.get_ticks() elif key_pressed == BUTTON_2: key_pressed = None vote_counts[current_vote_index][1] += 1 # 这里加渲染第一题选2的结果页逻辑 current_state = "RESULT" state_start_tick = pygame.time.get_ticks() elif current_state == "RESULT": # 这里放你已经调试好的单题结果渲染逻辑 # 停留时间到了就跳转 if pygame.time.get_ticks() - state_start_tick >= result_show_time: current_vote_index += 1 if current_vote_index >= len(voting_pages): # 所有题投完,切总榜 current_state = "FINAL" else: # 切下一题 current_state = "VOTING" state_start_tick = pygame.time.get_ticks() elif current_state == "FINAL": # 这里放你已经调试好的高分榜/总统计结果渲染逻辑 # 停留时间到了切回介绍页 if pygame.time.get_ticks() - state_start_tick >= final_show_time: current_state = "INTRO" state_start_tick = pygame.time.get_ticks() # 更新显示,控制帧率60,避免CPU占满 pygame.display.update() clock.tick(60) except KeyboardInterrupt: GPIO2.cleanup() pygame.quit()
注意事项
- 按键接线要对应上拉/下拉配置,代码里开了内部上拉,按键要接在GPIO引脚和GND之间,按下时引脚读低电平,如果你是接3.3V的话改下输入检测逻辑就行
- 你之前调试好的计数、文本渲染逻辑,直接对应填到RESULT和FINAL状态的渲染位置即可,不需要改动原有逻辑
- 所有和pygame显示、更新相关的代码全放在主线程的循环里,不要放到子线程或者回调里,不然会出现随机的显示崩溃问题
内容的提问来源于stack exchange,提问作者chawancut
相关产品推荐
相关产品推荐

