Can't figure out proper way to reference a widget

193 views
Skip to first unread message

Tyro

unread,
Aug 17, 2017, 4:14:34 PM8/17/17
to Kivy users support

My program is failing because I'm not correctly referring to a particular widget.  The root widget is a ScreenManager (MainInterface).  It has a couple screens.  To one of them, game_screen, I add a progress bar, “pb” (in create_puzzle).  That works.

But when I try to increment the value of the progress bar (in time_left_update), I get: “AttributeError: ‘Screen’ object has no attribute ‘pb’.

I understand (I think) that pb will not be part of the ids dictionary, but I thought the way I refer to it in the time_left_update function should work.  It doesn’t.  Nor does “MainInterface.game_screen.pb”.

Final note:  If I add the progress bar in the kv file, things work (except that the last line, where I try to remove it, does not work).  I’m adding it in the Python code instead, however, because I need to repeatedly create and remove the progress bar.

I would be grateful if someone could straighten me out.

 

 class MainInterface(ScreenManager):

    def __init__(self, **kwargs):

        super(MainInterface, self).__init__(**kwargs)

     

     (doing other things here)... 

 

#Note:  these functions are not part of the MainInterface class. 

def create_puzzle(w,*largs):

   Do some things here…

    pb = ProgressBar(size_hint = (.33, .05), pos_hint = {'x': .33, 'y': .61}, max = 360)

    main.ids.game_screen.add_widget(pb)

    event = Clock.schedule_interval(time_left_update, 1/6)

 

def time_left_update(self,*largs):

    main.ids.game_screen.pb.value += 1

    # line above causes AttributeError: 'Screen' object has no attribute 'pb'

    if main.ids.game_screen.pb.value == 60

        remove_pb()

 

def remove_pb(self):

    event.cancel()

    main.ids.game_screen.pb.value = 0

    main.ids.game_screen.remove_widget(main.ids.game_screen.pb)

Oon-Ee Ng

unread,
Aug 17, 2017, 11:37:21 PM8/17/17
to kivy-...@googlegroups.com
You need to save a reference to the created progress bar.

