【问题标题】:Removing a kivy child widget删除一个 kivy 子小部件
【发布时间】:2021-09-04 13:51:04
【问题描述】:

我正在开发一个 kivy/kivymd vlc 媒体播放器,但在删除子小部件时遇到了挑战。

dashboard.kv sn-p

<ScreenTwo>:

    MDFloatLayout:

        # Set background colour
        md_bg_color: get_color_from_hex("#415b69")

        # Add MDToolbar widget
        MDToolbar:
        
            id: toolbar
            # title: "Woven Ancestry - Lusine Remix"

            # Set toolbar background colour 
            md_bg_color: get_color_from_hex("#212121")

            # Set toolbar text
            specific_text_color: get_color_from_hex("#718089")

            # Set toolbar position
            pos_hint: {'center_x':0.5, 'center_y':0.95}

            # Add left action items
            left_action_items: [["rewind", lambda x: app.callback()], ["play", lambda x: app.callback()], ["fast-forward", lambda x: app.callback()]]

            # Add right action items
            right_action_items: [["volume-minus", lambda x: app.callback()], ["volume-plus", lambda x: app.callback()]]


        # Add scroll view for media list
        ScrollView:
            id: media_list
            pos_hint: {'top': 0.9}

            # Add MDList widget
            MDList:
                id: container

app.py sn-p

class ScreenTwo(MDScreen):   

    def on_pre_enter(self):

        # Instantiate VLC class
        self.vlc_player = vlc.MediaPlayer()

        # Instantiate the MediaLibrary class
        self.media_library = MediaLibrary()

        # Get media file list
        self.media_list = self.media_library.get_media_list('/home/piers/Music')

        # Iterate through media list
        for media in self.media_list:

            # If item in media list includes text, create TwoLineAvatarIconListItem widget
            if len(media['text']) > 0:

                # Create instance of a TwoLineAvatarIconListItem
                self.media_list_item = TwoLineAvatarIconListItem(
                    text=media['text'],
                    secondary_text=media['duration'],
                    on_press=partial(print, "list item clicked!"))

                # Quick hack to include play icon in a specified TwoLineAvatarIconListItem
                if media['text'] == 'Woven Ancestry  Lusine Remix':

                    # Set tool bar text
                    self.ids.toolbar.title = media['text']

                    # Create instance of an IconLeftWidget
                    self.left_icon_widget = IconLeftWidget(icon='play', on_press=partial(print, "play node {}".format(media['node'])))

                    # Add the IconLeftWidget to the TwoLineAvatarIconListItem
                    self.media_list_item.add_widget(self.left_icon_widget)

                    # Attempt to remove the TwoLineAvatarIconListItem child IconLeftWidget (Testing only)
                    self.media_list_item.remove_widget(self.left_icon_widget)
                
                # Add TwoLineAvatarIconListItem to the MDList id: container
                self.ids.container.add_widget(self.media_list_item)

        # Traverse list
        for item in self.ids.container.children:

            print(item) # Print the children widgets in the MDList id: container
            # print(item.children) # Print the children widgets in the TwoLineAvatarIconListItem

            ## Attempt to remove the widget from a specified TwoLineAvatarIconListItem

            # if item.text == 'Woven Ancestry  Lusine Remix':
            #     print(item.children)
            #     print(item.text)
            #     item.remove_widget(item.children[0])
            #     print(item.children)

dashboard.kv sn-p 中,我有一个 MDList 小部件。然后在 app.py sn-p 中使用TwoLineAvatarIconListItem's 进行填充

我能够成功地将IconLeftWidget 添加到TwoLineAvatarIconListItem,但是一旦创建,该小部件就不会显示为子小部件,也无法使用remove_widget 方法将其删除。

如果有人能就我做错了什么提供一些指导,我真的很感激????

