AjaxSwing renderers and updaters can
be used to support custom components and to override HTML generation for
standard components (java.awt.* and javax.swing.*). Only one custom renderer per application is allowed in
the Standard Edition, and if you need more renderers you need to purchase an
appropriate commercial license. AjaxSwing maintains a map of components and their renderers.
When iterating children of a container generate HTML page AjaxSwing first
determines the name of the class of each child component. Then it tries to lookup
the renderer for this component in the map of renderers. If a renderer
is found, it is instantiated and used, otherwise the superclass of the component
is checked for a registered renderer. If no renderer is found for any class in the component
hierarchy, AjaxSwing uses a universal
SnapshotRenderer that can render any
component as an image on a page.
Supporting custom GUI components requires creating a Freemarker template or coding and registering a renderer class
Creating a template is easier and more straightforward, so it is a good choice for components that map cleanly to HTML
code. Developing a renderer class is a better choice in cases where a lot of logic needs to be evaluated or calculated
to produce HTML. Renderer class is also faster and more maintainable because it doesn't rely on reflection like the
Freemarker template. Finally, both approaches can be combined by extending com.creamtec.ajaxswing.rendering.html.TemplateRenderer
and preparing extra component-specific data for the template.
.html pattern.
For example, if AjaxSwing is installed into C:/AjaxSwing directory and the custom component class is com.creamtec.ajaxswing.ui.CustomPanel,
then the template file name should be c:/AjaxSwing/conf/templates/custom-components/com.creamtec.ajaxswing.ui.CustomPanel.html.
Templates syntax must follow Freemarker rules. The following data objects are available to the template:
- page - currently rendered HTMLPage
- agent - ClientAgent
- component - component to be rendered
- id - id/name of the component to be rendered
- style - component style attributes derived from Swing component
Note that all methods and properties of objects are available to the template via Freemarker expressions. See
AjaxSwing/conf/templates/default-component/com.creamtec.ajaxswing.ui.CustomPanel.html
template for an example of container template.
Custom component renderering using a renderer class (similar to a servlet)
Writing renderer is similar
to writing a servlet that only produces a portion of a page.
All renderers must implement com.creamtec.ajaxswing.rendering.ComponentRenderer
interface. If you look at ComponentRenderer interface, you would see that it is very
simple and defines two methods
void initializeDocument (Document document)
throws Exception
This method is by AjaxSwing
to initialize
the newly created HTML page. It gives the renderer an opportunity to include
external stylesheets and JavaScript files and to generate other header content. This
method is only called once per page creation. Updates to page are sent
via AJAX and applied only to the page elements that have changed.
void renderComponent (Document document, Object component)
throws Exception
This method is called to append
the HTML representation of the component to the page. This code can be as simple
as <IMG> tag or as complex as <IFRAME></IFRAME> section.
The passed document
is the output document that will be returned to the client. For HTML generatation
it is an instance of com.creamtec.ajaxswing.rendering.html.AjaxPage. Component is the instance of the component to be
rendered. Since AjaxSwing uses positioning of components and styles, it is
highly recommended to invoke PageRenderer's appendComponentStyle() method which
will append coordinates and size of the component. See API JavaDoc and
CustomComponentProcessor.java
on specifics of what methods to use and required parameters.
Registering the custom renderer with AjaxSwing
Once a custom renderer class has been developed, it has to
be registered with AjaxSwing. This is done by adding an entry to the application's
properties file in the conf directory. The entry follows format <render>.<package_name>.<class_name>=
<renderer_class_name>. For example, to use our example renderer com.creamtec.ajaxswing.examples.CustomControlProcessor
for component com.creamtec.ajaxswing.ui.CustomControl in your application MyFirstApp you will add the
following line to <AjaxSwing>/conf/MyFirstApp.properties
render.com.creamtec.ajaxswing.ui.CustomControl=com.creamtec.ajaxswing.examples.CustomControlProcessor
Similarly, if you want to use your CustomControlProcessor to render Swing's JSlider
you can use
render.javax.swing.JSlider=com.creamtec.ajaxswing.examples.CustomControlProcessor
Custom Updater
As you have learned, custom renderers allow you to extend
AjaxSwing by providing logic to render unsupported controls to HTML page. But
what if the control is an input field such as a text field or a radio button?
Generating HTML for it will allow the user to see it on the page, but if the
user changes the value of the field how would it get propagated back to the
UI element such as JTextField? The solution for this is to add a custom ComponentUpdater.
Component updaters are used by AjaxSwing engine to set values received from the
browser to the UI elements. It can be as simple as calling a setText() on a
JTextField and as complicated as synchronizing the JTable model to match the
new values received from the HTML table. Just like custom renderers, updaters
need to be registered for the controls that they support. For example, the line
below tells AjaxSwing to use CustomControlProcessor to update CustomControl
update.com.creamtec.ajaxswing.ui.CustomControl=com.creamtec.ajaxswing.examples.CustomControlProcessor
Custom updaters must implement ComponentUpdater interface and provide implementation
for updateComponent method. The implementation is specific to the control and
the rendering that was used to represent it on HTML page. The parameter values
submitted by the browser are available thru HttpRequestData structure. See Javadoc
for more information.
Implementation Example for a Custom Control
WindowsThemeDemo includes a custom control and a processor which acts as the renderer
and updater for it to support the control in HTML. The source files are provided
for your reference and as a guideline for implementation. Custom control in
this demo extends JComponent and contains a JCheckBox and a JLabel. The checkbox
specifies whether the label should be drawn with "3D" effect or not.
Run WindowsThemeDemo as a stand alone Java application to see how the control works
(go to Dialogs->Fixed Dialog in the menu). If you try to run the demo as-is
in AjaxSwing you would see familiar "Unsupported class" link saying
that com.creamtec.ajaxswing.ui.CustomControl is not supported. To solve this problem
we provide CustomControlProcessor which implements both ComponentRenderer and
ComponentUpdater, and register it in conf/WindowsThemeDemo.properties file. CustomControlProcessor
does in HTML what CustomControl does in GUI - draws a shade under the label
to make it look 3D-like. It's a simple but a complete real life example.
CustomControl.java
CustomControlProcessor.java