You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy框架下RecycleView列表项点击无法跳转至目标Screen的问题求助

解决Kivy中RecycleView点击项无法打开新界面的问题

我明白你卡在哪了——你已经成功拿到了点击项的索引,但新界面就是不出来,核心问题是你没有用ScreenManager来管理你的多个屏幕。你只是创建了MenuDetailsSubject的实例,但这个屏幕根本没被加入到应用的界面树里,自然不会显示出来。下面是具体的修复方案:

问题根源

Kivy的Screen组件必须由ScreenManager管理才能实现屏幕切换。你之前的代码里直接实例化MenuDetailsSubject(index=index),只是创建了一个对象,但没有把它添加到界面结构中,也没有触发屏幕切换的动作。

修复步骤

1. 初始化ScreenManager管理所有屏幕

在你的LaunchApp类的build方法里,创建一个ScreenManager,把MenuSubjects和MenuDetailsSubject都添加进去,作为应用的根组件。

2. 修改RVItem的点击逻辑

点击列表项时,不要直接实例化新屏幕,而是通过应用实例获取ScreenManager,切换到MenuDetailsSubject屏幕,并传递索引参数。

3. 调整MenuDetailsSubject的初始化逻辑

因为ScreenManager会负责创建屏幕实例,所以我们可以通过on_pre_enter事件来加载数据(避免在初始化时可能出现的文件读取问题),或者在屏幕切换时传递参数。

修改后的完整代码

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
import pandas as pd
from kivy.uix.recycleview import RecycleView
from kivy.factory import Factory

Builder.load_string("""
<RV>:
    RecycleBoxLayout:
        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        spacing : 10
""")

class RVItem(Factory.Button):
    def get_data_index(self):
        return self.parent.get_view_index_at(self.center)

    def on_press(self):
        index = self.get_data_index()
        print(index)
        # 获取应用的ScreenManager,切换到详情页并传递索引
        app = App.get_running_app()
        app.sm.current = 'menu_details'
        # 把索引传递给详情页
        app.sm.get_screen('menu_details').selected_index = index

class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'text': str(x)} for x in range(100)]

class MenuSubjects(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.title = Label(text='Title', font_size= '50px', pos_hint={'y': 0.35})
        self.new_subject_button = Button(
            text= ("Button"),
            size_hint=(0.26, 0.05),
            pos_hint={"x": 0.37, "y": 0.70},
            font_size=25,
        )
        self.layout = RV()
        self.layout.viewclass= 'RVItem'
        self.layout.size_hint = (None, None)
        self.layout.pos_hint={'x': 0.35, 'y': 0.25}
        self.layout.width= 450
        self.layout.height= 300
        self.quit_button = Button(
            text=("Exit"),
            font_size=20,
            size_hint=(0.1,0.05),
            pos_hint={"x": 0.10, "y": 0.10 },
            on_press=lambda x: App.get_running_app().stop()
        )
        self.add_widget(self.title)
        self.add_widget(self.new_subject_button)
        self.add_widget(self.layout)
        self.add_widget(self.quit_button)

class MenuDetailsSubject(Screen):
    def __init__(self, **kwargs):
        self.selected_index = None
        super().__init__(**kwargs)
        self.title = Label(text='Détails du sujet', font_size= '50px', pos_hint={'y': 0.35})
        self.button_previous= Button(
            text= "Précédent",
            font_size=15,
            size_hint=(0.1,0.05),
            pos_hint={"x": 0, "y": 0.9 },
            on_press=lambda x: setattr(App.get_running_app().sm, 'current', 'menu_subjects')
        )
        self.button_supp=Button(
            text= "Supprimer",
            font_size=15,
            size_hint=(0.1,0.05),
            pos_hint={"x": 0.9, "y": 0.9 },
        )
        self.text_details=TextInput(
            font_size= 20,
            background_color=(0,0,0,0),
            foreground_color=(1,1,1,1),
            size_hint=(0.3,0.3),
            pos_hint={'x': 0.35, 'y': 0.4}
        )
        self.add_widget(self.title)
        self.add_widget(self.button_previous)
        self.add_widget(self.button_supp)
        self.add_widget(self.text_details)

    def on_pre_enter(self, *args):
        # 进入屏幕前加载数据
        if self.selected_index is not None:
            filename = "buttons_names.xlsx"
            data = pd.read_excel(filename)
            self.name = str(data.loc[self.selected_index]["Nom"] + data.loc[self.selected_index]["Prenom"])
            self.gender = str(data.loc[self.selected_index]["Genre"])
            self.text_details.text = f"Nom, prénom : {self.name} \n Genre : {self.gender}"

class LaunchApp(App):
    def build(self):
        # 创建ScreenManager并添加所有屏幕
        self.sm = ScreenManager()
        self.sm.add_widget(MenuSubjects(name='menu_subjects'))
        self.sm.add_widget(MenuDetailsSubject(name='menu_details'))
        return self.sm

if __name__ == '__main__':
    LaunchApp().run()

关键修改点说明

  • 添加ScreenManager:在LaunchApp中创建ScreenManager,并将两个屏幕都注册进去,每个屏幕设置唯一的name属性用于切换。
  • 修改RVItem的点击事件:通过App.get_running_app()获取当前应用实例,进而拿到ScreenManager,切换到详情页并设置选中的索引。
  • 使用on_pre_enter加载数据:把Excel读取逻辑移到on_pre_enter方法中,确保每次进入详情页时都会根据选中的索引更新内容,避免初始化时可能的文件读取问题。
  • 添加返回按钮逻辑:给详情页的“Précédent”按钮添加返回主界面的功能。

这样修改后,你点击RecycleView中的项时,就能正常切换到详情页并显示对应索引的内容了。

内容的提问来源于stack exchange,提问作者Reenny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 11:27:34