Kivy高尔夫差点计算器报错:提示无可用记分卡求助
高尔夫差点计算器Kivy界面提示“无可用记分卡”问题修复
问题场景
首次开发支持4名玩家的高尔夫差点计算器,已实现玩家姓名和差点的输入功能,但输入玩家信息并点击「创建游戏」按钮后,界面提示「无可用记分卡」,无法继续计算流程。
核心问题分析
代码中存在两处关键逻辑错误:
- 玩家选择流程未触发:原
select_players方法仅创建了玩家选择布局,但未将其显示到界面,用户无法勾选参与游戏的玩家;同时该方法错误返回复选框列表而非选中的玩家对象。 - 游戏创建判断逻辑错误:
create_game方法直接用复选框列表长度判断玩家数量,而非实际选中的玩家数量,导致未经过玩家选择就进入记分卡流程,后续计算因数据类型错误触发异常,最终显示错误提示。
修复后的完整代码
from kivy.app import App from kivy.uix.gridlayout import GridLayout from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.dropdown import DropDown from kivy.uix.textinput import TextInput from kivy.uix.checkbox import CheckBox from kivy.uix.scrollview import ScrollView import json class GolfScorecardApp(App): def build(self): # 加载本地数据 self.load_data() # 主布局 layout = GridLayout(cols=1, padding=10, spacing=10) # 标题 title_label = Label(text="高尔夫差点计算器", font_size=24, size_hint=(1, 0.1)) layout.add_widget(title_label) # 玩家输入布局 player_input_layout = GridLayout(cols=2, spacing=10, size_hint=(1, 0.5)) # 玩家姓名输入框 self.player_name_inputs = [] for i in range(4): player_name_input = TextInput(hint_text='输入玩家姓名') self.player_name_inputs.append(player_name_input) player_input_layout.add_widget(Label(text=f"玩家 {i+1} 姓名:")) player_input_layout.add_widget(player_name_input) # 玩家差点输入框 self.player_handicap_inputs = [] for i in range(4): player_handicap_input = TextInput(hint_text='输入玩家差点') self.player_handicap_inputs.append(player_handicap_input) player_input_layout.add_widget(Label(text=f"玩家 {i+1} 差点:")) player_input_layout.add_widget(player_handicap_input) layout.add_widget(player_input_layout) # 添加玩家按钮 add_player_button = Button(text='添加玩家', size_hint=(1, 0.1)) add_player_button.bind(on_release=self.add_player) layout.add_widget(add_player_button) # 创建游戏按钮 create_game_button = Button(text='创建游戏', size_hint=(1, 0.1)) create_game_button.bind(on_release=self.create_game) layout.add_widget(create_game_button) # 滚动式玩家列表 self.players_scroll_view = ScrollView(size_hint=(1, 0.2)) # 玩家列表布局 self.players_layout = GridLayout(cols=1, spacing=10, size_hint_y=None, height=100) self.players_scroll_view.add_widget(self.players_layout) layout.add_widget(self.players_scroll_view) # 结果提示标签 self.result_label = Label(text='', size_hint=(1, 0.2), valign='top') layout.add_widget(self.result_label) return layout def load_data(self): try: # 从本地文件加载数据 with open('data.json', 'r') as file: self.data = json.load(file) except FileNotFoundError: # 文件不存在时初始化数据,包含示例记分卡 self.data = {'scorecards': [], 'players': []} self.data['scorecards'] = [ {'name': '记分卡1', 'holes': [{'number': 1, 'par': 4}, {'number': 2, 'par': 3}, {'number': 3, 'par': 5}], 'slope': 72}, {'name': '记分卡2', 'holes': [{'number': 1, 'par': 4}, {'number': 2, 'par': 3}, {'number': 3, 'par': 5}], 'slope': 72} ] def save_data(self): # 保存数据到本地文件 with open('data.json', 'w') as file: json.dump(self.data, file) def add_player(self, instance): # 获取输入的玩家姓名和差点 players = [] for i in range(4): name = self.player_name_inputs[i].text handicap = self.player_handicap_inputs[i].text if name and handicap and handicap.isdigit(): player = {'name': name, 'handicap': int(handicap)} players.append(player) # 添加玩家到数据中 if players: self.data['players'].extend(players) # 更新玩家列表显示 self.update_player_list() # 清空输入框 for i in range(4): self.player_name_inputs[i].text = '' self.player_handicap_inputs[i].text = '' # 保存数据 self.save_data() def create_game(self, instance): # 检查是否有可用玩家 if not self.data['players']: self.result_label.text = "没有可用玩家,请先添加玩家。" return # 显示玩家选择界面 self.show_player_selection() def show_player_selection(self): players = self.data['players'] # 创建玩家选择布局 selection_layout = GridLayout(cols=2, padding=10, spacing=10, size_hint_y=None) selection_layout.bind(minimum_height=selection_layout.setter('height')) self.player_checkboxes = [] for player in players: label = Label(text=player['name'], size_hint_x=0.7) checkbox = CheckBox(active=False, size_hint_x=0.3) checkbox.player = player self.player_checkboxes.append(checkbox) selection_layout.add_widget(label) selection_layout.add_widget(checkbox) # 添加确认按钮 confirm_btn = Button(text='确认选择', size_hint=(1, None), height=44) confirm_btn.bind(on_release=self.on_confirm_players) # 包装成滚动布局 scroll_view = ScrollView(size_hint=(1, 0.8)) scroll_view.add_widget(selection_layout) # 创建主布局替换当前界面 main_layout = GridLayout(cols=1, padding=10, spacing=10) main_layout.add_widget(Label(text="选择4名参与游戏的玩家", font_size=18)) main_layout.add_widget(scroll_view) main_layout.add_widget(confirm_btn) self.root.clear_widgets() self.root.add_widget(main_layout) def on_confirm_players(self, instance): # 获取选中的玩家 selected_players = [cb.player for cb in self.player_checkboxes if cb.active] if len(selected_players) <4: self.result_label.text = "请至少选择4名玩家。" # 返回主界面 self.root.clear_widgets() self.root.add_widget(self.build()) return # 保存选中的玩家,进入记分卡选择 self.selected_players = selected_players self.select_scorecard() def select_scorecard(self): scorecards = self.data['scorecards'] if not scorecards: self.result_label.text = "无可用记分卡。" # 返回主界面 self.root.clear_widgets() self.root.add_widget(self.build()) return dropdown = DropDown() for scorecard in scorecards: btn = Button(text=scorecard['name'], size_hint_y=None, height=44) btn.bind(on_release=lambda btn: dropdown.select(btn.text)) dropdown.add_widget(btn) main_button = Button(text='选择记分卡', size_hint=(1, None), height=44) main_button.bind(on_release=dropdown.open) layout = GridLayout(cols=1, padding=10, spacing=10) layout.add_widget(Label(text="选择使用的记分卡", font_size=18)) layout.add_widget(main_button) dropdown.bind(on_select=self.on_scorecard_select) # 替换当前界面为记分卡选择布局 self.root.clear_widgets() self.root.add_widget(layout) def on_scorecard_select(self, instance, value): # 根据选中的名称获取记分卡对象 selected_scorecard = None for scorecard in self.data['scorecards']: if scorecard['name'] == value: selected_scorecard = scorecard break if selected_scorecard: # 计算每位玩家在各球洞的额外杆数 game_handicap = sum(player['handicap'] for player in self.selected_players) // 4 game_results = self.calculate_game_results(selected_scorecard, self.selected_players, game_handicap) # 显示计算结果 self.display_results(game_results) # 返回主界面 self.root.clear_widgets() self.root.add_widget(self.build()) # 重置选中的玩家 self.selected_players = [] else: # 显示错误提示 self.result_label.text = "无可用记分卡。" # 返回主界面 self.root.clear_widgets() self.root.add_widget(self.build()) # 重置选中的玩家 self.selected_players = [] def calculate_game_results(self, scorecard, players, game_handicap): game_results = {} for player in players: player_name = player['name'] player_handicap = int(player['handicap']) extra_strokes = [] for hole in scorecard['holes']: hole_par = hole['par'] extra_strokes_count = max(0, hole_par + player_handicap - scorecard['slope'] + game_handicap) extra_strokes.append(extra_strokes_count) game_results[player_name] = extra_strokes return game_results def display_results(self, game_results): result_text = "计算结果:\n" for player, extra_strokes in game_results.items(): result_text += f"{player}: {extra_strokes}\n" self.result_label.text = result_text def update_player_list(self): player_names = [player['name'] for player in self.data['players']] self.result_label.text = f"可用玩家: {', '.join(player_names)}" def on_stop(self): self.save_data() if __name__ == '__main__': GolfScorecardApp().run()
修复说明
- 重构玩家选择流程:
- 删除原无效的
select_players和on_player_select方法,新增show_player_selection方法创建带玩家姓名和复选框的选择界面,添加确认按钮; on_confirm_players方法收集选中玩家,判断数量是否达标,达标则进入记分卡选择,否则返回主界面提示。
- 删除原无效的
- 修正游戏创建逻辑:
create_game方法先检查是否存在可用玩家,无玩家直接提示;有玩家则显示选择界面等待用户操作。
- 界面本地化:将英文文本替换为中文,提升使用体验。
- 修复数据类型错误:确保
self.selected_players存储玩家字典对象,避免后续计算时的键错误。
内容的提问来源于stack exchange,提问作者Bdown4587
相关产品推荐
相关产品推荐