【问题讨论】:

  • 感谢您添加代码,您需要如何删除 IconLeftWidget,您需要在有人点击图标时将其删除还是需要在几秒钟后将其删除?如果您需要在有人点击图标时将其删除,您可以添加为 IconLeftWidget 创建一个具有相同“on_press”部分的新类,定义为 kivy lang 和 python 类,在“on_press”中您可以添加一个自我删除小部件,例如“on_press:root.remove_widget(root)”到kv lang部分,这意味着当您单击图标时它将自行删除
  • 您好 jbsidis,感谢您抽出宝贵时间阅读和回复这篇文章。关于您的问题: > 您如何需要删除 IconLeftWidget。当单击 MDList 中的单独 TwoLineAvatarIconListItem (然后添加 IconLeftWidget)或触发下一个跟踪方法时,应删除 IconLeftWidget。我感到困惑的是,为什么在添加 IconLeftWidget 后直接删除它并没有被删除,并且在遍历 MDList.children 时该小部件没有显示为子小部件。任何支持将不胜感激

标签: python kivy kivymd


【解决方案1】:

你可以试试这个代码(我是根据你和你的 cmets 做的),我希望它能满足你的需要:

from time import sleep
from kivymd.icon_definitions import md_icons

from kivymd.uix.list import OneLineIconListItem
from kivymd.uix.button import MDIconButton
from kivymd.uix.label import MDLabel 
from kivymd.uix.card import MDCard
from kivymd.uix.tab import MDTabsBase
from kivymd.uix.dialog import MDDialog
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import OneLineIconListItem, MDList
from kivymd.toast import toast
from kivymd.uix.behaviors import TouchBehavior
from kivymd.uix.filemanager import MDFileManager
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.button import MDFloatingActionButton
from kivymd.uix.button import MDFlatButton
from kivymd.uix.list import OneLineListItem
from kivymd.uix.list import TwoLineIconListItem
from kivymd.uix.list import ThreeLineAvatarListItem
from kivymd.uix.list import OneLineAvatarIconListItem
from kivymd.uix.list import TwoLineAvatarListItem
from kivymd.uix.list import OneLineAvatarListItem
from kivymd.uix.list import ImageLeftWidget
from kivymd.uix.gridlayout import MDGridLayout
from kivymd.uix.list import IconLeftWidget
from kivymd.uix.list import IconRightWidget
from kivymd.uix.textfield import MDTextField
from kivymd.uix.snackbar import Snackbar
from kivymd.uix.bottomsheet import MDListBottomSheet
from kivymd.uix.bottomsheet import MDGridBottomSheet
from kivymd.uix.filemanager import MDFileManager
from kivymd.uix.imagelist import SmartTileWithLabel

#import kivymd.uix.behaviors.MagicBehavior
from kivymd.uix.behaviors.magic_behavior import MagicBehavior
#from kivymd.uix.button import MagicButton
import sys

from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.animation import Animation
from kivy.graphics.context_instructions import Color
from kivy.lang import Builder
from kivy.properties import (
    NumericProperty,
    StringProperty,
    BooleanProperty,
    OptionProperty,
    ListProperty,
    ObjectProperty,
)
from kivy.metrics import dp
from kivy.metrics import sp

from kivymd.font_definitions import theme_font_styles
from kivymd.theming import ThemableBehavior
from kivymd.uix.label import MDIcon

from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.image import Image
from kivy.factory import Factory
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.image import Image
from kivy.uix.scrollview import ScrollView
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen

from kivy.uix.screenmanager import ScreenManager,Screen,WipeTransition,FadeTransition,FallOutTransition,RiseInTransition,CardTransition        

from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.core.audio import SoundLoader
from kivy.metrics import dp
from kivy.uix.bubble import Bubble
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.progressbar import ProgressBar
from kivy.setupconfig import USE_SDL2
from kivy.uix.bubble import Bubble
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.scatter import Scatter
from kivy.properties import StringProperty, ListProperty

import requests
import time
import shutil
from datetime import datetime
from datetime import date, timedelta
import os
worm = os.getcwd()+"/"
Window.softinput_mode = "below_target"
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
    ListProperty,
    NumericProperty,
    BooleanProperty,
    StringProperty,
)
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout

