Creating and Extending Components

The most fundamental and widely used class within the Echo framework is Component. It is an abstract base class which serves as the foundation for all user interface components. Every Echo component is derived from the Component class.

As an Echo developer, you will often wind up extending Component in one way or another, be it for creating a reusable component that will be used across many applications, or in creating a visual piece of a single application. As such, it is important to know how the Component class works.

Component Hierarchies

Components are assembled into hierarchies in order to create user interfaces. This has been demonstrated throughout the course of this tutorial with the various tutorial applications. The component class itself provides the fundamental methods required to create these hierarchies.

A component is added as a child of another component by invoking one of the to-be-parent component's add() methods. Likewise, the remove() methods are used to remove children from a component.

While all components have add() and remove() methods, many do not support their use. Some of these components, such as Button, Label, and TextComponent plainly do not provide support for child components. Other such components, such as Table, Grid and AbstractPane do support children, but forbid developers from calling the Component class' add() and remove() methods. Components that do not support public use of the add() and remove() methods will have undefined behavior if the methods are nevertheless invoked externally. Consult the API Documentation on a component before attempting to add children beneath it.

Hierarchy Events

A Component will fire events when its state changes within a hierarchy of components. Such events are described using the HierarchyEvent object. A HierarchyEvent is fired when one or more of the following take place:

  • The registration state of a component changes. A component is said to be registered when it is a member of a hierarchy whose ultimate ancestor is a Window that has been registered (added) to an EchoInstance (i.e., by way of a call to addWindow()).
  • The showing state of a component changes. A component's showing state is changed when a visible component is registered or unregistered, or when a registered component is made visible or non-visible.
  • A component's parent component is changed.

A single HierarchyEvent may reflect an adjustment to several of the above component/hierarchy state changes. The event may be queried for information describing the particulars of the state change using its getChangeFlags() method or by calling other convenience methods, e.g., isShowingChanged().

In order to receive notification of HierarchyEvents, the to-be-notified object must implement the HierarchyListener interface, and register itself with the listened-to Component, using the addHierarchyListener() method.

Initialization

The component class contains a method, init(), which is used for initialization purposes. This method is intended to be overridden if necessary when extending a component, and in many ways plays a role similar to a constructor. The method is invoked the first time the component becomes part of a registered hierarchy of components. Its primary purpose is to provide a place for constructor-like beginning-of-lifecycle code to be placed that will only be invoked once the component is part of a hierarchy, and therefore can return a non-null value when its getEchoInstance() method is invoked. This can be very beneficial as information such as the intial Locale as well as application-wide state information will not be available without access to the EchoInstance, and a reference to it may not automatically be obtained during the execution of the constructor.

When creating a component that overrides its init() method, it is critical to invoke super.init(). This method should be invoked before any other actions are taken within the method. Failure to call super.init() will result in the superclass not having a chance to perform its initialization tasks, which will cause undefined and undesired behavior.

Validation

Echo's "validation" facility provides components a chance to prepare to be rendered. Before a component is rendered into HTML form by the Echo application container, it will first undergo a process known as validation. During validation, the component hierarchy is traversed from the top down and the validate() method of every component is invoked. By default the Component class provides an empty implementation of validate(). It is intended to be overridden by components that require validation functionality.

The purpose of the validate() method is to provide components with an opportunity to optimize performance. In certain cases, components may be more efficient if they are allowed to exist in a state unsuitable for rendering until just before rendering is to occur. An example of such a component can be found in Echo's own Table component. Tables will only render their internal data into child Components when the validate() method is invoked. This is done to avoid having to unnecessarily re-render every time the application makes an adjustment.

When overriding the validate() method, it is critical to invoke super.validate() in order to give the Component's superclass a chance to validate itself. This should be done before any other operations in your implementation of validate(). Failing to call super.validate() will result in undefined behavior.

The Container Component

A Container is a trivial concrete implementation of the Component class. Containers provide no additional visual function, they only serve to "wrap" multiple components into a single component.