Problem
Quixote's quixote.form2 package generates a user interface automatically. Your code should add widgets to the form and then render the form (call the form's render method).
However, there are some things that you can do to customize the the look of the user interface. This entry suggests several ways to customize the way in which forms and widgets from the quixote.form2 package are rendered.
Solution
Ordering the widgets
Widgets are rendered, from top to bottom, in the same order that you add them to the form. You can change their order by changing the order in which you add them to the form
Adding labels and hints
Use the title argument of the form2.Form.add method to give a widget a title.
Use the hint argument of the form2.Form.add method to give the widget additional user information. The hint is (by default) displayed to the right of the input item.
Here is an example:
zipForm.add(form2.StringWidget, 'user_name', '[enter user name]', title='User name:', hint='Enter your name', size=40, required=False)
Customizing rendering of the form
To customize the way in which the form and the widets in it are rendered, do the following:
Create a subclass of form2.Form.
Override the rendering methods in form2.Form, for example _render_body, _render_sep, and _render_components, _render_start, and _render_finish.
Then create and use an instance of your subclass of form2.Form, instead of form2.Form itself.
Here is an example:
class MyForm(form2.Form): def _render_body(self): r = TemplateIO(html=True) r += htmltext('<table border="0" width="100%">') r += self._render_error_notice() r += self._render_components() r += self._render_button_widgets() r += htmltext('</table>') return r.getvalue() def render_sep(self): return htmltext('<tr><td colspan="3"><hr/></td></tr>') def _render_components(self): r = TemplateIO(html=True) firstTime = True for component in self.components: if not firstTime: r += self.render_sep() firstTime = False r += component.render() return r.getvalue()
Explanation:
This subclass adds a horizontal rule (tag <hr/>) between widgets. See method render_sep.
Customizing rendering of the widgets
By default, each widget is rendered in a pair of table rows within an HTML table. We can change this and can change the way in which each widget is rendered by (1) subclassing the class form2.WidgetRow and then (2) instructing the form to use this subclass.
Here is an example in which we render each widget in a single row:
class MyWidgetRow(form2.WidgetRow): def render(self): title = self.title or '' if title and self.required: title = title + htmltext(' *') r = TemplateIO(html=True) r += htmltext('<tr><th width="15%" align="left">') r += title r += htmltext('</th><td>') r += self.widget.render() r += htmltext('</td><td>') r += self._render_error() r += self._render_hint() r += htmltext('</td></tr>') return r.getvalue()
Explanation:
We've subclassed form2.WidgetRow and overridden method render.
Our new render method is a copy of the superclass's method, except that it puts the title, the input item, and the hint all in a single row. That is, it eliminates one pair of <tr> tags.
Then, we create a form that uses our subclass with something like the following:
aSimpleForm = form2.Form(name='simple_form', action_url='show_contents', component_class=MyWidgetRow )
Discussion
Here are some links to form2:
http://www.rexx.com/~dkuhlman/quixote_uihowto.html - Quixote User Interface How To
http://curtis.med.yale.edu/dchud/log/project/sentinel/form2-user_ui-overview.html - Quixote form2 overview: a sample user admin panel
http://curtis.med.yale.edu/dchud/log/project/sentinel/form2-sample-user_ui.ptl