from kivymd.theming import ThemableBehavior
from kivymd.uix.card import MDCard
from kivymd.uix.toolbar import MDToolbar


n="""

Screen:
    ScreenManager:
        id: manage
        Screen:
            MDLabel:
                text: "Loading..."

<Item15>: #two line avatar item
    divider: None
    on_release:
        root.check_if_other_is_playing(app.Ab())
    #Item16:
          
<Item16>: #icon left widget
    id: bar
    canvas:
        Color:
            rgba: [0,1,0,.4]
        RoundedRectangle:
            pos: self.pos
            size: self.size
    icon: root.myicon #"music-note"
    on_release:
        #root.remove_widget(root) #did not work
        root.this_function_changes_icons(root.icon,root)

    
<ScreenTwo>:
    name: "secondscreen"

    MDFloatLayout:

        # Set background colour
        md_bg_color: get_color_from_hex("#415b69")

        # Add MDToolbar widget
        MDToolbar:
            id: toolbar
            # title: "Woven Ancestry - Lusine Remix"
            # Set toolbar background colour 
            md_bg_color: get_color_from_hex("#212121")
            # Set toolbar text
            specific_text_color: get_color_from_hex("#718089")
            # Set toolbar position
            pos_hint: {'center_x':0.5, 'center_y':0.95}
            # Add left action items
            left_action_items: [["rewind", lambda x: app.callback()], ["play", lambda x: app.callback()], ["fast-forward", lambda x: app.callback()]]
            # Add right action items
            right_action_items: [["volume-minus", lambda x: app.callback()], ["volume-plus", lambda x: app.callback()]]

        # Add scroll view for media list
        ScrollView:
            id: media_list
            pos_hint: {'top': 0.9}

            # Add MDList widget
            MDList:
                id: container




            
<Item20>: #two line avatar item
    divider: None
    on_release:
        root.check_if_other_is_playing_jbsidis(app.Ab(),root.ids.my_icon.icon,root.ids.my_icon,root.text)
    IconLeftWidget:
        id: my_icon
        canvas:
            Color:
                rgba: [1,0,0,.4]
            RoundedRectangle:
                pos: self.pos
                size: self.size
        icon: root.myicon
        on_release:
            root.this_function_changes_icons(root.ids.my_icon.icon,root.ids.my_icon)
        
            
"""


class Item20(TwoLineAvatarListItem): #two line avatar item
    bar = StringProperty()
    myicon=StringProperty()
    def check_if_other_is_playing_jbsidis(self,allx,a,bi,z):
        b=allx
        current_list=b.ids.container
        all_songs=current_list.children
        b.ids.toolbar.title=str(z)
        #self.ids.my_icon.icon=""
        self.this_function_changes_icons(a,bi)
        
        
##        print(all_songs)
##        the_single_song_item_list= all_songs[0].children
##        print(the_single_song_item_list[0])
    def this_function_changes_icons(self,a,b):
        print(a,b)
        if a=="music-note":
            b.icon="pause"
            return 0
        if a=="pause":
            b.icon="music-note"
            return 0

class Item15(TwoLineAvatarListItem): #two line avatar item
    bar = ObjectProperty()
    def check_if_other_is_playing(self,allx):
        b=allx
        current_list=b.ids.container
        all_songs=current_list.children
        #print(all_songs)
        the_single_song_item_list= all_songs[0].children
        print(the_single_song_item_list[0])

##        for each_song in all_songs:
##            the_single_song_item_list= each_song.children
##            print(the_single_song_item_list)
##            for parts in the_single_song_item_list:
##                the_icon_is=parts
##                if str(the_icon_is).find("Item16")>-1:
##                    #the_icon_is
##                    self.this_function_changes_icon(the_icon_is)

                
    def this_function_changes_icons(self,a):
        a=a.myicon
        if a=="music-note":
            a.myicon="pause"
            return 0
        if a=="pause":
            a.myicon="music-note"
            return 0
    pass
