目录结构的Kivy Treeview会消耗很多内存

发布于 2025-01-21 03:48:49 字数 7249 浏览 0 评论 0原文

我有一个应用程序,可以从USB驱动器中读取文件以进一步处理,因此我使用Kivy中的TreeView创建了USB的目录结构。 TreeView的每个节点都是一个包含复选框和标签的BoxLayout。我们可以通过单击相应的文件/文件夹名称的复选框选择文件。我面临的挑战是,如果目录结构包含超过5000个文件,则在TreeView中列出的内存时消耗的内存很高,并且应用程序速度很慢,如果它超过10000,则该应用程序冻结了,并且应用程序将获得某个应用程序。由于记忆力低而崩溃。

请找到以下代码,我正在加载文件夹 /UsbDrive的文件以加载文件,请创建文件夹并在其中包含一些文件,然后执行以下Python程序

from kivy.app import App
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.treeview import TreeView , TreeViewNode
from kivy.clock import Clock
from kivy.metrics import dp

import os
import subprocess
from functools import partial
import time


file_folder_select={}
selected_node=''
class MyEachNode(BoxLayout):

    def __init__(self, **kwargs):
        self.text = kwargs.pop('text', 'None')
        super(MyEachNode, self).__init__(**kwargs)
        global file_folder_select, selected_node
        self.orientation = 'horizontal'
        self.base_name=os.path.basename(self.text)
        self.parent_name=os.path.dirname(self.text)
        self.size_hint_y = None
        self.height = dp(60)
        self.padding=(20,0,20,0)
        # make the parts of the node
        self.lbl = Label(text=self.base_name, size_hint_x=0.5, halign="left", valign="center", bold=True, font_size=25)
        #self.chkbx_each_node = CheckBox(size_hint_x=0.01, color=(1, 1, 1, 3.5))  # alpha=3.5 to make it more visible
        self.chkbx_each_node=CheckBox(size_hint_x= None, size_hint_y= None, height=60, width=50)
        #self.chkbx_each_node.background_checkbox_normal = 'includes/unchecked.png'
        #self.chkbx_each_node.background_checkbox_down = 'includes/checked.png'
        file_folder_select[self.text]=self.chkbx_each_node
        self.chkbx_each_node.bind(active=self.on_checkbox_active)
        self.lbl.bind(size=self.lbl.setter('text_size'))
        # add the parts to the BoxLayout
        self.add_widget(self.chkbx_each_node)
        self.add_widget(self.lbl)
        #if os.path.isfile(self.text):
        try:
            file_folder_select[self.text].active=file_folder_select[self.parent_name].active
        except:
            pass
    def on_checkbox_active(self,checkbox, value):
        global selected_node
        if os.path.isdir(self.text):
            self.folder_files=subprocess.getoutput("find \'%s\'" %self.text)
            #for self.entries in  self.folder_files.splitlines()[:2]:
            if not selected_node in self.folder_files.splitlines():
                for self.entries in  self.folder_files.splitlines():
                    try:
                        file_folder_select[self.entries].active = value
                    except:
                        pass
            else:
                selected_node=''
            if value == False:
                try:
                    if file_folder_select[os.path.dirname(self.text)].active == True:
                        selected_node=str(self.text)
                    file_folder_select[os.path.dirname(self.text)].active = value
                except:
                    pass
                
        else:
            if value == False:
                #print(self.text)
                try:
                    if file_folder_select[os.path.dirname(self.text)].active == True:
                        selected_node=str(self.text)
                    file_folder_select[os.path.dirname(self.text)].active = value
                except:
                    pass
                
class MyTreeNode(MyEachNode, TreeViewNode):
    pass


