Forum Archive

Sub views of NavigationView are not accessible

marcus67

Using the UI editor I have created an instance of a "NavigationView" with several "Buttons" as subviews to push the child views. So far I had handled the control of the sub views individually, meaning I explicitly hardcoded the calls to push_view. Now I tried to this generically by accessing the button views using the "[]" operator and the buttons' names. However, none of the buttons could be found by name. Using the "subviews()" method I tried to iterate over the subviews only to find that the NavigationView does not seem to have a single sub view. Is this intended? Are NavigationViews treated in a special way when it comes to view hierarchy? Or is this a bug?

papahabla

I'm also unsure how to use the NavigationView in this way. I've placed a tableview within the nav and I'm unsure how to access this root view in code to set the delegate and data source so that I can push selected table rows onto the stack. I know that I can call push and pop once I have an initial selection, however.

JonB

Can you post your pyui so we can understand what you are trying to do?

Or a little more explanation of how you created your view. Why are you trying to access the button's using [] rather than using sender? Are the buttons in "pushed" views, or truly subviews of the NV. Or as left_buttons / right_buttons in the title bar?

The pushed views of a NV are not subviews, yes it is strange.

If you want to see where your buttons live, you could use print sender.superview, and so on up the superview chain until you get to the top view.

marcus67

I'm afraid I have to ask a very stupid question: How do I access the pyui files? There's an export feature for the py the files but I haven't found one for the pyui files. To me they are still black boxess still. Thanks!

Webmaster4o
with open('file.pyui','r') as f:
    print f.read()
ccc

You might want to pprint.pprint() instead of just print().

dgelessus

@ccc f.read() returns a string, pprint doesn't do bupkis here. ;) The proper way to prettify the JSON would be to json.load it, and then json.dump it into sys.stdout with indent=4 or indent="\t".

Webmaster4o

However, if all he's concerned about is exporting, formatting doesn't matter, he just needs text to copy/paste

ccc

@dgelessus Good catch... I should have just linked out to pyui_print.py instead of responding so quickly.

Phuket2

If he is on 1.6 he can just rename the pyui file with a 'json' extension , then can rename it back again with the 'pyui' extension

papahabla

The issue seems to be something like the following...

When starting from a new pyui file, if you add a navigation view and then add views within the nav view using the UI designer, those views do not appear as .subviews. Where are they? I think that this is essentially an attempt at creating a root view of the nav controller. Also an issue with this approach is that any subsequent views pushed to the stack will underlay the buttons and touch event on the pushed view will not work.

One solution could be to instead programmatically push another pyui file with your buttons onto the nav stack. However, this results in odd behavior because the view pushed will seem to be the second view on the stack. I.e. You will be able to navigate backwards to an empty view from the button view.

I can't seem to find any relevant example code.

JonB

yes it does appear that the "subview" of a navigationview in the ui editor sets the root view. But since you cannot easily access the rootview of a navigationview after it is created this leads to some awkward situations.

Here is a way to get the rootview of a nav view, which only relies on a small bit of gc magic:

def get_navigationview_root(nv):
   o=[v for v in gc.get_objects() if hasattr(v,'navigation_view') and v.navigation_view==nv and not v.superview]
   return o[0]
marcus67

@JonB After the issue of NavigationViews has been dormant for a while I picked it up again and tried your little helper function. Unfortunately, it did not work for me since the object set always seems to be empty for navigation views.

JonB

turns out you must present the view before this trick works. here I created a view in the ui editor, added a navigationview, then added a subview to the navigation view, to which i added a button. after loading then presenting, you can find the view which the nav view is showing. (this works for finding the active view of a navigation view, since other views will not have the navigation_view attribute pointing at the nav view object). If you gave the view a unique viewname, you could filter by name and that should work before the nv is presented. It would also be possible to store a list of views from gc before and after loading the view, and then filtering by name, or views with no superviews, etc. just make sure you delete the list so you don't hang onto references to discarded objects.

import ui,gc

v = ui.load_view()
nv=v.subviews[0]

def get_navigationview_root(nv):
   o=[v for v in gc.get_objects() if hasattr(v,'navigation_view') and v.navigation_view==nv and not v.superview]
   if o:
    return o[0]
root=get_navigationview_root(nv)
print root  #None
v.present('sheet')
root=get_navigationview_root(nv)
print root #<_ui.View object at 0x48a0c34>
ccc
    o=[v for v in gc.get_objects() if hasattr(v,'navigation_view') and v.navigation_view==nv and not v.superview]
   if o:
    return o[0]

This is probably a place where a list comprehension is not your friend.

    v for v in gc.get_objects():
        if hasattr(v, 'navigation_view') and v.navigation_view == nv and not v.superview:
            return v
    return None  # explicit is better than implicit

allows you to stop building a list of all gc objects immediately after you have found the one that you want.