class Item16(IconLeftWidget): #icon left widget
    myicon=StringProperty()
    def this_function_changes_icons(self,a,b):
        if a=="music-note":
            b.icon="pause"
            return 0
        if a=="pause":
            b.icon="music-note"
    pass



class ScreenTwo(Screen):   

    def on_pre_enter(self):

        # Instantiate VLC class
        try:
            self.vlc_player = vlc.MediaPlayer()

            # Instantiate the MediaLibrary class
            self.media_library = MediaLibrary()

            # Get media file list
            self.media_list = self.media_library.get_media_list('/home/piers/Music')
        except:
            pass

        # Iterate through media list
        for media in range(0,100): #self.media_list:
            media=str(media)+" - New song.mp3"

            # If item in media list includes text, create TwoLineAvatarIconListItem widget
            if len(media) > 0: #

                # Create instance of a TwoLineAvatarIconListItem #partial(print, "list item clicked!")
                #,on_press=lambda x:()
                self.media_list_item = Item20(
                    text=media,
                    secondary_text="3:42",
                    myicon="music-note"
                    )
                if media.find("1") > -1:

                    # Set tool bar text
                    self.ids.toolbar.title = media #media['text']
                    self.ids.container.add_widget(self.media_list_item)



from kivymd.app import MDApp


class Hi(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.sc2 = ScreenTwo()

    def callback(self):
        print(11111)
    def this_function_changes_icons(self,a,b):
        if a=="music-note":
            b.icon="pause"
            return 0
        if a=="pause":
            b.icon="music-note"
            return 0

    def Ab(self):
        T=self.root.ids.manage.get_screen("secondscreen")
        return T #self.sc2

    def add_any_screens(self):
        self.root.ids.manage.add_widget(ScreenTwo())
        print("added")

    def goto(self,a):
        self.root.ids.manage.current=a #"secondscreen"
        
    def build(self):
        Clock.schedule_once(lambda x:self.add_any_screens(),2)
        Clock.schedule_once(lambda x:self.goto("secondscreen"),3)
        return Builder.load_string(n)


Hi().run()

我附上图片,jbsidis:

【讨论】:

    【解决方案2】:

    首先非常感谢 jbsidis 的支持???

    问题是由于在将 IconLeftWidget 添加到 TwoLineAvatarIconListItem 时图形小部件树的嵌套性质所致

    在检查子对象之后

    self.media_list_item.add_widget(self.left_icon_widget)

    使用

    print(self.media_list_item.children)

    我看到了:

    [&lt;kivy.uix.boxlayout.BoxLayout object at 0x7f8ca0d8ac80&gt;, &lt;kivy.uix.boxlayout.BoxLayout object at 0x7f8ca0d8ac10&gt;, &lt;kivy.uix.boxlayout.BoxLayout object at 0x7f8ca3524a50&gt;]

    然后使用以下方法遍历子 boxlayout 对象:

    for child in self.media_list_item.children:
        print(child.children)
    

    然后我看到IconLeftWidget

    [&lt;kivymd.uix.list.IconLeftWidget object at 0x7f978149fcf0&gt;] [&lt;kivymd.uix.label.MDLabel object at 0x7f978149f3c0&gt;, &lt;kivymd.uix.label.MDLabel object at 0x7f97833cdb30&gt;, &lt;kivymd.uix.label.MDLabel object at 0x7f97833bd9e0&gt;]

    现在我了解了IconLeftWidget 在图形小部件树中的位置,我可以遍历MDList id:container 中的TwoLineAvatarIconListItem 并删除子小部件。

    # Traverse list
    for item in self.ids.container.children:
    
        # Select a specified TwoLineAvatarIconListItem
        if item.text == 'Woven Ancestry  Lusine Remix':
    
            # Get the boxlayout with the IconLeftWidget child widget
            self.target_boxlayout = item.children[1]
    
            # Remove the widget
            self.target_boxlayout.remove_widget(self.target_boxlayout.children[0])
    

    因此,当将一个小部件添加到另一个小部件时,不要指望它会是一个直接子代。根据父小部件的构成,它可以进一步嵌套。 #永远学习?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2016-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多