class MyTreeView(TreeView):
    def __init__(self):
        super(MyTreeView, self).__init__()
        self.size_hint_y=None
        self.bind(minimum_height=self.setter('height'))
        #self.on_node_expand=self.node_exp()
        self.bind(on_node_expand=self.node_exp)
        self.root_options={'text': 'USBDRIVE', 'bold':True, 'font_size':25}
        # The usb drive is mounted in /USBDRIVE or you can copy the files to /USBDRIVE
        self.my_drive='/USBDRIVE'
        self.extracted={}
        self.folder_files=subprocess.getoutput("find \'%s\' -maxdepth 1 " %self.my_drive)
        self.nodes={}
        self.create_nodes()
    def create_nodes(self, *largs):
        for self.entries in self.folder_files.splitlines():
            self.dir_name=os.path.dirname(self.entries)
            self.base_name=os.path.basename(self.entries)
            if  self.dir_name != "/":
                #if len(self.folder_files) <= 5500:
                    self.nodes[self.entries]=self.add_node(MyTreeNode(text=self.entries))
                    if os.path.isdir(self.entries):
                        self.nodes[self.entries].is_leaf=False
                # else:
                #     break
    def node_exp(self, node, exp_node):
        global running_windows, my_pid, file_manager_widget, file_folder_select
        self.exp_node=exp_node
        if not ( self.exp_node.text == 'USBDRIVE' or self.exp_node.text == 'DVDDRIVE'):
            if self.exp_node.is_loaded == False:
                self.keys = [self.k for self.k, self.v in self.nodes.items() if self.v == self.exp_node]
                self.folder_files=subprocess.getoutput("find \'%s\' -maxdepth 1 " %self.keys[0])
                Clock.schedule_once(partial(self.add_childs_inside_node, exp_node))

    def add_childs_inside_node(self,exp_node, *largs):
        global my_pid, running_windows, file_folder_select
        self.mycount=0
        for self.entries in self.folder_files.splitlines():
            # if len(file_folder_select) <= 5500:
                if self.mycount != 0:
                    if (self.mycount%1000) == 0 :
                        time.sleep(1)
                self.dir_name=os.path.dirname(self.entries)
                self.base_name=os.path.basename(self.entries)
                if  self.dir_name == self.keys[0]:
                    self.mycount+=1
                    self.nodes[self.entries]=self.add_node(MyTreeNode(text=self.entries),self.nodes[self.keys[0]])
                    if os.path.isdir(self.entries):
                        self.nodes[self.entries].is_leaf=False
            # else:
            #     break
        self.exp_node.is_loaded=True

    def hide_widget(self,wid, dohide):
        if hasattr(wid, 'saved_attrs'):
            if not dohide:
                wid.height, wid.size_hint_y, wid.opacity, wid.disabled = wid.saved_attrs
                del wid.saved_attrs
        elif dohide:
            wid.saved_attrs = wid.height, wid.size_hint_y, wid.opacity, wid.disabled
            wid.height, wid.size_hint_y, wid.opacity, wid.disabled = 0, None, 0, True







class FilelistApp(App):
       
    def build(self):
        
        MainBox = BoxLayout()
        InsideBox=BoxLayout(size_hint_y=.9)
        self.file_folder_tree=MyTreeView()
        self.scroll_view=ScrollView(size_hint=(1, 1),do_scroll_y=True,size=InsideBox.size)
        self.scroll_view.pos_hint_x=0
        self.scroll_view.pos_hint_y=1
        MainBox.add_widget(InsideBox)
        InsideBox.add_widget(self.scroll_view)
        self.scroll_view.add_widget(self.file_folder_tree)
 
        return MainBox
 
root = FilelistApp()
   

root.run()

I have an application which reads file from the usb drive to process further, So I have created the directory structure of the USB using the Treeview in Kivy. Each node of the Treeview is a Boxlayout which contains a Checkbox and a Label. We can select the files by clicking the Checkbox of respective File/Folder name. The challenge I am facing is if the directory structure contains more than 5000 files, the memory consumed is high when it is listed in the treeview and the application gets slow, if it is more than 10000 then the application freeze and sometime the application will get crash due to low memory.

Please find the below code, I am loading the files from the folder /USBDRIVE to load the files, kindly create the folder and have some files in it, then execute the below python program

from kivy.app import App
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.treeview import TreeView , TreeViewNode
from kivy.clock import Clock
from kivy.metrics import dp

import os
import subprocess
from functools import partial
import time


file_folder_select={}
selected_node=''
class MyEachNode(BoxLayout):

    def __init__(self, **kwargs):
        self.text = kwargs.pop('text', 'None')
        super(MyEachNode, self).__init__(**kwargs)
        global file_folder_select, selected_node
        self.orientation = 'horizontal'
        self.base_name=os.path.basename(self.text)
        self.parent_name=os.path.dirname(self.text)
        self.size_hint_y = None
        self.height = dp(60)
        self.padding=(20,0,20,0)
        # make the parts of the node
        self.lbl = Label(text=self.base_name, size_hint_x=0.5, halign="left", valign="center", bold=True, font_size=25)
        #self.chkbx_each_node = CheckBox(size_hint_x=0.01, color=(1, 1, 1, 3.5))  # alpha=3.5 to make it more visible
        self.chkbx_each_node=CheckBox(size_hint_x= None, size_hint_y= None, height=60, width=50)
        #self.chkbx_each_node.background_checkbox_normal = 'includes/unchecked.png'
        #self.chkbx_each_node.background_checkbox_down = 'includes/checked.png'
        file_folder_select[self.text]=self.chkbx_each_node
        self.chkbx_each_node.bind(active=self.on_checkbox_active)
        self.lbl.bind(size=self.lbl.setter('text_size'))
        # add the parts to the BoxLayout
        self.add_widget(self.chkbx_each_node)
        self.add_widget(self.lbl)
        #if os.path.isfile(self.text):
        try:
            file_folder_select[self.text].active=file_folder_select[self.parent_name].active
        except:
            pass
    def on_checkbox_active(self,checkbox, value):
        global selected_node
        if os.path.isdir(self.text):
            self.folder_files=subprocess.getoutput("find \'%s\'" %self.text)
            #for self.entries in  self.folder_files.splitlines()[:2]:
            if not selected_node in self.folder_files.splitlines():
                for self.entries in  self.folder_files.splitlines():
                    try:
                        file_folder_select[self.entries].active = value
                    except:
                        pass
            else:
                selected_node=''
            if value == False:
                try:
                    if file_folder_select[os.path.dirname(self.text)].active == True:
                        selected_node=str(self.text)
                    file_folder_select[os.path.dirname(self.text)].active = value
                except:
                    pass
                
        else:
            if value == False:
                #print(self.text)
                try:
                    if file_folder_select[os.path.dirname(self.text)].active == True:
                        selected_node=str(self.text)
                    file_folder_select[os.path.dirname(self.text)].active = value
                except:
                    pass
                
