Java Gui Builder |
|
You are here: | Home > Documentation > Tutorials > Basic Web Browser Example |
The complete example's file is available as webbrowser.xml.
You have been tasked to create a basic web browser. This new application should have the usual controls: URL field, a Go button, a browser display area, and a menu.
With the previous example, as a guide, you could implement the whole window without effort. Where you would have problems is in the event handling department. Your application needs to respond to user-generated events: the enter key in the URL field, a click on the Go button, active links, item selections in the menus.
The JGB framework implements event handling by having one or more objects be notified when interesting events occur. This is achieved through the Mediator Pattern.
The mediator pattern (PDF link) is a way for a set of objects to collaborate without all of them being aware of every other object.
The mediator pattern achieves this decoupling by having each objects in the set speak with only one other object, the mediator. The mediator is then responsible for managing the interactions between all other objects.
In the JGB framework, the mediator pattern is used to manage the interactions between the different controls in a window. The user is responsible for providing an implementation of this pattern.
You decide to start easy by creating the framework upon which event handling will be attached later on. You start with the following:
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE window PUBLIC "-//SOURCEFORGE/Java Gui Builder DTD version 1.0//EN" "http://jgb.sourceforge.net/dtd/jgb.dtd"> <window id="webbrowser" type="jframe"> <object id="view" class="javax.swing.JEditorPane"> <constructor/> <property name="editable"><value type="boolean" data="false"/></property> <property name="page"> <value type="string" data="http://jgb.sourceforge.net/"/> </property> </object> <controls> <layout class="BorderLayout"/> <constraints> <constant name="java.awt.BorderLayout.NORTH"/> </constraints> <panel layout="GridBagLayout"> <label id="urllabel" text="URL:"/> <textfield id="url" reflabel="urllabel"/> <button id="go" mnemonic="g" text="Go !"/> </panel> <panel layout="GridBagLayout"> <control class="javax.swing.JScrollPane"> <property name="viewportView"><ref refid="view"/></property> </control> </panel> </controls> </window>
If you execute this window sample, you will not get the same look as the final window. This example cuts to the heart of the matter by ignoring most layout management issues. You should consult the actual example source file to see the code in all of it's glory.
Run the XML sample by using the runexample batch file or shell script.
Next, you decide it is time to add the menu. This too does not require event handling right now. So, you add the following:
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE window PUBLIC "-//SOURCEFORGE/Java Gui Builder DTD version 1.0//EN" "http://jgb.sourceforge.net/dtd/jgb.dtd"> <window id="webbrowser" type="jframe"> <menuBar id="menu"> <menu id="menu.file" text="File" mnemonic="f"> <item id="menu.file.quit" text="Quit" accelerator="Ctrl+Q" mnemonic="q"/> </menu> </menuBar> ... </window>
You decide to go easy on yourself yet again by handling the Quit item from the File menu first. So, you check the Event-Handling section of the JGB Elements Documentation Index.
You notice a register element which fits the bill. After reading the description of the element, you understand what you have to do now.
The first step is to modify the XML GUI description file to add the required elements:
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE window PUBLIC "-//SOURCEFORGE/Java Gui Builder DTD version 1.0//EN" "http://jgb.sourceforge.net/dtd/jgb.dtd"> <window id="webbrowser" type="jframe"> <object id="eventManager" class="jgb.examples.WebBrowserEventManager"> <constructor/> </object> ... <item id="menu.file.quit" text="Quit" accelerator="Ctrl+Q" mnemonic="q"> <register class="java.awt.event.ActionListener" event="actionPerformed" manager="eventManager" method="quit"/> </item> ... </window>
According to the documentation, event-handling will behave like this:
Now, we have to provide an implementation of WebBrowserEventManager.
package jgb.examples; import jgb.builder.WindowContext; import java.util.EventObject; public class WebBrowserEventManager { public void quit(EventObject event, WindowContext context) { System.exit(1); } }
Well, that was easy. So, you compile and run your application. Success ! The Quit option really closes down the application.
Let's continue by implementing the Go button. This button should take whatever is in the URL field and point the JEditorPane to this URL. You start by writing the necessary logic in the XML GUI description file:
... <button id="go" mnemonic="g" text="Go !"> <register class="java.awt.event.ActionListener" event="actionPerformed" manager="eventManager" method="go"/> </button> ...
This time, whenever the JGB framework receives an actionPerformed event on the Go button, it will turn around and call the go method of the eventManager object. You provide the following go method implementation:
public void go(EventObject event, WindowContext context) { final JEditorPane view = (JEditorPane)context.getObject("view"); final JTextField urlField = (JTextField)context.getObject("url"); SwingUtilities.invokeLater(new Runnable() { public void run() { try { view.setPage(urlField.getText()); } catch (final IOException e) { SwingUtilities.invokeLater(new Runnable() { public void run() { JOptionPane.showMessageDialog( view, e, "Error retrieving URL", JOptionPane.ERROR_MESSAGE); } }); } } }); }
This time around, your code required access to the context. You had to get some objects from the context so that you could update their properties. In this instance, you retrieved the URL field and the browser view so that you could read the URL stored in the URL field and set the page property of the browser view. The rest is just exception handling.
Running the application again yields something very nice. Your application can quit and can respond to URL change requests.
JEditorPane can notify registered listeners when users click on hyperlinks. We will use this capability to allow the user to click on links and open them up in the same window. As usual, you decide to start with the GUI XML description file:
<object id="view" class="javax.swing.JEditorPane"> ... <register class="javax.swing.event.HyperlinkListener" event="hyperlinkUpdate" manager="eventManager" method="hyperlinkUpdate"/> </object> ...
And the corresponding Java code:
public void hyperlinkUpdate(EventObject event, WindowContext context) { final JEditorPane view = (JEditorPane)context.getObject("view"); final JTextField urlField = (JTextField)context.getObject("url"); HyperlinkEvent hEvent = (HyperlinkEvent)event; if (hEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { URL newUrl = hEvent.getURL(); urlField.setText(newUrl.toExternalForm()); go(event, context); } }
In this bit of code, you do two things: you set the URL field to
the new URL, and you click on go
. Since the go
method did not depend on it's EventObject being a particular type,
you can safely call this method and not bother with it.
After writing this and testing, you are confident that everything works fine. You decide to do a bit of refactoring, since you have the two same lines of code in two different methods.
The actual refactoring is left as an exercise to the reader...
After adding appropriate layout directives, the window should look like this:
This example was quite simple. Only a few methods were able to handle all of the required functionnality. In a larger example, it would probably be interesting to use the mediator pattern at a second level of abstraction: One mediator per window, and the different windows speaking to each other through another mediator.
I encourage you to take a look at the XML GUI description file and the actual WebBrowserEventManager implementation
Hosted on SourceForge.net |
Valid XHTML 1.0 ! |
Valid CSS ! |
Code Coverage provided by Clover |