Kivy RecycleView: Get indices of all data items that are currently in view - python-3.x

I need to get the indices of all data items that are currently in view in a Kivy RecycleView widget. I want to display many Image widgets for which I render a texture and apply it to them. To save memory I need to delete these textures if they are not in view any more. I tried using the Kivy RecycleView example and modify it for my needs:
class SelectableImage(RecycleDataViewBehavior, Image):
def refresh_view_attrs(self, rv, index, data):
#Catch and handle the view changes
#print in view
print(index)
#call initial function of image class
return super(SelectableImage, self).refresh_view_attrs(rv, index, data)
The problem here is that refresh_view_attrs() only fires when a new Image widget gets added to the view. Thus I can only know what that last Image is, but not if there are any other in view. For this I'd also need to know which widget disappeared from the view. Is there any function in the RecycleView widget that I can use to obtain such information? Maybe there is a function that gets called whenever the view changes?

Okay, I found three possible solutions for my issue:
1. Solution
Calculate the position of all the Image widgets yourself and compare it with the position of the scrollbar to get the widgets that are currently displayed.
This is quite hacky and the RecycleView already does this internally. Thus I'd save the unnecessary computing and avoid this approach.
2. Solution
Use the get_visible_view(index) function of the view_adapter property of a RecycleView. This returns the currently visible view associated with index. If it return None, the view associated with index is not visible right now. This is how it's called for example:
self.myRecycleView.view_adapter.get_visible_view(index)
You could loop through the entire length of your data list and check for each item (the index in the list) if it is currently displayed or not.
3. Solution
My favourite approach: Use get_view_index_at(pos) of the layout_manager property to check what view index is at the given coordinates. This way you could check which item is at the top of the RecycleLayout widget and which one is at the bottom. You need to use coordinate transformation though. Example:
#get position at top center of RecycleView (upper limit)
pos = self.myRecycleView.to_local(self.myRecycleView.center_x, self.myRecycleView.height)
#check which items collides with the given position
print(self.myRecycleView.layout_manager.get_view_index_at(pos))
I hope this clears some things up!

Related

Get the contents of a widget in a layout in PyQt

I recently decided to create a small application that simply reads the files in a compressed file and renames them. I went through several UI modules and decided to use PyQt6.
To achieve this, I first created a QWidget that holds the widgets QPushButton and QLineEdit.
The user then types the new name into the QLineEdit widget and select the QPushButton if the file has to be excluded.
Now, this widget that was created will be added into a QVBoxLayout which is then set as the QScrollArea layout.
Here's my problem:
Once I was done creating the scroll area and the list, I wanted to retrieve the content of each widget. For this purpose, I use the findChild method. But it only returns the address of the object.
Is there any way to get the text stored in QLineEdit of each widget? Is it possible to retrieve the text just by knowing its address?
Here's what I tried:
for index in range(self.layout.count()):
widget = self.layout.itemAt(index).widget()
nameFromLineEdit = widget.findChild(QLineEdit).text()
print(nameFromLineEdit)

How to get list of widgets in pyqt?

I am designing a interface with QtDesigner and editing its functionalities with PyQt. One of the widgets that i created has several pushButtons and i want them all to have the property Checkable = True.
So currently what i am doing is:
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
uic.loadUi('./my_widget.ui', self)
self.pushButton_X.setCheckable(True)
self.pushButton_Y.setCheckable(True)
self.pushButton_Z.setCheckable(True)
self.pushButton_ETC.setCheckable(True)
self.show()
Is there any way i can do something like:
pushbuttons_list = self.get_all_pushbuttons()
for i in pushbuttons_list:
i.setCheckable(True)
?
Im trying the answers to this question but i keep getting
> File "./testing_class.py", line 12, in __init__
items = (self.layout.itemAt(i) for i in range(self.layout.count()))
AttributeError: 'builtin_function_or_method' object has no attribute 'count'
Your example failed because all Qt properties can be accessed by calling the attribute (see the parentheses used for self.layout()):
items = (self.layout().itemAt(i) for i in range(self.layout().count()))
Note that this will only get access to the layout items, not the widgets they might (or might not) contain. For this, using comprehensions will only complicate things unnecessarily, as one-liners should be used only as long as they keep the code readable; the comprehension above is already complex enough, and since you will need to cycle through all items anyway, there's little use in it. Just use a for loop, which is far more readable:
for i in range(self.layout().count()):
widget = self.layout().itemAt(i).widget()
if isinstance(widget, QPushButton):
widget.setCheckable(True)
Note that if you have several buttons that you want checkable and you are doing this only to avoid manually setting the checkable property for all of them, you can just use the extended selection mode that is common for all UI elements that allow selection by keeping pressed Ctrl when clicking multiple objects.
The property editor will automatically show all common properties for the selected widgets, and apply the changed property to all of them.
Another option is to use findChildren():
for button in self.findChildren(QPushButton, Qt.FindDirectChildrenOnly):
button.setCheckable(True)
The Qt.FindDirectChildrenOnly flag is required whenever you have complex layouts that have nested widgets containing other buttons, if you remove that you will find any push button that exists inside the window (or the widget referenced as self).
Finally, buttons can be part of a QButtonGroup, which can also be created in Designer. Just select all buttons (as explained above), right click on one of them and select "Assign to button group", and then:
for button in self.buttonGroup.buttons():
button.setCheckable(True)
Note that the self.buttonGroup above is the object name assigned by Designer, if you change it or you create more than one, ensure that the reference matches it.

