Discussion:
[Urwid] Updating objects buried several layers deep
Matthew Mosesohn
2013-08-12 17:11:31 UTC
Permalink
Hi all,

I'm trying to make a useful tool that has 2 main columns: menu and
module. Modules get loaded dynamically from a folder and return an
urwid.Listbox with an urwid.SimpleListWalker inside it. The menu lets
me navigate between different modules.

I can get information displayed once, but I want to be able to click a
RadioButton and display information relevant to that object.

In this specific case, I want to display networking information. Here
is some relevant code:

---- start code ----
def getNetwork(self):
"""Uses netifaces module to get addr, broadcast, netmask about
network interfaces"""
import netifaces
for iface in netifaces.interfaces():
if 'lo' in iface or 'vir' in iface:
#if 'lo' in iface or 'vir' in iface or 'vbox' in iface:
continue
#print netifaces.ifaddresses(iface)
#print iface, netifaces.ifaddresses(iface)[netifaces.AF_INET][0]
self.netsettings.update({iface:
netifaces.ifaddresses(iface)[netifaces.AF_INET][0]})


def get_default_gateway_linux(self):
"""Read the default gateway directly from /proc."""
with open("/proc/net/route") as fh:
for line in fh:
fields = line.strip().split()
if fields[1] != '00000000' or not int(fields[3], 16) & 2:
continue

return socket.inet_ntoa(struct.pack("<L", int(fields[2], 16)))
def radioSelect(self, obj, other):
self.activeiface = obj.get_label()
self.gateway=self.get_default_gateway_linux()
self.getNetwork()
self.screenUI() ### called later to create text objects
self.listbox_content=[self.net_text1, self.net_text1,
self.net_text2, self.net_text3,
self.net_text4, self.net_choices]
self.listwalker[:]=[self.parent.cols]

...

def TextField(keyword, label, width, default_value=None):
"""Returns an Urwid Edit object"""
edit_obj = urwid.Edit(('important', label.ljust(width)), default_value)
wrapped_obj = urwid.AttrWrap(edit_obj, 'editbx', 'editfc')
return wrapped_obj

def ChoicesGroup(self, choices, default_value=None):
"""Returns a horizontal Urwid GridFlow with radio choices on one line."""
rb_group = []

for txt in choices:
if default_value == None:
is_default = "first True"
else:
is_default = True if txt == default_value else False
radio_button = urwid.AttrWrap(urwid.RadioButton(rb_group,
txt, is_default, on_state_change=self.radioSelect),
'buttn','buttnf')
wrapped_choices = urwid.Padding(urwid.GridFlow(rb_group, 13, 3, 1,
'left'), left=4, right=3, min_width=13)
return wrapped_choices


...

self.net_text1 = TextLabel("Current network settings for %s" %
self.activeiface)
self.net_text2 = TextLabel("IP address: %s" %
self.netsettings[self.activeiface]['addr'])
self.net_text3 = TextLabel("Netmask: %s" %
self.netsettings[self.activeiface]['netmask'])
self.net_text4 = TextLabel("Default gateway: %s" % (self.gateway))
self.net_choices = ChoicesGroup(self,
self.netsettings.keys(),self.activeiface)
self.listbox_content=[self.net_text1, self.net_text2, self.net_text3,
self.net_text4, self.net_choices]
self.listwalker=urwid.SimpleListWalker(self.listbox_content)
screen = urwid.ListBox(self.listwalker)
return screen
--- end code ---

I apologize for skimming base level code and my wrapper functions, but
it keeps the modules lighter and more readable. I can get changes
made if I manually set_text on each Text object, but it's quite manual
to do this. I would much rather call screenUI() and let every object
get recreated and rendered.

Updating the listwalker of the top level parent works if I change
objects in the very topmost layer, but if I change any listwalker that
isn't the very top one, I don't get any results. I wonder if it is a
bug or there are other ways to inform Urwid I want to redraw the
screen with my new widgets.

Does anyone have some great suggestions or examples where you can
update a nested listwalker?

-Matthew Mosesohn
Ian Ward
2013-08-13 13:38:22 UTC
Permalink
On Mon, Aug 12, 2013 at 1:11 PM, Matthew Mosesohn
Post by Matthew Mosesohn
Updating the listwalker of the top level parent works if I change
objects in the very topmost layer, but if I change any listwalker that
isn't the very top one, I don't get any results. I wonder if it is a
bug or there are other ways to inform Urwid I want to redraw the
screen with my new widgets.
Does anyone have some great suggestions or examples where you can
update a nested listwalker?
I suggest writing a custom ListWalker for this. From there you have
control over invalidation and exactly how all the displayed contents
are stored.

Ian
Matthew Mosesohn
2013-08-13 13:44:11 UTC
Permalink
Ian,

Thanks for the idea, but I gave up and just ran edit_text on all my objects.
Post by Ian Ward
On Mon, Aug 12, 2013 at 1:11 PM, Matthew Mosesohn
Post by Matthew Mosesohn
Updating the listwalker of the top level parent works if I change
objects in the very topmost layer, but if I change any listwalker that
isn't the very top one, I don't get any results. I wonder if it is a
bug or there are other ways to inform Urwid I want to redraw the
screen with my new widgets.
Does anyone have some great suggestions or examples where you can
update a nested listwalker?
I suggest writing a custom ListWalker for this. From there you have
control over invalidation and exactly how all the displayed contents
are stored.
Ian
_______________________________________________
Urwid mailing list
Urwid at lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.excess.org/pipermail/urwid/attachments/20130813/bad8c7b6/attachment.htm
Loading...