You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Kivy屏幕实例重叠问题:标签与复选框重复加载导致界面混乱

Kivy屏幕实例重叠问题:标签与复选框重复加载导致界面混乱

嘿,我仔细看了你的代码和问题描述,很快就找到问题根源啦!你的SP_list_Screen类里犯了一个很容易踩的小坑——layout定义成了类属性,而不是实例属性,这就导致所有屏幕实例共享同一个布局对象,每次进入屏幕都会重复添加控件,自然就重叠了。

问题分析

你看,原来的SP_list_Screen里直接写了:

class SP_list_Screen(Screen):
    name = "sp_list"
    layout = BoxLayout(orientation='vertical')  # 这是类属性,所有实例共用!

类属性会被这个类的所有实例共享,而且你在b_l方法里每次都会新建一个layout并调用self.add_widget(layout),但之前添加的旧布局并没有被移除,所以每次进入屏幕都会在原有控件上叠加新的内容,最终就造成了界面混乱。

解决方案

我们只需要做两个关键修改,就能彻底解决这个问题:

  1. layout改成实例属性:在__init__方法里初始化布局,确保每个屏幕实例有自己独立的布局。
  2. 每次加载内容前清空屏幕的子控件:在list_update或者b_l方法开头,先清空当前屏幕的所有子控件,再添加新内容。

修改后的完整代码

下面是修复后的核心代码部分,我已经标注了修改的地方:

from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivymd.uix.button import MDRectangleFlatButton
from kivy.metrics import dp
from kivymd.uix.button import MDIconButton

class SP_list_Screen(Screen):
    name = "sp_list"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 把layout改成实例属性,每个实例独立拥有
        self.layout = BoxLayout(orientation='vertical')
        self.add_widget(self.layout)  # 只在初始化时添加一次主布局

    def list_update(self, my_list):
        # 清空主布局里的所有控件,准备加载新内容
        self.layout.clear_widgets()
        self.my_list = my_list[1:]
        self.heading = my_list[0]
        self.b_l()

    def b_l(self):
        # 这里不需要再新建主layout,用初始化时的self.layout即可
        top_padding_layout = BoxLayout(orientation='horizontal', size_hint=(1, 0.1))
        icon_button = MDIconButton(icon='arrow-left', on_release=self.back)
        label = Label(text=self.heading, halign='left', color=(0, 0, 0, 1), text_size=(350, None))
        top_padding_layout.add_widget(icon_button)
        top_padding_layout.add_widget(label)
        self.layout.add_widget(top_padding_layout)

        scrollview = ScrollView()
        self.selected_songs = []
        grid_layout = GridLayout(cols=1, spacing=dp(20), size_hint_y=None, padding=dp(5))
        grid_layout.bind(minimum_height=grid_layout.setter('height'))
        self.checkboxes = []
        self.list_display(grid_layout, scrollview)

    def list_display(self, grid_layout, scrollview):
        for i in range(len(self.my_list)):
            checkbox_layout = BoxLayout(orientation='horizontal', size_hint=(1, None), height=dp(30))
            label = Label(text=self.my_list[i], size_hint=(0.7, None), color=(0, 0, 0, 1), height=dp(30), text_size=(250, None))
            checkbox = CheckBox(size_hint=(0.3, None), height=dp(30), color=(0, 0, 0, 1))
            checkbox.label = self.my_list[i]
            checkbox.active = False
            checkbox.bind(active=self.on_checkbox_active)
            checkbox_layout.add_widget(label)
            checkbox_layout.add_widget(checkbox)
            self.checkboxes.append(checkbox)
            grid_layout.add_widget(checkbox_layout)
        self.a_l(scrollview, grid_layout)

    def a_l(self, scrollview, grid_layout):
        scrollview.add_widget(grid_layout)
        self.layout.add_widget(scrollview)
        download_button = MDRectangleFlatButton(text='Download Selected', size_hint=(1, 0.1), on_press=self.download_selected_songs)
        self.layout.add_widget(download_button)

    # 其他方法保持不变
    def on_checkbox_active(self, checkbox, value):
        song_name = checkbox.label
        if value:
            self.selected_songs.append(song_name)
        else:
            self.selected_songs.remove(song_name)

    def back(self, instance):
        self.manager.current = 'my_button'

    def download_selected_songs(self, instance):
        print("Selected Songs:")
        print(self.selected_songs)

class MyButtonScreen(Screen):
    def __init__(self, **kwargs):
        super(MyButtonScreen, self).__init__(**kwargs)
        self.name = "my_button"
        self.layout = MDRectangleFlatButton(text="Click Me", on_press=self.On_press)
        self.add_widget(self.layout)

    def On_press(self, instance):
        names=['Space Song - song and lyrics by Beach House ', 'Myth - song and lyrics by Beach House ', 'Apocalypse - song and lyrics by Cigarettes After Sex ', 'Fourth of July - song and lyrics by Sufjan Stevens ', 'Cry - song and lyrics by Cigarettes After Sex ', 'Touch - song and lyrics by Cigarettes After Sex ', 'On the Sea - song and lyrics by Beach House ', 'Somewhere Only We Know - song and lyrics by Keane ', 'Here With Me - song and lyrics by d4vd ', 'The Night We Met - song and lyrics by Lord Huron ', "You're Somebody Else - song and lyrics by flora cash ", "You're All I Want - song and lyrics by Cigarettes After Sex ", 'Until I Found You - song and lyrics by Stephen Sanchez ', 'Glimpse of Us - song and lyrics by Joji ', 'Repeat Until Death - song and lyrics by Novo Amor ', 'Another Love - song and lyrics by Tom Odell ', 'In My Head - song and lyrics by Bedroom ', 'Past Lives - song and lyrics by Farizki ']
        self.manager.get_screen('sp_list').list_update(names)
        self.manager.current = 'sp_list'

class MyApp(MDApp):
    def build(self):
        Window.size=(340,600)
        sm = ScreenManager()
        sm.add_widget(MyButtonScreen(name="button_screen"))
        sm.add_widget(SP_list_Screen(name='sp_list'))
        return sm

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

修改说明

  • SP_list_Screenlayout从类属性移到__init__方法里,变成实例属性,每个屏幕实例都有自己的主布局。
  • list_update方法开头调用self.layout.clear_widgets(),确保每次加载新内容前清空旧控件。
  • 移除了b_l方法里新建主layout的代码,直接使用初始化时创建的self.layout,避免重复往屏幕里添加布局。

现在你再运行代码,不管多少次切换到sp_list屏幕,控件都不会重叠了——每次进入都会清空旧内容,重新加载新的列表项。

备注:内容来源于stack exchange,提问作者Avijit Bhuin

火山引擎 最新活动