Issue with weakref in dropdown - Kivy ids

98 views
Skip to first unread message

Shoumik Das

unread,
Jul 12, 2020, 7:16:14 AM7/12/20
to Kivy users support
Hi! I have a weird issue at hand. I have built a small app with multiple screens and a custom drop down implemented in each screen. The drop downs seem to work fine till the time I switch screens and reactivate any of the drop downs. I then get the following error:

ReferenceError: weakly-referenced object no longer exists

Drop down working fine



Navigate to a different screen. The time zone drop down also works fine.




Return back to the old screen and re-select a drop down



I initially thought that it might be because I am using the inspector tool which is still in an experimental phase but then I tested the scenario without launching the inspector tool and I still get the same weak reference error. I have set a different id for each of the drop downs that I am using in the Kivy file.

Sample Python code:

class ImageLabel(BoxLayout):
source = StringProperty('images/expand-arrow-48.png')
text = StringProperty('User')


class ImageLabelButton(ButtonBehavior, ImageLabel):
pass


class ImageLabelButtonTop(ButtonBehavior, ImageLabel):
pass

Kivy Code:

<SivaStatusScreen>:
name: 'status_screen'
canvas.before:
Color:
rgba: 255/255, 255/255, 255/255, 1
Rectangle:
pos: self.pos
size: self.size
AnchorLayout:
id: status_add
anchor_x: 'right'
anchor_y: 'bottom'
ImageButton:
id: status_addbtn
source: {'normal': 'images/plus-96.png', 'down': 'images/plusblue-96.png'} [self.state]
size_hint: 0.2, 0.2
on_release: root.new_status_entry()
BoxLayout:
id: status_layout
orientation: 'vertical'
BoxLayout:
id: actionbar_layout
size_hint_y: None # size the box layout to contain the action bar
height: 48 # width of the action bar in line with the minimum dimensions of the icons
ActionBar:
id: status_actionbar
pos_hint: {'top': 1}
background_image: ''
background_color: 195/255, 60/255, 35/255, 1
ActionView:
use_separator: True
ActionPrevious:
title: 'SIVA'
with_previous: False
ActionOverflow:
CustomActionButton:
id: status-button
important: True
source: {'normal': 'images/communicationgreen-48.png', 'down': 'images/communication-48.png'} [self.state]
on_release: root.to_statusscreen()
CustomActionButton:
id: accounts-button
important: True
source: {'normal': 'images/key-48.png', 'down': 'images/keygreen-48.png'} [self.state]
on_release: root.to_accountsscreen()
CustomActionButton:
id: bot-button
important: True
source: {'normal': 'images/bot-48.png', 'down': 'images/botgreen-48.png'} [self.state]
on_release: root.to_botscreen()
CustomActionButton:
id: logout-button
important: True
source: {'normal': 'images/shutdown-48.png', 'down': 'images/shutdowngreen-48.png'} [self.state]
on_release: root.to_logout()
BoxLayout:
id: status_display
# size_hint is not needed. This Layout shares space with the BoxLayout that has a fixed y size, it will grow to fill the space.
orientation: 'vertical'
BoxLayout:
id: status_label
size_hint_y: None
height: 40
orientation: 'horizontal'
BoxLayout:
orientation: 'horizontal'
Image:
keep_ratio: True
source: 'images/communication-48.png'
Label:
text: 'Status'
markup: True
color: 0, 0, 0, 1
ImageLabelButtonTop:
# conflict in the on_release defined for ImageLabelButton and this instance.
id: parent_button
source: 'images/expand-arrow-48.png'
text: 'User'
on_release:
# root.add_dd_values()
dropdown.open(self)
on_parent: dropdown.dismiss()
size_hint_y: None
height: '40dp'
DropDown:
id: dropdown
on_select:
# args is a reserved keyword which returns only two values: object alias (0) and data (1).
parent_button.text = args[1][0]
parent_button.source = args[1][1]
# Invoked inside dropdown
# root - Screen, self - DropDown object
ImageLabelButton:
source: 'images/twitter-circled-48.png'
text: 'Twitter'
ImageLabelButton:
source: 'images/linkedin-circled-48.png'
text: 'LinkedIn'
BoxLayout:
id: status_content



<ImageLabel>:
orientation: 'horizontal'
size_hint_y: None
height: '40dp'
spacing: 1
canvas.before:
Color:
rgba: 255/255, 255/255, 255/255, 1
Rectangle:
pos: self.pos
size: self.size
Image:
size_hint_x: 0.3
keep_ratio: True
source: root.source  # root - ImageLabel
Label:
size_hint_x: 0.7
markup: True
halign: 'center'
valign: 'middle'
text: root.text  # root - ImageLabel
color: 0, 0, 0, 1


<ImageLabelButton>:
on_release:
# Tuple returned in dropdown.select() method to pass two values bundled as one.
app.root.get_screen('status_screen').ids.dropdown.select((self.text, self.source))
# Invoked inside ImageLabelButton rule
# app.root - Screen, root - ImageLabelButton object, self - ImageLabelButton object

Can you please suggest as to what I am doing wrong? Is there a problem in the way I am accessing the drop down fields using their ids?

Thanks in advance.

Elliot Garbus

unread,
Jul 12, 2020, 8:51:36 AM7/12/20
to kivy-...@googlegroups.com

It looks like this should solve your issue:

Read:  https://kivy.org/doc/stable/guide/lang.html#referencing-widgets

 

An id is a weakref to the widget and not the widget itself. As a consequence, storing the id is not sufficient to keep the widget from being garbage collected. To demonstrate:

<MyWidget>:
    label_widget: label_widget
    Button:
        text: 'Add Button'
        on_press: root.add_widget(label_widget)
    Button:
        text: 'Remove Button'
        on_press: root.remove_widget(label_widget)
    Label:
        id: label_widget
        text: 'widget'

Although a reference to label_widget is stored in MyWidget, it is not sufficient to keep the object alive once other references have been removed because it’s only a weakref. Therefore, after the remove button is clicked (which removes any direct reference to the widget) and the window is resized (which calls the garbage collector resulting in the deletion of label_widget), when the add button is clicked to add the widget back, a ReferenceError: weakly-referenced object no longer exists will be thrown.

To keep the widget alive, a direct reference to the label_widget widget must be kept. This is achieved using id.__self__ or label_widget.__self__ in this case. The correct way to do this would be:

<MyWidget>:
    label_widget: label_widget.__self__

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/d72ae362-5f1b-43eb-a93f-b7fe9febd790o%40googlegroups.com.

 

Shoumik Das

unread,
Jul 13, 2020, 1:02:00 PM7/13/20
to Kivy users support
That was magic. Fixed my issue! I was a bit confused about weakrefs since I started learning Kivy a few months ago. This has cleared my doubts. Thank you very much.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Reply all
Reply to author
Forward
0 new messages