Python控制台交互式菜单选中项重复Bug排查求助
控制台菜单重复选中项Bug排查与修复
问题重现
操作步骤:
- 下移至第4项(counter值为3)
- 按Enter键切换到shop状态
- 在shop状态下移至第5项(counter值为4)
- 按Enter键切回play状态
- 按向下箭头
实际显示结果:
TOSHOP > TOSHOP < TOSHOP > TOSHOP <
预期显示结果:
TOSHOP > TOSHOP < TOSHOP TOSHOP
相关代码
main.py
import keyboard import ui import os os.system("cls") ui.play[ui.counter] = "> " + ui.play[ui.counter] + " <" ui.navmenuprint(ui.play) while True: while ui.state == "play": keypressed = keyboard.read_key() while keyboard.is_pressed("down"): pass while keyboard.is_pressed("up"): pass while keyboard.is_pressed("enter"): pass if keypressed == "up": os.system("cls") ui.navup(ui.play, ui.play2) ui.navmenuprint(ui.play) if keypressed == "down": os.system("cls") ui.navdown(ui.play, ui.play2) ui.navmenuprint(ui.play) if keypressed == "enter": if ui.counter == 0: ui.switchstate("shop") if ui.counter == 1: ui.switchstate("shop") if ui.counter == 2: ui.switchstate("shop") if ui.counter == 3: ui.switchstate("shop") while ui.state == "shop": keypressed = keyboard.read_key() while keyboard.is_pressed("down"): pass while keyboard.is_pressed("up"): pass while keyboard.is_pressed("enter"): pass if keypressed == "up": os.system("cls") ui.navup(ui.shop, ui.shop2) ui.navmenuprint(ui.shop) if keypressed == "down": os.system("cls") ui.navdown(ui.shop, ui.shop2) ui.navmenuprint(ui.shop) if keypressed == "enter": if ui.counter == 0: ui.switchstate("play") if ui.counter == 1: ui.switchstate("play") if ui.counter == 2: ui.switchstate("play") if ui.counter == 3: ui.switchstate("play") if ui.counter == 4: ui.switchstate("play")
ui.py
import os from termcolor import cprint state = "play" counter = 0 play = ["TOSHOP", "TOSHOP", "TOSHOP","TOSHOP"] play2 = ["TOSHOP", "TOSHOP", "TOSHOP","TOSHOP"] shop = ["TOPLAY", "TOPLAY","TOPLAY","TOPLAY","TOPLAY"] shop2 = ["TOPLAY", "TOPLAY","TOPLAY","TOPLAY","TOPLAY"] def switchstate(fromwhere): global state, counter if fromwhere == "play": counter = 0 state = fromwhere play = play2.copy() os.system("cls") play[counter] = "> " + play[counter] + " <" navmenuprint(play) if fromwhere == "shop": counter = 0 state = fromwhere shop = shop2.copy() os.system("cls") shop[counter] = "> " + shop[counter] + " <" navmenuprint(shop) def navup(list1, list2): global counter if counter != 0: list1[counter] = list2[counter] counter -= 1 list1[counter] = "> " + list1[counter] + " <" else: list1[counter] = list2[counter] counter -= 1 list1[counter] = "> " + list1[counter] + " <" counter = len(list1) - 1 print (counter) def navdown(list1,list2): global counter if counter != len(list1) - 1: list1[counter] = list2[counter] counter += 1 list1[counter] = "> " + list1[counter] + " <" else: list1[counter] = list2[counter] counter = 0 list1[counter] = "> " + list1[counter] + " <" print (counter) def navmenuprint(list): global counter for i in list: print(i)
Bug原因分析
- 全局列表未被正确重置:
switchstate函数中修改play和shop时,未将其声明为全局变量,导致函数内创建了局部变量,而非修改全局的列表实例。全局列表仍保留之前操作添加的选中标记(> TOSHOP <),切换回play状态后,新的选中标记与旧标记叠加,出现重复。 - 状态切换逻辑错误:
switchstate函数中,state = fromwhere的赋值逻辑完全错误——比如从play切换到shop时,应该将state设为"shop"而非传入的fromwhere参数值,导致状态切换失效,进一步加剧了列表状态的混乱。 - navup函数存在索引逻辑错误:当
counter为0时,代码先将其减至-1再赋值,虽Python允许负索引,但不符合循环到列表末尾的预期逻辑,存在潜在风险。
修复方案
1. 修正switchstate函数的全局变量声明与状态赋值
def switchstate(target_state): global state, counter, play, shop # 声明要修改的全局变量 counter = 0 state = target_state # 直接设置为目标状态 if target_state == "shop": play = play2.copy() # 重置play列表 os.system("cls") play[counter] = "> " + play[counter] + " <" navmenuprint(play) if target_state == "play": shop = shop2.copy() # 重置shop列表 os.system("cls") shop[counter] = "> " + shop[counter] + " <" navmenuprint(shop)
2. 修正navup函数的循环逻辑
避免负索引,直接实现循环到列表末尾的逻辑:
def navup(list1, list2): global counter # 清除当前选中项 list1[counter] = list2[counter] # 处理循环逻辑 if counter > 0: counter -= 1 else: counter = len(list1) - 1 # 设置新选中项 list1[counter] = "> " + list1[counter] + " <" print(counter)
3. 简化main.py中的Enter判断逻辑
# play状态下的Enter处理 if keypressed == "enter": if ui.counter in range(4): ui.switchstate("shop") # shop状态下的Enter处理 if keypressed == "enter": if ui.counter in range(5): ui.switchstate("play")
修复后验证
按照原操作步骤执行,切回play状态后按向下箭头,只会显示一个选中项,符合预期。
内容的提问来源于stack exchange,提问作者Sedus
相关产品推荐
相关产品推荐

