So I'm trying to delete a node from a tree by using these two functions inside the class.Unfortunately it just doesnt delete anything and i was wondering what is wrong about it! any help would be truly appreciated.
def Find_Min(self,node):
current=node
while current.left is None:
current=current.left
return current
def deletenode(self,node,ntbd): ##ntbd:node to be deleted /// node: root node
if node is None:
return None
elif node.data>ntbd:
node.left=self.deletenode(node.left,ntbd)
elif node.data<ntbd:
node.right=self.deletenode(node.right,ntbd)
else: ##Found you bastard
if node.left==None and node.right==None:
node=None
elif node.left==None:
temp=node.right
node=None
print("----",temp)
elif node.right==None:
temp=node.left
node=None
print("----",temp)
else:
smallest=self.Find_Min(node.right)
node.data=smallest.data
node.right=self.deletenode(node.right,smallest.data)
Related
I need to implement pagination for list of entities in a telegram bot's reply keyboard.
the problem is that i need to have a show more button that loads next set of entities and i don't know how to get the page that user is currently viewing.
the next problem is how to know which list of entities is user currently viewing.
the only way that there is in my mind is to store the current state of user in database or cache it but i don't know that is there some way to add additional data to telegram reply keyboard's button or some other way to do this so i don't have to do this load of work.
You can add page number to message text or callback_data, and editMessage method is helpful.
For instance, this case using callback_data to pass current page and actions.
I started with this model once. Maybe it's helpful for someone else:
class PaginationModel(Generic[T]):
def __init__(self, all_items: Iterable[T] = None, items_per_page: int = 1):
self.all_items = list(all_items or [])
self._current_page = 0
self.items_per_page = items_per_page
#property
def _begin(self):
return self._current_page * self.items_per_page
#property
def _end(self):
return min((self._current_page + 1) * self.items_per_page, self.item_count)
#property
def item_count(self):
return len(self.all_items)
#property
def page_items(self) -> List[T]:
return self.all_items[self._begin : self._end]
#property
def current_page_number(self) -> int:
return self._current_page + 1
#property
def has_next_page(self) -> bool:
return self._end < self.item_count
#property
def has_previous_page(self) -> bool:
return self._begin > 0
def flip_next_page(self):
self._current_page += 1
def flip_previous_page(self):
self._current_page -=
I have implemented a delegate and model on a TreeView, which contains an spinbox on the column number one, but the number format is not the correct one. But, after I click the spinbox, it is setted correctly. I am using PyQt5.
Here I attached two images which explain it much better.
Value setted on a first time
The value is seen correctly after click the spinbox
Here is the code where spinbox are initialized on a first time:
def createEditor(self, parent, option, index):
item = index.internalPointer()
if index.column() == 0:
editor = super().createEditor(parent, option, index)
elif index.column() == 1:
name = item.get_data()[0]
data = item.get_data()[1]
editor = QtWidgets.QSpinBox(parent, minimum=-9999999999, maximum=9999999999)
# editor.setEditTriggers(QAbstractItemView.SelectedClicked)
editor.setObjectName(name)
editor.setValue(data)
editor.setStyleSheet("""
border-radius: 0px;
""")
editor.installEventFilter(self)
else:
editor = super().createEditor(parent, option, index)
return editor
I think that I missed a comitData somewhere, but I don't know where is the better place to emit it, or if it is the correct way to do that.
Thanks you,
Marcel
The problem was resolved.
It was not in the delegate, and it has not got any relationship about QSpinBox, but the model and str format.
On QtCore.Qt.DisplayRole role on function data, I did the correct conversion, as I show on the following code:
def data(self, in_index, role):
if not in_index.isValid():
return QVariant()
node = in_index.internalPointer()
if role == QtCore.Qt.DisplayRole:
if node.data(in_index.column()) is None:
return ''
if in_index.column() == 1:
return str(float(node.data(in_index.column())))
return str(node.data(in_index.column()))
Thanks you all.
Regards,
Marcel
I placed QTreeWidget into QVBoxLayout.
self._tree = QTreeWidget()
layout = QVBoxLayout()
layout.addWidget(self._some_other_widget)
layout.addWidget(self._tree)
layout.addStretch()
self.setLayout(layout)
All nodes in this tree widget are always expanded.
I would like to create this tree widget with minimal height (for example, for one row/item). When new items are added this tree widget also grows to show all items. How can this be done? Thank you in advance.
There are at least two solutions:
Use self._tree.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents). Thank you for this, G.M.
I have also found another solution:
def sizeHint(self):
return self._sizeHint()
def minimumSizeHint(self):
return self._sizeHint()
def _sizeHint(self):
sh = super().sizeHint()
if self._item_count > 0:
return QSize(sh.width(), self.sizeHintForRow(0) * self._item_count)
else:
return QSize(sh.width(), 40)
In PyQt, I am looking for a way to set the height of rows in a QTreeView (similarly to QTableView.setRowHeight(row, row_height), but QTreeView does not have this function). QAbstractItemModel is used to set the tree model. I read some suggestions here using and sub-classing QAbstractItemDelegate.sizeHint(option, index) but I don't know exactly how to call them correctly within my tree model.
Any minimal code or suggestion would be greatly appreciated. Thanks.
The QTreeView works out a height for each row based on the data and size hints returned for each item. I think you probably just need to return size hints, either for all your items, or at least the first row (if you have setUniformRowHeights(True)). Incidentally this can significantly improve performance and so you should set it if you can.
So you just need to implement your AbstractItemModel.data() method to return a size hint in the SizeHintRole. Something like this:
def data(self, index, role = QtCore.Qt.DisplayRole):
# Check the index, possibly return None
if role == QtCore.Qt.DisplayRole:
# Return the data
elif role == QtCore.Qt.SizeHintRole:
return QtCore.QSize(item_width,item_height)
# Other roles - maybe return None if you don't use them.
EDIT: Big example
You say you are still having trouble so here is a complete working example, based on the standard QT itemviews example. Try varying the QSize returned in the data method to see how the view changes:
import sys
from PySide import QtCore,QtGui
class TreeItem(object):
def __init__(self, data, parent=None):
self.parentItem = parent
self.data = data
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
class TreeModel(QtCore.QAbstractItemModel):
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self.rootItem = TreeItem(None)
for i,c in enumerate("abcdefg"):
child = TreeItem([i,c],self.rootItem)
self.rootItem.appendChild(child)
parent = self.rootItem.childItems[1]
child = TreeItem(["down","down"],parent)
parent.appendChild(child)
def columnCount(self, parent):
return 2
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole:
item = index.internalPointer()
return item.data[index.column()]
elif role == QtCore.Qt.SizeHintRole:
print "giving size hint"
return QtCore.QSize(40,40)
return None
def flags(self, index):
if not index.isValid():
return QtCore.Qt.NoItemFlags
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return ["A","B"][section]
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.childItems[row]
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
parentItem = index.internalPointer().parentItem
if parentItem == self.rootItem:
return QtCore.QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return len(parentItem.childItems)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
model = TreeModel()
view = QtGui.QTreeView()
view.setModel(model)
view.setWindowTitle("Simple Tree Model")
view.show()
sys.exit(app.exec_())
It's pretty simple to do this with stylesheet :
self.setStyleSheet("QTreeView::item { padding: 10px }")
Don't know about Python, but C++ code would be like this:
model->setData(model->index(/*your index*/), QSize(20, 20), Qt::SizeHintRole);
And you need to set it for all items in your tree.
If you want use QItemDelegate - you no need to call this function, you just set your delegate to view, like this (C++ code again, but main idea is the same):
treeView->setItemDelegate(new MyDelegate(this));
Than view will use it when it need it.
For the PySide bindings, here's the Python code for the custom delegate on the AbstractItemModel.
from PySide import QtCore, QtGui
tree = QTreeView()
tree.model = QtGui.QAbstractItemModel()
tree.setModel(tree.model)
size = QtCore.QSize(20, 20)
index = tree.model.index(row, col) # row, col are your own
tree.model.setData(index, size, QtCore.Qt.SizeHintRole)
delegate = MyDelegate()
tree.setItemDelegate(delegate)
This is just translating the code from #RazrFalcon to Python, and was requested by another user.
With Qt 5.9.2, I had trouble with simultaneously getting QTreeView auto-sizing columns and custom row heights. Using SizeHintRole worked for height but seemingly wrecked auto-width. The solution for me was to set the rows to have uniform heights and then do something like this in Python 3.7:
self._tree = QTreeView()
self._tree.setAlternatingRowColors(True)
self._tree.setUniformRowHeights(True)
...
fi = QFontInfo(self.font())
self._tree.setStyleSheet(
f'''
QTreeView {{
alternate-background-color: #E6FFFF;
}}
QTreeView::Item{{
height:{fi.pixelSize() * 2}px;
}}
''')
I'll speculate that setting colors and heights this way provides a tiny bit of a performance improvement.
I'm start using Django-MPTT app to get a tree-based approach on my Django-site pages.
For ex. I have pages with sub pages:
Trance:
Vocal Trance(sub page)
Hard Trance(sub page)
Breaks:
Atmo Breaks(sub page)
Progressive Breaks(sub page)
How can I get access to them from urls.py?
What pattern will help?
Do I need to store Full_path in model or it can be done via url pattern?
I assume you mean you want to do URLs like this:
/trance/
/trance/vocal-trance/
/trance/hard-trace/
/breaks/
/breaks/atmo-breaks/
/breaks/progressive-breaks/
If so, it's probably best to store the url fragment in your model. Something like:
from mptt.models import MPTTModel
from django.db import models
from django.template.defaultfilters import slugify
class Page(MPTTModel):
name = models.CharField(max_length=50)
slug = models.CharField(max_length=50,null=True)
url = models.CharField(max_length=255,null=True)
def save(self, *args, **kwargs)
if self.slug is None:
# create a slug that's unique to siblings
slug = slugify(self.name)
self.slug = slug
siblings = self.get_siblings()
i = 1
while siblings.filter(slug=self.slug).exists():
i += 1
self.slug = slug + '-%d' % i
# now create a URL based on parent's url + slug
if self.parent:
self.url = '%s/%s' % (self.parent.url, self.slug)
else:
self.url = self.slug
super(Page, self).save(*args, **kwargs)
Then add a URL pattern:
(r'^pages/(?P<page_url>[\w\d_/-]+)/$', 'pages.views.show_page'),
And in your view you can just fetch the right page:
def show_page(request, page_url=None):
page = get_object_or_404(Page, url=page_url)
...
Thank you for your attention to my problem.
See,How I finally do it.
models.py
class WebPage(MPTTModel):
slug=RuSlugField(max_length=20,unique=True)
title=models.CharField(max_length=50)
content=models.TextField()
parent=TreeForeignKey('self',null=True,blank=True,related_name='children')
class MPTTMeta:
order_insertion_by=['slug']
def get_absolute_url(self):#TODO:: replace with get_ancestors
url = "/%s/" % self.slug
page = self
while page.parent:
url = "/%s%s" % (page.parent.slug,url)
page = page.parent
return url
urls.py
urlpatterns = patterns('website.views',
url(r"^add/$", "add_page",name="add"),
url(r"^(?P<full_slug>.*)/add/$", "add_page",name="add"),
url(r"^(?P<full_slug>.*)/edit/$", "edit_page",name="edit"),
url(r'^$', ListView.as_view(model=WebPage,template_name='index.html',context_object_name="webpages_list",),name='index'),
url(r"^(?P<full_slug>.*)/$", "page", name="page"),
)
views.py
def page(request, full_slug):
# Make a list from full_slug.
# For ex. /trance/progressive_trance/fonarev -> ['trance','progressive_trance','fonarev']
slugs=full_slug.split('/')
page=None
# Get a page by it's slug
if len(slugs)>1:
page=get_object_or_404(WebPage,slug=slugs[-1])#slugs=['trance','vocal_trance'] -> 'vocal_trance'
elif len(slugs)==1:
page=get_object_or_404(WebPage,slug=slugs[0])#slugs=['trance'] -> 'trance'
# Check if page url matches requested full_slug
if page.get_absolute_url().strip('/') == full_slug:
return render_to_response('page.html', {'page': page},context_instance=RequestContext(request))
else:
raise Http404
def edit_page(request,full_slug):
slugs=full_slug.split('/')
page=None
if len(slugs)>1:
page=get_object_or_404(WebPage,slug=slugs[-1])
elif len(slugs)==1:
page=get_object_or_404(WebPage,slug=slugs[0])
if not page.get_absolute_url().strip('/') == full_slug:
raise Http404
# Send POST data for update an existing page.Update a page.
if request.method=='POST':
form=WebPageForm(request.POST, instance=page)
if form.is_valid():
form.save()
return HttpResponseRedirect(page.get_absolute_url())
# Render a form to edit data for existing page
else:
form=WebPageForm(instance=page)
return render_to_response('edit_page.html',{'form':form,},context_instance=RequestContext(request))
def add_page(request,full_slug=None):
parent_page=None
slug=None
if full_slug:
slug=full_slug.split('/')
# If there is a slug in REQUEST(ex.'trance')->we need to add a new_page to her parent_page.
# So get a parent page.
if slug:
if len(slug)>1:
parent_page=get_object_or_404(WebPage,slug=slug[-1])
elif len(slug)==1:
parent_page=get_object_or_404(WebPage,slug=slug[0])
# Create a new_page
if request.method=='POST':
form=WebPageForm(request.POST)
if form.is_valid():
new_page=form.save(commit=False)
if parent_page:
new_page.parent=parent_page
new_page.save()
return HttpResponseRedirect(new_page.get_absolute_url())
# Return an unbounded form
else:
form=WebPageForm()
return render_to_response('add_page.html',{'form':form,},context_instance=RequestContext(request))
The trick is in we have to check if the page really exists accessing to it via full_slug:
if not page.get_absolute_url().strip('/') == full_slug:
raise Http404
Otherwise, it could be wrong allowing to check only by slug.
There's also a django app that will do the work for you: django-mptt-urls
def get_absolute_url(self):
return '/'.join([x['slug'] for x in self.get_ancestors(include_self=True).values()])