class MyTreeNode(MyEachNode, TreeViewNode):
    pass


class MyTreeView(TreeView):
    def __init__(self):
        super(MyTreeView, self).__init__()
        self.size_hint_y=None
        self.bind(minimum_height=self.setter('height'))
        #self.on_node_expand=self.node_exp()
        self.bind(on_node_expand=self.node_exp)
        self.root_options={'text': 'USBDRIVE', 'bold':True, 'font_size':25}
        # The usb drive is mounted in /USBDRIVE or you can copy the files to /USBDRIVE
        self.my_drive='/USBDRIVE'
        self.extracted={}
        self.folder_files=subprocess.getoutput("find \'%s\' -maxdepth 1 " %self.my_drive)
        self.nodes={}
        self.create_nodes()
    def create_nodes(self, *largs):
        for self.entries in self.folder_files.splitlines():
            self.dir_name=os.path.dirname(self.entries)
            self.base_name=os.path.basename(self.entries)
            if  self.dir_name != "/":
                #if len(self.folder_files) <= 5500:
                    self.nodes[self.entries]=self.add_node(MyTreeNode(text=self.entries))
                    if os.path.isdir(self.entries):
                        self.nodes[self.entries].is_leaf=False
                # else:
                #     break
    def node_exp(self, node, exp_node):
        global running_windows, my_pid, file_manager_widget, file_folder_select
        self.exp_node=exp_node
        if not ( self.exp_node.text == 'USBDRIVE' or self.exp_node.text == 'DVDDRIVE'):
            if self.exp_node.is_loaded == False:
                self.keys = [self.k for self.k, self.v in self.nodes.items() if self.v == self.exp_node]
                self.folder_files=subprocess.getoutput("find \'%s\' -maxdepth 1 " %self.keys[0])
                Clock.schedule_once(partial(self.add_childs_inside_node, exp_node))

    def add_childs_inside_node(self,exp_node, *largs):
        global my_pid, running_windows, file_folder_select
        self.mycount=0
        for self.entries in self.folder_files.splitlines():
            # if len(file_folder_select) <= 5500:
                if self.mycount != 0:
                    if (self.mycount%1000) == 0 :
                        time.sleep(1)
                self.dir_name=os.path.dirname(self.entries)
                self.base_name=os.path.basename(self.entries)
                if  self.dir_name == self.keys[0]:
                    self.mycount+=1
                    self.nodes[self.entries]=self.add_node(MyTreeNode(text=self.entries),self.nodes[self.keys[0]])
                    if os.path.isdir(self.entries):
                        self.nodes[self.entries].is_leaf=False
            # else:
            #     break
        self.exp_node.is_loaded=True

    def hide_widget(self,wid, dohide):
        if hasattr(wid, 'saved_attrs'):
            if not dohide:
                wid.height, wid.size_hint_y, wid.opacity, wid.disabled = wid.saved_attrs
                del wid.saved_attrs
        elif dohide:
            wid.saved_attrs = wid.height, wid.size_hint_y, wid.opacity, wid.disabled
            wid.height, wid.size_hint_y, wid.opacity, wid.disabled = 0, None, 0, True







class FilelistApp(App):
       
    def build(self):
        
        MainBox = BoxLayout()
        InsideBox=BoxLayout(size_hint_y=.9)
        self.file_folder_tree=MyTreeView()
        self.scroll_view=ScrollView(size_hint=(1, 1),do_scroll_y=True,size=InsideBox.size)
        self.scroll_view.pos_hint_x=0
        self.scroll_view.pos_hint_y=1
        MainBox.add_widget(InsideBox)
        InsideBox.add_widget(self.scroll_view)
        self.scroll_view.add_widget(self.file_folder_tree)
 
        return MainBox
 
root = FilelistApp()
   

root.run()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文