如何在Kivy的Jeu屏幕中创建10×10 ToggleButton网格?
核心问题分析
- 不能将
Jeu类从Screen改为GridLayout——ScreenManager仅接受Screen类型组件,修改后会导致程序无法启动。 - 动态生成ToggleButton网格需在
Jeu的初始化流程中完成,确保组件正确挂载到Screen布局内。
修改后的Python代码
import numpy as np from collections import namedtuple from kivy.app import App from kivy.clock import Clock from kivy.core.audio import SoundLoader from kivy.core.window import Window from kivy.lang import Builder from kivy.properties import ObjectProperty, ListProperty from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.togglebutton import ToggleButton from kivy.uix.screenmanager import NoTransition, ScreenManager, Screen field = namedtuple('field', ['rows', 'cols']) FIELD = field(30, 60) # 全局变量控制音乐状态 a = "play" class Jeu(Screen): def __init__(self, **kwargs): super(Jeu, self).__init__(**kwargs) # 创建主布局:垂直排列网格和控制按钮 main_layout = GridLayout(cols=1) # 10×10的ToggleButton网格 self.cell_grid = GridLayout(cols=10, size_hint=(1, 0.8)) self.cells = [] for i in range(10): row = [] for j in range(10): btn = ToggleButton() btn.bind(on_press=self.on_cell_toggle) row.append(btn) self.cell_grid.add_widget(btn) self.cells.append(row) # 控制按钮布局 control_layout = GridLayout(cols=4, size_hint=(1, 0.2)) self.start_btn = ToggleButton(id='start', text='开始模拟') self.start_btn.bind(on_state=self.on_start_toggle) control_layout.add_widget(self.start_btn) control_layout.add_widget(Button(id='next', text='下一代', on_press=self.next_generation)) control_layout.add_widget(Button(id='clear', text='清空', on_press=self.clear_grid)) control_layout.add_widget(Button(text="返回菜单", on_release=self.go_back_to_menu)) # 将布局添加到Screen main_layout.add_widget(self.cell_grid) main_layout.add_widget(control_layout) self.add_widget(main_layout) def on_cell_toggle(self, instance): # 处理单元格点击事件,可在这里更新生命游戏状态 pass def on_start_toggle(self, instance, value): if value == 'down': Clock.schedule_interval(self.update_simulation, 0.1) else: Clock.unschedule(self.update_simulation) def update_simulation(self, dt): # 生命游戏迭代逻辑,这里先保留打印测试 print("模拟中...") def next_generation(self, instance): # 手动触发下一代逻辑 pass def clear_grid(self, instance): # 清空所有ToggleButton状态 for row in self.cells: for btn in row: btn.state = 'normal' self.start_btn.state = 'normal' def go_back_to_menu(self, instance): self.start_btn.state = 'normal' self.manager.current = 'menu' class MenuScreen(Screen): pass class RuleScreen (Screen): pass class SettingsScreen(Screen): def __init__(self, **kwargs): super(SettingsScreen, self).__init__(**kwargs) self.sound = SoundLoader.load('oui.wav') def fullscreen(self): if Window.fullscreen: self.ids.fullscreen.text = '关闭全屏' Window.fullscreen = False else: self.ids.fullscreen.text = '开启全屏' Window.fullscreen = True def music(self): global a if a == "play": self.ids.music.text = '关闭音乐' a = "stop" self.sound.stop() else: self.ids.music.text = '开启音乐' a = "play" self.sound.play() class PloytestApp(App): def build(self): sm = ScreenManager() sm.add_widget(MenuScreen(name='menu')) sm.add_widget(Jeu(name='jeu')) sm.add_widget(RuleScreen(name='rules')) sm.add_widget(SettingsScreen(name='settings')) sm.transition = NoTransition() return sm if __name__ == '__main__': PloytestApp().run()
修改后的kv文件
#: import Window kivy.core.window.Window <MenuScreen>: GridLayout: cols: 1 Image: id: gif source: 'test.zip' allow_stretch: True keep_aspect: False anim_loop: 0 Label: pos: self.parent.pos size: self.parent.size text:"康威生命游戏" font_size: 60 color: 0.5, 0.8, 1, 1 GridLayout: cols: 1 Button: text: '开始游戏' on_release: root.manager.current = 'jeu' Button: text: '游戏规则' on_release: root.manager.current = 'rules' Button: text: '设置' on_release: root.manager.current = 'settings' Button: text: '退出' on_release: app.stop() <RuleScreen>: GridLayout: cols:1 Image: source: 'rules.jpg' GridLayout: cols: 2 Button: text: '设置' on_release: root.manager.current = 'settings' Button: text: '返回菜单' on_release: root.manager.current = 'menu' <SettingsScreen>: GridLayout: cols: 1 size: root.width - 100, root.height -100 Button: id: fullscreen text: "关闭全屏" on_release: root.fullscreen() Button: id: music text: "开启音乐" on_release: root.music() Button: text: '返回菜单' on_release: root.manager.current = 'menu'
关键修改说明
- 保留Jeu的Screen继承:确保组件能正常加入ScreenManager,解决程序无法启动的问题。
- 动态生成ToggleButton网格:在
Jeu的__init__方法中创建10×10网格,循环添加按钮并存储引用,方便后续操作单元格状态。 - 修正控制按钮逻辑:
- 修复"开始模拟"按钮的状态切换逻辑,按下启动定时器,松开停止。
- 整合"清空"和返回菜单按钮的状态重置逻辑,确保返回时停止模拟。
- 优化音乐控制:将音乐播放/停止逻辑整合到
SettingsScreen中,移除全局回调,代码更简洁。 - 修正kv文件错误:移除无效注释,调整布局缩进,将界面文本翻译为中文。
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

