[Urwid] Screens with forms with fixed-length input fields.

Christopher R. Hertel crh at ubiqx.mn.org
Sun Jun 5 14:21:19 EDT 2011

I raised a question on IRC and got some very good help.  I was asked to
post both problem and solution to the list, so here goes...

I am working on a module to create old-school input screens.  I used
this code as an example:


...but I needed slightly different behavior so I written my own module.
(Note: If you want to view the above referenced code, dig through the
web page a little.  There are several versions.  I used the newest I
could find.)

The demo code at that URL uses the urwid Edit widget for all input.  I
needed a couple of changes to meet my goals.  In particular, the Edit
widget does not support fixed-length input.  Here's a code snippet to
show what I've done:

    prompt  = u.Text( "Gimme Input:", align='right' )
    prompt  = u.AttrMap( prompt, 'normal', 'focusprompt' )
    f_widget = u.AttrMap( TextEdit( "", fwidth ), 'normal', 'focusfield' )
    f_widget = u.Padding( f_widget, width=fwidth+1, right=2 )
    f_widget = [ prompt, ('weight', 2, f_widget) ]
    f_widget = u.Columns( f_widget, dividechars=1 )
    f_widget = u.AttrMap( f_widget, None, {'normal':'focusprompt'} )
    self._widgets.append( f_widget )

The first line creates the prompt Text widget from the string "Gimme
Input:". In my code I use a variable.  Promise.  ;)

The first line after the #comment creates a TextEdit() widget with an
empty edit_text and a fixed width of fwidth (provided in earlier code).

Okay...  with all of that preliminary stuff out of the way, here's what
works and what doesn't:


* By wrapping the TextEdit() widget inside padding with a fixed width,
  the in-focus attributes of the field are limited to the fixed width.
  So, if width=10 and the in-focus attribute is underline, I get
  10-column-wide underlined space. Doesn'tworks:

* The padding width needs to be one more than the actual field maximum
  to accommodate the cursor when the field is full.  Otherwise, the
  field contents scroll and the first character disappears from
  view--which is very confusing to look at on screen.

I would love to figure out how to change the attributes for that one
final column.


* TextEdit() works just fine, thanks to the guidance I received on IRC.


* IntEdit(), like Edit(), does not support a maximum length.  IntEdit()
  also does not support negative numbers.

So I wrote a NumEdit() class...

NumEdit() is a descendant of Edit() because the valid_keys() method in
IntEdit() throws all non-decimal-numeric values back to lower-level
widgets.  That means that accidentally pressed keys ('q' is near '1' on
the keyboard) can have unexpected consequences.  My base-level widget
was looking for 'q' to quit. Pressing 'w' didn't do anything (as
expected) but accidentally pressing 'q' quit the program.  In NumEdit(),
the non-numeric printing keys are filtered out in the insert_text()

Also in NumEdit, I am not using the Edit.caption to display a prompt so
I fudged it to hold the minus sign for negative numbers.  The caption
gets the same normal/in-focus attributes as the edit_text (which may be
a problem in some situations but works fine for my purposes).  So...
what I do is add 2 extra columns to the padding and store ' ' in the
caption if the value is positive and '-' in the caption if the value is
negative.  This works.  No, really!

Chris -)-----

More information about the Urwid mailing list