Or my preferred workaround in this case would simply be to add it in the kv file, not remove it, and instead hide it (I like doing this by changing it's y coordinate to something low, using animations you get the 'slide out of the screen' effect).

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tyro

unread,
Aug 18, 2017, 8:30:36 AM8/18/17
to kivy-...@googlegroups.com
Thank you, Oon-Ee.  Regarding your first suggestion, could I trouble you to show me what you mean by "saving a reference" to the progress bar.  (I thought that creating it and adding it to its parent does that.)  Does my problem have to do with the fact that I create and add it in one function but reference it in another?
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

Bill Janssen

unread,
Aug 18, 2017, 7:50:21 PM8/18/17
to Kivy users support
The problem is that calling "add_widget" on "game_screen" does not add an attribute called "pb":

main.ids.game_screen.add_widget(pb)

"pb" is the name of a local variable.  When you use it as a parameter to a function, that function never even sees the name "pb".  In fact, it adds it to a list, which is stored on the "children" attribute of "game_screen".  So, later on, when you reference "pb" as an attribute of "game_screen", it's saying, "I don't know what he's going on about there!"

This is pretty elemental programming, I have to say.  You might need to read up a bit before you go further.  I've heard good things about "Think Python" (https://www.amazon.com/gp/product/144933072X).

Bill

Tyro

unread,
Aug 19, 2017, 10:00:47 AM8/19/17
to Kivy users support

Bill,

 

    Thanks for your help.  I don’t see my mistake as reflecting ignorance of Python (though my knowledge isn’t great--hence the name I've chosen) but rather an insufficient understanding of Kivy.  I don’t see that I’m passing pb as a parameter to a function.  If one adds a widget to a parent in the kv file, then that widget can be referenced anywhere in the program, within any function or method.  Why, then, I’m wondering, is the same not true when you add a widget to a parent (here pb to game_screen) in the Python code?

ZenCODE

unread,
Aug 19, 2017, 11:30:05 AM8/19/17
to Kivy users support
"If one adds a widget to a parent in the kv file, then that widget can be referenced anywhere in the program".

Not at all. All you you do by using 'add_widget' is 'add a widget'. It does not become magically accessible anywhere. Accessing an object created elsewhere is not really a Kivy issue, but a python/programming  issue. If you want to expose it elsewhere, then you need to expose it. Please post runnable code, otherwise it's all just theory..:-)\

Tyro

unread,
Aug 19, 2017, 6:32:46 PM8/19/17
to Kivy users support
I will try to come up with a minimal bit of code to show the problem.  In the meantime, though, regarding magically accessing a widget, I understood that when I create a widget in my kv file, I can then access that widget anywhere within my program with "root.ids.my_widget," i.e, that the widget is thereby "exposed."  (This is certainly working for me.)  So I thought that when I create a widget within the python code, it would get added to the ids list in the same way.  This is obviously not correct.  If there's a simple way to make this widget accessible from anywhere, please enlighten me.

ZenCODE

unread,
Aug 20, 2017, 3:59:47 PM8/20/17
to Kivy users support
Well, there are ways of exposing a widget. If you add an'id' property in your kv file, then yesn you can access it via the 'ids' property.

But this is not globally available. It is only accessible to the class in which you define it. 'root' in this case refers to this class. So, its difficult to give general advice as this will depend on how you have setup your class structure.

Tyro

unread,
Aug 22, 2017, 11:54:54 AM8/22/17
to Kivy users support
Thanks, ZenCODE.  I'll continue to try to figure this out, but, in the meantime, my bigger problem is that buildozer has suddenly stopped compiling this (or any other) program.  (https://groups.google.com/forum/#!topic/kivy-users/JuMUQ9DAP8A)

Bill Janssen

unread,
Aug 23, 2017, 2:20:40 PM8/23/17
to Kivy users support
kv and Python are not the same language.  The Builder code in Kivy takes the kv description and writes Python code from it in some strange and wonderful way.  But if you are writing it yourself, you've got to do all the nitty-gritty details yourself.  Like finding or creating the "ids" dict on a Widget and registering your pushbutton under the name you'd like to give it, e.g. "pb".

I hope you don't mind me suggesting that you take a bit of time to understand what it is you're doing with this text you're editing.  There's a Coursera course, https://www.coursera.org/learn/learn-to-program, which you might try.

Bill

allaboutmike

unread,
Sep 6, 2017, 8:31:42 PM9/6/17
to Kivy users support
Not sure what your ids are or your layout is, but I have a root widget containing an action bar and a ScreenManager (id: manager), which has several screens under it.
The kv file has this (cut down to just the relevant part I hope):

<RootWidget>:
    manager: manager
    ActionBar:
        id: _action
        # blah blah actionbar stuff

    ScreenManager:
        id: manager
        info: info          # This line is key: it makes the "info" id part of the list of manager's ids, so you can refer to the info id down below as manager.ids.info
        other: other      # same for other
        Screen:
            name: 'Info'
            InfoScreen: #InfoScreen is defined below as a distinct class
                id: info    # This line is key: it gives an id to the screen itself, so you don't have to refer to manager's children to reference it.
        Screen:
            name: 'Lines'
            OtherScreen: #OtherScreen is defined below
                id: other

In my python file (from anywhere!), I get a reference to the root widget like so:
        root = App.get_running_app().root
        root.manager

and root.manager is my ScreenManager.

root.manger.ids.info is a reference to my InfoScreen

If InfoScreen has things you want to reference buried in it, you can use the same trick as above to reference the elements contained in it.
Give them an internalid and make a root level id point to that internalid (each class <classname> is referred to as root by the things in it, remember)
I make them the same, though you may find that confusing.

So if InfoScreen had a ProgressBar, maybe like this:

(KV)
<InfoScreen>:
    pbrootlevelid: pbinternalid
    BoxLayout:
        #some stuff
        ProgressBar:
            id: pbinternalid

you should be able to find it at root.manager.ids.info.ids.pbrootlevelid

I would go with one of the other suggestions and put it in there from the start and adjust visibility or position to "add" and "remove".

Hope that helps!

Tyro

unread,
Sep 19, 2017, 2:56:56 PM9/19/17
to Kivy users support
Mike (I assume), thanks very much for this.  I've been away from programming for a couple weeks so I didn't see it.  I'll look carefully at your suggestion and see if it would work for me.  Thanks again for taking the time.

Gmoo

unread,
Mar 27, 2018, 2:37:08 PM3/27/18
to kivy-...@googlegroups.com
Hi all!

I have a question that is related to the solution that allaboutmike describes. Thanks for your clear answer by the way!

I can reference a widget from my Python file in the manner you describe. I set an 'id' to the widget and I couple a rootlevel-id to the internal-id in the kv file.
 (Additionally I declare the rootlevel-id in the root Python class as an ObjectPropertry(None).

However, when I add a new widget, for example:
self.mainscreen.add_widget(NewWidget(center = self.mainscreen.center, id = 'newwidget'),
how do I make a new rootlevel-id:internal-id connection in the kv file, so that I can reference to the new widget using the rootwidget.ids list?

I hope you know what to do, thanks a lot for the help in advance!





Op donderdag 7 september 2017 02:31:42 UTC+2 schreef allaboutmike:

Gmoo

unread,
Apr 1, 2018, 3:48:39 AM4/1/18
to Kivy users support
Is there please anyone that can help me with this? I really am stuck.. Thank you so much!

Op dinsdag 27 maart 2018 20:37:08 UTC+2 schreef Gmoo:

ZenCODE

unread,
Apr 1, 2018, 7:03:02 AM4/1/18
to Kivy users support
@Gmoo

It's difficult to help when you add on to post with a long history and a lot to read. If you have an issue, please create a new post with a title that accurately describes the issue and ideally, code we can run that shows the issue.

Thnaks

G van M

unread,
Apr 3, 2018, 3:53:20 AM4/3/18
to kivy-...@googlegroups.com
Ah, I'm sorry. I thought it'd be easier. I have posted a new question in a separate post, with runnable code :) Thanks!

Op zo 1 apr. 2018 om 13:03 schreef ZenCODE <zenkey....@gmail.com>:
@Gmoo

It's difficult to help when you add on to post with a long history and a lot to read. If you have an issue, please create a new post with a title that accurately describes the issue and ideally, code we can run that shows the issue.

Thnaks

--
You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/oWNFhkw4VAA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages