Browse Source

Improved tree and addwidgets performances

pull/174/head
Eugenio Parodi 3 years ago
parent
commit
a293ee5701
  1. 5
      TermTk/TTkCore/helper.py
  2. 12
      TermTk/TTkLayouts/layout.py
  3. 9
      TermTk/TTkWidgets/TTkModelView/treewidget.py
  4. 48
      TermTk/TTkWidgets/TTkModelView/treewidgetitem.py
  5. 8
      tests/stress/02.many.tree.nodes.py
  6. 81
      tests/timeit/16.event.vs.set.py

5
TermTk/TTkCore/helper.py

@ -88,8 +88,9 @@ class TTkHelper:
@staticmethod
def addUpdateWidget(widget):
# if not widget.isVisibleAndParent(): return
TTkHelper._updateWidget.add(widget)
TTkHelper.unlockPaint()
if widget not in TTkHelper._updateWidget:
TTkHelper._updateWidget.add(widget)
TTkHelper.unlockPaint()
@staticmethod
def addUpdateBuffer(canvas):

12
TermTk/TTkLayouts/layout.py

@ -312,7 +312,7 @@ class TTkLayout(TTkLayoutItem):
:param widgets: the widget to be removed
:type widgets: list of :class:`~TermTk.TTkWidgets`
'''
for item in self._items:
for item in reversed(self._items):
if item._layoutItemType == TTkK.WidgetItem and \
item.widget() in widgets:
self.removeItem(item)
@ -366,13 +366,11 @@ class TTkLayout(TTkLayoutItem):
def update(self, *args, **kwargs):
ret = False
for i in self.children():
if i._layoutItemType == TTkK.WidgetItem and not i.isEmpty():
ret = ret or i.widget().update(*args, **kwargs)
# TODO: Have a look at this:
# i.getCanvas().top()
for i in self._items:
if i._layoutItemType == TTkK.WidgetItem and (_wid:=i._widget):
ret = ret or _wid.update(*args, **kwargs)
elif i._layoutItemType == TTkK.LayoutItem:
ret= ret or i.update(*args, **kwargs)
ret = ret or i.update(*args, **kwargs)
return ret
class TTkWidgetItem(TTkLayoutItem):

9
TermTk/TTkWidgets/TTkModelView/treewidget.py

@ -109,7 +109,7 @@ class TTkTreeWidget(TTkAbstractScrollView):
def clear(self):
# Remove all the widgets
for ri in self._rootItem.children():
ri.setParent(None)
ri.setTreeItemParent(None)
if self._rootItem:
self._rootItem.dataChanged.disconnect(self._refreshCache)
self._rootItem = TTkTreeWidgetItem(expanded=True)
@ -121,15 +121,16 @@ class TTkTreeWidget(TTkAbstractScrollView):
def addTopLevelItem(self, item):
self._rootItem.addChild(item)
item.setParent(self)
item.setTreeItemParent(self)
self._refreshCache()
self.viewChanged.emit()
self.update()
def addTopLevelItems(self, items):
self._rootItem.addChildren(items)
for item in items:
item.setParent(self)
self._rootItem.setTreeItemParent(self)
#for item in items:
# item.setTreeItemParent(self)
self._refreshCache()
self.viewChanged.emit()
self.update()

48
TermTk/TTkWidgets/TTkModelView/treewidgetitem.py

@ -75,7 +75,7 @@ class TTkTreeWidgetItem(TTkAbstractItemModel):
widget.sizeChanged.connect(self._widgetSizeChanged)
self._height = max(self._height,widget.height())
if self._parentWidget:
widget.setParent(self._parentWidget)
widget.setTreeItemParent(self._parentWidget)
if hasattr(widget, 'text'):
ret = widget.text()
if hasattr(widget,'textChanged'):
@ -129,18 +129,40 @@ class TTkTreeWidgetItem(TTkAbstractItemModel):
def height(self):
return self._height
def setParent(self, parent):
def _clearTreeItemParent(self):
widgets = []
if self._hasWidgets:
widgets += [w for w in self._widgets if w and w.parentWidget()]
# for widget in widgets:
# if pw := widget.parentWidget():
# pw.rootLayout().removeWidgets([w for w in self._widgets if w])
if self._parentWidget:
self._parentWidget.rootLayout().removeWidgets(widgets)
self._parentWidget = None
for c in self._children:
widgets += c._clearTreeItemParent()
return widgets
def _setTreeItemParent(self, parent):
self._parentWidget = parent
widgets = []
if self._hasWidgets:
widgets = [w for w in self._widgets if w]
if parent:
parent.layout().addWidgets(widgets)
else:
for widget in widgets:
if pw := widget.parentWidget():
pw.rootLayout().removeWidgets([w for w in self._widgets if w])
widgets += [w for w in self._widgets if w]
# parent.layout().addWidgets(widgets)
for c in self._children:
c.setParent(parent)
widgets += c._setTreeItemParent(parent)
return widgets
def setTreeItemParent(self, parent):
if parent:
widgets = self._setTreeItemParent(parent)
parent.rootLayout().addWidgets(widgets)
else:
# pw = self._parentWidget
widgets = self._clearTreeItemParent()
# pw.rootLayout().removeWidgets(widgets)
def hasWidgets(self):
return self._hasWidgets
@ -168,7 +190,7 @@ class TTkTreeWidgetItem(TTkAbstractItemModel):
self._setDefaultIcon()
self._sort(children=False)
if self._parentWidget:
child.setParent(self._parentWidget)
child.setTreeItemParent(self._parentWidget)
child.dataChanged.connect(self.emitDataChanged)
def addChild(self, child):
@ -189,7 +211,7 @@ class TTkTreeWidgetItem(TTkAbstractItemModel):
return None
child = self._children.pop(index)
child.dataChanged.disconnect(self.emitDataChanged)
child.setParent(None)
child.setTreeItemParent(None)
self.dataChanged.emit()
return child
@ -197,7 +219,7 @@ class TTkTreeWidgetItem(TTkAbstractItemModel):
children = self._children
for child in children:
child.dataChanged.disconnect(self.emitDataChanged)
child.setParent(None)
child.setTreeItemParent(None)
self._children = []
self.dataChanged.emit()
return children

8
tests/stress/02.many.tree.nodes.py

@ -72,7 +72,8 @@ ttk.TTkLog.use_default_file_logging()
root = ttk.TTk(layout=ttk.TTkGridLayout())
root.layout().addWidget(btn:=ttk.TTkButton(text="Add Buttons",border=True,maxHeight=3),0,0)
root.layout().addWidget(btnadd:=ttk.TTkButton(text="Add Nodes",border=True,maxHeight=3),0,0)
root.layout().addWidget(btndel:=ttk.TTkButton(text="Clean",border=True,maxHeight=3),0,1)
root.layout().addWidget(tw:=ttk.TTkTree(),1,0,1,2)
root.layout().addWidget(ttk.TTkLogViewer(maxHeight=10),2,0,1,2)
@ -83,7 +84,7 @@ types = ("Fatal", "Error", "Mil", "Warning", "Info", "Entry", "Exit")
def _addMany():
ttk.TTkLog.info("Start Stress!!!")
items = []
for i in range(300):
for i in range(500):
_item_elements = [f"n: {i=}", 'console']
for _t in types:
_btn_t = _OnOff(checkable=True, checked=(i%0x07==0))
@ -94,6 +95,7 @@ def _addMany():
tw.addTopLevelItems(items)
ttk.TTkLog.info("End Stress!!!")
btn.clicked.connect(_addMany)
btnadd.clicked.connect(_addMany)
btndel.clicked.connect(tw.clear)
root.mainloop()

81
tests/timeit/16.event.vs.set.py

@ -0,0 +1,81 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2023 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys, os
import timeit
import threading, random
from functools import reduce
data = [random.randint(0,10) for _ in range(500)]
pe = threading.Event()
pe.set()
def test1(d=data, p=pe):
s = set()
for x in d:
s.add(x)
p.set()
return sum(s)
def test2(d=data, p=pe):
s = set()
for x in d:
if x not in s:
p.set()
s.add(x)
return sum(s)
def test3(d=data, p=pe):
s = set()
for x in d:
if x not in s:
s.add(x)
p.set()
return sum(s)
def test4(d=data, p=pe):
s = set()
for x in d:
if x not in s:
s.add(x)
return sum(s)
def test5(d=data, p=pe):
s = set()
for x in d:
s.add(x)
return sum(s)
loop = 10000
a={}
iii = 1
while (testName := f'test{iii}') and (testName in globals()):
result = timeit.timeit(f'{testName}(*a)', globals=globals(), number=loop)
# print(f"test{iii}) fps {loop / result :.3f} - s {result / loop:.10f} - {result / loop} {globals()[testName](*a)}")
print(f"test{iii:02}) | {result / loop:.10f} sec. | {loop / result : 15.3f} Fps ╞╡-> {globals()[testName](*a)}")
iii+=1
Loading…
Cancel
Save