Mplcursor hover showing _line0 on data points

Does anybody know why I would be getting "_line0" on certain points when using mplcursor hover on rectangles? I created a bunch of rectangles in a subplot and used the following code to create a cursor to show annotation when hovering over them:
def update_annotation(sel):
""" update the annotation belonging to the current selected item (sel) """
# get the label of the graphical element that is selected
label = sel.artist.get_label()
#point = sel.artist[sel.target.index]
# change the text of the annotation
sel.annotation.set_text(label)
sel.annotation.set(position=(1, 10), anncoords="offset points")
sel.annotation.get_bbox_patch().set(fc="yellow", alpha = 1)
sel.annotation.arrow_patch.set(arrowstyle="simple", fc="yellow", alpha=.5)
# create an mplcursor object that shows an annotation while hovering
cursor = mplcursors.cursor(axs[1], hover=True)
# call the function "update_annotation" each time a new element gets hovered over
cursor.connect("add", update_annotation)
However, when I hover over certain datapoint, not only is it REALLY slow to go to where I'm hovering over but it also shows me this:
My guess is that there are too many overlapping data points? If so, does anybody know a way around that and also can somebody explain to me what _line0 even means?
I realize the cursor is hovering over an empty space in the plot but it also shows _line0 when I hover over rectangles. Sometimes it will even show the label and then go back to _line0.

How to avoid usage of Task.Delay while scrolling to a particular point in Scroll View as I am adding children in runtime which are out of view?

Here, I have used a scroll view and children are added upto visible height and the other children are added in runtime while scrolling down. Hence I need to scrollTo a particular point like Scrollview.ScrollTo(x,y) for this I need to calculate y by adding children height.Height is calculated by using delay to bring the view in screen first and I calculate. But need to calculate once the children displayed while scrolling without delay
ScrollViewer.ScrollTo(0, (int)totalheight);
await Task.Delay(500);
totalheight += this.CalculateHeight(ScrollView.GetChildrenAt(i));
Where children view height is return in the last method, but without delay the view become null.

adding image-links to current layout - rebol

I'm playing around with Rebol, and Can't figure out how I can add components from the user back to my layout.
I have a layout that has images, taken from image-urls, linked to articles/videos online. I want to add more images linked to their corresponding articles/videos online, taken from the user as 2 urls (one for the image and one for the article/video).
Do I use a list, add the two links to the list and call the view again using show as the button event? Is there a way to add it without refreshing my whole layout?
You can use a list, but it's a tricky beast. I'll include an example here so that you can evaluate the way it works and if it's right for you.
With a list, you define a layout, then modify the layout dynamically based on some data or other. To illustrate, here's some icons:
icons: [
http://reb4.me/r/html-document.png
http://reb4.me/r/pdf-document.png
http://reb4.me/r/excel-document.png
http://reb4.me/r/word-document.png
http://reb4.me/r/zip-document.png
]
The list style consists of a size, layout and a supply function (and I'm going to zap the edge):
view center-face layout [
across
lst: list 48x240 edge none [image 48x48] supply [
face/image: all [
img: pick icons count
load-image img
]
]
btn "Random" [
icons: random icons
show lst
]
]
Included at the bottom is a button that modifies our data, then redisplays only the list.
Size is 48x240 — list works vertically, calling the supply function (list height / iterative layout height) times. I have five icons, so multiplied the icon height by five.
The [image 48x48] is our iterative layout. Note that we only define one face in this example. Unlike generic layouts, a list layout is created using the layout/tight refinement—you need to be specific if you want alternate spacing.
The supply [...] part is our supply function. This is shorthand for a function that will be created and called to update the list. That function is func [face count index][...] where face is the operative face; count is the position in the list; and index is the face's offset in the iterative layout.
It's key to remember that iterative layout is only created once. As the count increases, you are merely changing the attributes of the faces within that layout.
You only need show the list, not the whole layout.
So from here, you can see the relationship between the data source and the display.

Resources