目录结构的Kivy Treeview会消耗很多内存
我有一个应用程序,可以从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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论