Creating GUI Applications Using Java and mSQL

From EDM2
Jump to: navigation, search

Written by Fernando Lozano

(Note: Here is a link to the msql6.zip files used in this article. Ed.)

Introduction

In the EDM/2 July issue I explained how to create a simple Java application accessing relational databases using the JDBC API, and in the August issue we saw how to build Java Servlets using JDBC to access data stored on a mSQL database.

In that same article, we also had some insights on how to design Java Servlets to take advantage of object-oriented project techniques. This time, we'll see how to build a GUI application that accesses an mSQL database and some hints on how to design this kind of application. As always, I'll guide you step-by-step on how to install the tools needed and on building a simple, although complete, application.

If you remember, good object-oriented design is built around the Model-View-Controller (MVC) paradigm. In this model, we encapsulate the data structures, presentation logic and the business rules in different layers of our applications. This approach leads to a high level of code re-utilisation and to less work maintaining the code.

In the Servlet article, we built these three layers:

The data (Model) layer used JDBC to access data from mSQL, and we had two classes, the first representing one only row from the address_book table, and the second representing a collection of rows from that same table. We will use these two classes without any modification in this article.

The presentation layer (View) had one class that made possible the input and output of address book entries as HTML forms. Now we will need a completely new presentation layer, providing specialized GUI objects (List boxes, Forms, etc.) that interact with address book entries. This new layer of classes can be reused in any GUI app we build that uses the address_book table, and that's the way OO design leads to great productivity.

Finally, the application (Controller) layer, which comprised three Servlets with a common base class. On this layer, we generally do not reuse the code, just the design patterns. We will build a new application layer for our new GUI application.

Although Java is cross-platform, the way we build our application layer, and to some extent the View layer, is dependent on the tools used. If you want GUI development, it's almost impossible to do so today without a productive IDE, and we choose the just released Visual Age for Java 2.0 as our IDE.

Our application will be implemented as a Java applet, but it could as easily be built as a stand alone Java application. Actually, Visual Age Java already creates its applets with the code they need to be executed as a stand-alone application, without the use of a web browser or applet viewer.

The Toolset

The database will again be mSQL 2.0.4.1. Since the last article about mSQL the new OS/2 port reached production status, do go to The mSQL PC Home Page (https://hughes.com.au/products/msql/) and download the "b4" (Build 4) release of mSQL 2.0.4.1 for OS/2.

The JDBC driver for mSQL has also been updated. The new release, mSQL-JDBC-1.0B4 (beta 4) is very stable (the previous one also was) and implements the PreparedStatement interface. The mSQL PC Home Page also has a link for the download of the new JDBC driver.

Although the use of PreparedStatements with mSQL does not give you the performance gains of a database that truly supports prepared statements, they provide you with a much simpler programming interface than the basic Statement class. We'll see how in a future article.

The mSQL JDBC driver does not compile under Visual Age for Java. The same errors are triggered by Beta 3 and Beta 4, so the sources of this article includes the (few) changes needed to use mSQL-JDBC with VisualAge Java.

Finally, we will use a commercial, state-of-art IDE instead of the plain JDK we used in the previous Java articles. You will still be able to compile and run all the sources of these articles in a plain JDK, or using another vendor's IDE, but we had to choose a particular IDE, so we could really teach how to write a real world database GUI application using Java.

You can download the Entry version of Visual Age for Java 2.0 at no charge from IBM Website. It's a HUGE download (about 85 MB), and you will not be very happy to discover that the download includes Netscape OS/2 2.02 and the Feature install 1.2.1, which probably you already have installed.

We will not use the Swing classes nor any third-party GUI class package, so you'll be able to use Visual Age for Java 1.0 (a 25 MB download) if you wish, but the operation of the IDE is somewhat different between the two versions. Simplicity and NetBeans are other options for OS/2 users who want a nice Java IDE for developing GUI apps but do not have such powerful machines.

Visual Age for Java 2.0 is a very hungry package. Don't even think about running it if you do not have 64 MB RAM. I have an Intel Pentium-133 with 64 MB RAM and a Matrox Millennium video card, but performance was not very good, due to excessive swapping. VAJ consumed dozens of MB from swap space, and its help system is entirely HTML-based, with a custom search engine that runs as a local web server. I hope you have a fast hard disk.

VAJ suffers from being software originally developed using Smalltalk. As good as Smalltalk can be as an academic tool, I can't see its value for commercial application development. If you once thought Java was too slow for any practical use, that's because you've never run a Smalltalk application.

But VAJ is a wonderful tool. Its text editor, object browsers, GUI painters and debugger are comparable to the best ones you've ever seen for any platform. VAJ takes visual development to a higher level than any other tool, allowing you to build code entirely from graphical connections between Java Beans.

The best feature of VAJ is the integrated source code repository. Most Windows and OS/2 developers do not use these kinds of tools, and they do not know what they are missing. Contrast this to the Unix world, where even the free packages are developed with the help of RCS, CVS or SCCS. By the way, there are OS/2 ports of RCS and CVS, if you do not want to use VAJ but realizes that a source-code management system is a nice tool.

At a hundred dollars, VAJ Professional is a bargain. My only complaint is that IBM could have included a bigger set of pre-built beans. But if you compare the price tag of VAJ Pro + any third-party beans package against other Java IDEs, VAJ has still the best value and feature set for its price.

Start working

VAJ 2.0 installation is based on Feature Install, a process that should be familiar to some OS/2 users (that's the same used by JDK 1.1.4 and above).

VAJ comes with a Getting Started book (in PDF format) that will guide you through building a simple Java application to teach you how to work with its IDE. We'll assume you have followed this tutorial and can create simple applications using VAJ.

To start our work, we have to import mSQL-JDBC classes into the repository. Add a new Project named "mSQL-JDBC" using the right button and the menu item "Add | Project". Then select the newly created project and click "Import" on the context menu for the project. Select "Jar file" from the Smartguide that pops up, and use the browse button to find the file named msql-jdbc10b4.jar. Note that release 1.0B3 of mSQL-JDBC packages its classes as a zip file, which you'd have to unzip and then import as a directory into VAJ. [Fernando says that this is because VAJ cannot import ZIP files. Java understands them. Ed]

VAJ would not compile the mSQL-JDBC classes, throwing four compile errors. The corrections are simple, and are related to some bugs (i.e. discrepancies from the JVM spec) between VAJ and George Reese's (mSQL-JDBC author) JDK. They are not real errors in the classes. The sources of this article include both a text file describing the changes and a .DAT file you can import directly into VAJ repository.

Having the mSQL-JDBC classes imported into VAJ, let's create another project to host our application. I named it "mSQL EDM2 October", although it will be published in the November issue. Give the name you like, for example "Address Book app". Then find the directory where you have the sources from the August article (about Java Servlets and mSQL).

You'll import only the files Entry.java and EntryCollection.java. To do so, you have to click the Details button on the "Import from directory" step of the Smartguide.

Now we have our data layer and are ready to start building our application.

The Java Address Book application

Our Address Book GUI Java application will be implemented as an applet. We could as easily build a stand alone Java application, but as everybody wants applets that can be easily launched by a web browser, we'll follow the trend.

Anyway, it's easy to create a stand-alone app from any applet, as long as the applet does not try to interact with the web browser: just provide a Frame window to host the applet. VAJ already does this trick, inside the main method it creates for any class built using the Visual Composition editor.

Our applet will have a List Box that shows the address book entries. To give some organization to the list, a Combo Box (named "Choice" on Java) will act as a filter, so the List shows only the entries whose last name starts with the letter selected in the combo box. Actually, the EntryCollection class already forces us to do so.

Besides the list box, the applet will have three buttons, for inserting a new entry on the address book, editing an entry from the address book, and finally deleting an entry from the address book.

The New and Edit buttons will both open the same Window, containing all fields from an address book entry. When the user clicks Ok, the entry will be inserted or updated on the address book table. So our application has two screens: an applet and a Frame Window. We cannot use a Dialog, because the applet does not provides a frame window to be the parent of the Dialog.

From this description of the application user interface we can identify two view layer classes for our application: the List Box and the Details Panel. The list box has the capability to be populated from an EntryCollection instance, and the Details Panel has to initialize its text fields from an Entry instance, besides returning another Entry instance containing the data typed by the user.

We design a Details Panel instead of a Details Window because this way we increase the reusability of the code. I could design the user interface in many different ways, for example a window split into two panels, one showing a list of entries and the other showing the details of the selected entry from the list. This alternative design would use the same List Box and Details Panel classes, but would not be able to reuse a Details Window.

So now we have our View layer design, and the application design consists of the Applet and the Edit Window. These two are just the "glue" between the Data and the View classes, and that's the way to design an object-oriented application.

If our application had more logic than simply new/edit/delete records from a relational table, we would create another class in the Data layer containing that logic. Then the Data layer would have two "sublayers", the Database Access classes and the Business Rules classes. The Business Rules classes would have matching View classes, and then we could reuse these classes in many different applications.

To summarize, here are our classes and layers:

Data             EntryCollection         Entry
                        |                  |
View                EntryList         EntryPanel
                        |                  |
Application      AddressBookApplet----EntryFrame

The lines above denote the "contains" relationships, not the inheritance relationship we showed in the Servlets article. But the line between AddressBookApplet and EntryFrame denotes the "uses" relationship, as the applet instantiates an EntryFrame window to insert or update address book entries.

Listing Address Book Entries

Now, let's start the real work! (Just kidding. Please never never NEVER approach the design of your applications as a loss of time. We all know that the real fun is in writing code, but codding without a proper design can turn the fun into a nightmare.)

Let's try to make our applet list the entries already stored in the address book, and after that we will build the editing capabilities on our application.

First of all, we'll create the EntryList class. Select "Add | Class" from the "Default package" of our Java Address Book project. Name the class "EntryList" and select "List" (from java.awt) as the superclass. Clear the "Compose the class visually" check box and click Finish.

When the Smartguide finishes creating the class, select "Add | Field" from the context menu for the class. Name the field entriesVector, private, from type java.util.Vector, but do not generate get/set methods. Now the EntryList class declaration should contain:

private Vector entriesVector;

This means we will store all Entry instances returned from the EntryCollection inside a Vector, so we can easily edit then. We could also store just the "id" field from each entry, and when requested instantiate an Entry object given its id. If you have bigger data sets, you'll have to follow this approach, but now we don't need to.

Now add the method "fill", whose argument is an EntryCollection. This method will be called to initialize the List Box and when the user selects another initial letter. This method should contain:

  public void fill( EntryCollection entries ) throws SQLException {
    removeAll();
    entriesVector = new Vector();
    Entry entry = entries.next();
    if (entry == null) {
      setEnabled(false);
    }
    else {
      setEnabled(true);
      while (entry != null) {
        entriesVector.addElement(entry);
        addItem(entry.last_name + ", " + entry.first_name + " (" + entry.company + ")");
        entry = entries.next();
      }
    }
  }

It clears the List Box contents, instantiates a new Vector to hold the Entries, and then iterates through the EntryCollection, storing each entry in the vector and adding a new line to the List Box.

The EntryList class needs another method, which we won't use now but we'll need to edit or delete an entry. This method will return the currently selected entry from the list:

  public Entry getSelectedEntry() {
    if (getSelectedIndex() >= 0) {
      return (Entry)entriesVector.elementAt(getSelectedIndex());
    }
    else {
      return null;
    }
  }

And we are finished. Now to create the Applet that will host the EntryList.

Java Layout Managers

We will build our applet visually. After selecting "Add | Class", just let the "Compose the class visually" check box be checked, and the Visual Composition Editor from VAJ will be started.

Our applet looks like fig.1.

Create-GUI-applet1.gif

You see a combo box (choice), a list box and three buttons. We also have two labels, one on the top of the Applet, and the other on the bottom. The first one acts as a title label for the list box, and the other will be used as a status line.

But our applet has more visual objects than may be apparent on the screenshot from fig.1. See fig.2.

Create-GUI-beans1.gif

This displays the Bean List from the applet (menu "Tools | Beans List" from Visual Composition Editor). The list shows two Panels, "Right Panel" and "Buttons Grid", and a third Label named "Separator".

Java is a cross-platform language, and this reflects on the way you should build your application GUI. Windows and OS/2 programmers are used to just drop "Controls" on a free-form surface, and then all Controls (text field, buttons and so on) are positioned by pixel (x,y) coordinates.

This works well on the PC, which has standard video displays and using operating systems that standardized the available screen fonts and the GUI look and feel. But each platform has different fonts, different aspect ratios, different border widths for Windows and many other differences in the visual aspect of Controls and Windows. The result is that your nice screens will get scrambled when moved from the original platform to another one.

Unix (X Window) programmers solve this problem specifying not the pixel coordinates for the Controls, but their relationships: the three buttons are one above the other in the same column, the list to the left from the buttons, and so on. Of course this is much harder than simply drawing on a free-form surface, and this is one of the causes most Unix software does not look as nice as OS/2, Windows and Mac software.

Java tries to make things easier by providing a set of Layout Managers. Each layout manager has a rule for positioning the Controls inside it. For example, the Flow layout puts one Control after another, from left to right and from top to bottom, just like text typed into a text editor. But The Grid layout splits its area into equal size cells, and gives all Controls the same size.

All Window and Container classes in Java have a layout manager. Java's default is the Flow layout, but VAJ Visual Composition Editor uses by default no layout (a "null" layout"), which has the same effect as a free-form surface.

If you guessed it's safe to stick with the null layout, as you will only run the app on your PC, you lost the bet. Each Java VM can implement the actual look and feel of the AWT (GUI) classes the way it wants. So, different Java VMs on the same operating system can display your GUI in very different manners. Even we, using IBM VAJ and Netscape Communicator (which uses IBM JDK) have this kind of problem. See fig.3.

Create-GUI-run1.gif

This shows our applet when run from VAJ's Applet Viewer and compare with fig.4 that shows the same applet when run by Netscape Communicator. See how the fonts, the window borders, the colours and the size of the controls are very different.

Create-GUI-run3.gif

Conclusion: always use the proper Java layout managers when designing your GUI. The trick to getting the results you want is to put some Panels one inside the other, so that each Panel can have its own Layout Manager, and we can use the easiest layout for each part of the Window.

Using the Bean list as a guide, drop the Beans (this is the name of Java GUI Controls and other components you can use to build applications on any Java IDE) on the Applet box. Start by changing the applet layout manager to a Border Layout, which let's you put components around a main component at the centre. This main component grows to fill all space not used by the "border" components.

Now drop the Labels at the top and at the bottom of the applet. Note how the Visual Composition shows dotted boxes providing you feedback about in which area (centre, top border, left border and so on) you are dropping the Bean. Name the Labels "Title Label" and "Status Line".

Now drop the EntryList at the centre of the applet. Click the icon at the top-right of the toolbox, the one that shows a question mark. This is the "Choose Bean...", which let's you specify any class not present in the toolbox. Choose the EntryList class and see how it expands to fill the entire area of the applet, except for the two labels.

Most Java layout managers tend to resize the Beans to their minimum size. For example, an "Ok" button will have the bare minimum size to make the work "Ok" readable. This is not very aesthetically pleasing for a button column, where we want all buttons to have the same size. So we'll use a Panel with a Grid Layout to hold the buttons. But the buttons do not fill the full height of the List Box. So we will put the Panel inside another Panel using the Flow layout. See again fig.2.

Drop a Panel at the right of the applet and change its layout to a Flow layout. Name it "RightPanel". Then drop another Panel on the RightPanel, name it "ButtonsGrid" and change its layout to a Grid Layout. Then get the properties of the ButtonsGrid. If you clicked somewhere on the Visual Composition screen and cannot select the ButtonsGrid again from the Applet, use the Beans List to get its context menu. Explode the "layout" property to show the "rows" property and change its value to 5. We have three buttons, a choice, and a Label to provide a separator between the buttons and the choice, so we have five cells (rows) in the grid.

Now drop the Choice, the Label and Three buttons on the ButtonsGrid Panel. Name then "LetterChoice", "Separator", "NewButton", "EditButton" and "DeleteButton" and change the Label property of the buttons. Use fig.1 as a guide.

That's enough for Java layouts. Let's add the code we need to run the fist version of our applet and see the list filled with address book entries.

Address Book Applet ver. 0.1

Select the menu "Bean | Save Bean" from the Visual Composition Editor. This will generate the code to initialize the applet and set the properties of all its beans.

We want just to see the List filled with data. So select the init() method, which is the place to put first-time initialization of an applet. The Visual Composition Editor re-generates this method every time you "Save Bean", but it also provides a place where you can insert your own code:

  // user code begin {1}
  // user code end

The code between these comments will be preserved by VAJ, but all other code from the generated methods will be lost. Let's include the bare minimum so we get data from mSQL and pass it to the EntryList:

  // user code begin {1}
  // connect to the database
  Class.forName ("com.imaginary.sql.msql.MsqlDriver");
  String url = "jdbc:msql://localhost:1114/pim";
  con = DriverManager.getConnection (url, "nobody", "");
  // provides an initial state to the applet
  getEntryList().fill(new EntryCollection(con, "L");
  getStatusLine().setText("Total entries: " + getEntryList().getItemCount());}
  // user code end

VAJ will complain about the variable "con". Save the code with the error and then add the following field to the AddrBookApplet class:

  private Connection con;

You'll also have to add the following to the imports of the class:

  import java.sql.*;

The user code connects to the database, instantiates an EntryCollection object and passes it as an argument to the fill() method from EntryList. It also initializes the status line with the number of rows retrieved from the database, that is, the number of items in the List.

Before we can run the applet we have to provide it with a custom CLASSPATH, so it can load the mSQL-JDBC classes. Get the properties of the applet (from its context menu) and select the "Class Path" tab. At the right of "Project Path" click the Edit button, and then check the "mSQL JDBC" project. Then click OK.

Finally we can run something. Select the Applet on VAJ Workbench and click the run button from VAJ toolbar. If everything is fine, you should get the same result as fig.3. Note that the applet needs to be resized to show the buttons and the choice. Don't worry, because when the applet is executed from Netscape the Layout managers will resize and move the beans so that all are visible to the user the first time.

Making Connections

After the first successful run of AddrBookApplet, we have to complete it so we can filter the data using the combo box and the three buttons are enabled and disabled when needed.

The first step is creating the methods that will perform these actions. Create the empty methods newEntry, editEntry and deleteEntry (for the buttons) and create the method refreshEntryList as below:

  public void refreshEntriesList() throws SQLException {
    getEntryList().fill(new EntryCollection(con, getLetterChoice().getSelectedItem()));
    getEditButton().setEnabled(false);
    getDeleteButton().setEnabled(false);
    getStatusLine().setText("Total entries: " + getEntryList().getItemCount());
  }

This method performs the same actions that were in the init() method. Besides, it disables the Edit and Delete buttons, as when the List is refreshed it will have no selected item.

Note also that now we get the argument to the EntryCollection constructor from the Choice. We have to fill the choice with all letters from the alphabet, and so the user code inside the init() will be:

  // user code begin {1}
  // fill the choice with all letters
  for (char l = 'A'; l <= 'Z'; l++) {
    getLetterChoice().addItem(String.valueOf(l));
  }
  // connect to the database
  Class.forName ("com.imaginary.sql.msql.MsqlDriver");
  String url = "jdbc:msql://localhost:1114/pim";
  con = DriverManager.getConnection (url, "nobody", "");
  // provides an initial state to the applet
  refreshEntriesList();
  // user code end

We added the code to fill the choice and replaced the code that fills the List with a call to refreshEntriesList. Now you can run the applet again, to test it. You should get an empty List (unless you have manually inserted some entries for the letter "A") but the Choice filled.

Now we have to connect the GUI events to our methods, and we have also to enable the Edit and Delete buttons when an item is selected in the EntryList. In the Visual Composition Editor, we use connections to perform this work.

We'll have six connections, as in fig.5.

Create-GUI-conn1.gif

One from the Choice, to refresh the List; three from the buttons, invoking the corresponding methods (now empty); and two between the list and the buttons, so they are enabled when an item is selected.

Select the Choice, choose from the context menu "Connect | ItemStateChanged". Then drop the connection on the free-form surface (the empty area of the Visual Compostion Editor) and select "Conectable Features". Now select method refreshEntriesList();

Select the New button, and choose "Connect | Action Performed" and then "Connectable features", to select method newEntry(); Repeat the procedure for Edit and Delete buttons, connecting their "Action Performed" events to methods editEntry() and deleteEntry() from the applet.

The connections are not very well laid out by default, but you can select the connection arrow and drag the control points to try a cleaner layout. That's why fig.5 has the arrows with different shapes than you should see now.

To enable the buttons, select the List and choose "Connect | ItemStateChanged" and drop the connection on the Edit button. Select "Connectable Features" and then setEnabled(boolean). The result will be a dashed line, because you have to supply the boolean parameter. So select the connection and choose "Connect | aBoolean" and drop the connection on the List. Select "enabled". Repeat the procedure for the Delete button.

Now when I write this I realize that this was not the simplest procedure to get the desired effect, but I'll leave as an exercise to the reader to discover a simpler way to enable the buttons using Visual Composition Editor connections.

Time to test our applet again. Now you should be able to choose any letter and see the matching records from the database, and you have also to see the buttons enabled and disabled at the right times.

The next step is to build the EntryPanel and EntryFrame classes, to be able to insert end update entries.

More GUI Classes

We'll start with the EntryPanel class, see fig.6.

Create-GUI-panel1.gif

It has no connections, but uses a different layout manager than the other classes. It's the GridBag Layout.

The GridBag layout is the most generic, most powerful and of course the most complicated of the core Java classes. It allows almost any positioning and spacing of Beans and has the option of expanding the beans or using their preferred sizes.

Think about the GridBag as a grid where the columns and cells can have arbitrary sizes. Of course, all cells in a row will have the same height, and all cells from the same column will have the same width. It's similar to an HTML table, and you can also make a bean "span" many adjacent cells.

Our details Panel makes simple use of the GridBag layout. Add a new class (EntryPanel) to the default project, using Panel as the superclass, and enter the Visual Composition Editor. Then change the Panel layout to GridBag and drop the labels and TextFields on the panel. Take care to put all labels in the same column and all TextFields in the same (another) column. Take care also, so the label gets the same line as the corresponding TextField.

Now select all Labels. Show their properties, and change the "alignment" to LEFT. Then expand the "constraints" property, and inside it expand the "insets" property. Change the "top" and "left" properties to 4, so the labels get the proper spacing.

Select all the Text Fields. Expand the "insets" property, as you did with the labels, and change the "top" and "right" properties to 4. Now, your panel should look like fig.6. Save the bean.

We'll add two methods to the EntryPanel:

  public Entry getEntry() {
    if (entry == null) {
      entry = new Entry();
    }
    entry.id = getIdField().getText();
    entry.first_name = getFirstNameField().getText();
    entry.last_name = getLastNameField().getText();
    entry.title = getTitleField().getText();
    entry.company = getCompanyField().getText();
    entry.e_mail = getEmailField().getText();
    return entry;
  }

This first one returns the data typed by the user, the other allows the application to initialize the Panel for editing a given entry.

  public void setEntry(Entry entry) {
    this.entry = entry;
    if (entry != null) {
      getIdField().setText(entry.id);
      getFirstNameField().setText(entry.first_name);
      getLastNameField().setText(entry.last_name);
      getTitleField().setText(entry.title);
      getCompanyField().setText(entry.company);
      getEmailField().setText(entry.e_mail);
    }
  }

These methods already provide us with the capability to get data in and out of the Panel, so we need no connections.

Now let's create the EntryFrame class. Add a new class and enter the Visual Composition Editor. Use fig.7.

Create-GUI-frame1.gif

And the bean list in fig.8.

Create-GUI-beans2.gif

As a guide to build the Frame. We used again a Panel with a Grid layout to keep the buttons the same size, and we put an EntryPanel inside the EntryFrame. The Frame uses a Border Layout.

Note that VAJ creates the frame already with one connection. This connection closes the window when the user clicks the close box or selects Close from the System Menu. We have to add connections to the Ok and Cancel buttons, but first let's create the methods that will be used as end points for these connections. Do not forget to save the bean before adding methods and fields (attributes).

The EntryFrame class needs a specialized constructor, as shown below:

  public EntryFrame( AddrBookApplet app, Entry entry, Connection con ) {
    super();
    this.app = app;
    this.entry = entry;
    this.con = con;
    initialize();
  }

This constructor will not be regenerated by the Visual Composition Editor. It only generates the constructor with no arguments. We need this constructor to pass the database connection, the Entry to be edited (null if we are inserting a new entry) and the Applet, so the EntryList can be refreshed to reflect the changes.

You will also have to add the following fields to the class:

  private AddrBookApplet app;
  private Entry entry;
  private Connection con;

We'll add user code to the initialize() method of the frame, so it gets a different title for insert and update operations, and to initialize the Panel with the Entry to be edited:

  // user code begin {2}
  if (entry == null) {
    setTitle("Inserting new Entry");
  }
  else {
    setTitle("Editing Entry");
  }
  getEntryPanel().setEntry(entry);
  // user code end

Finally, the commitChanges method saves the new or updated Entry in the database:

  public void commitChanges() throws Exception {
    Entry newEntry = getEntryPanel().getEntry();
    newEntry.validate();
    if (entry == null) {
      newEntry.insert(con);
    }
    else {
      newEntry.update(con);
    }
    app.refreshEntriesList();
  }

Now we can make the connections from the EntryFrame class. See fig.9. We have three connections.

Create-GUI-conn2.gif

The connection from the Cancel button is simple. It just closes the Window. Choose "Connect | ActionPerformed", drop the connection to the free-form surface, and then select "dispose()". We are done.

From the Ok Button, choose "Connect | ActionPerformed" and then "Connectable Features" from the free-form surface. Then select the "commitChanges()" method.

The Ok button also needs to connect to the dispose() method, but only if the commitChanges() method was successful. Remember (from the August article) that if the new or updated Entry class does meet its validation criteria, an exception will be thrown.

The way to close the window only if the data was saved in the database is to make a connection from the connection that calls commitChanges(). Select the connection, and choose "Connect | normalResult". Drop the connection on the free-form surface and select "dispose()".

Now we have the EntryFrame class finished, that's time to complete AddrBookApplet newEntry() and editEntry() methods.

A Final Word About Layout Managers

The newEntry() method from AddrBookApplet needs only to open the EntryFrame window:

  public void newEntry() {
    Frame frame = new EntryFrame(this, null, con);
    frame.show();
  }

We can already run the applet to test if the EntryFrame class is working as it should and we can insert new records in the database. Fill in all fields, as we still have no code to trap the exception if the entry is not valid.

Fig.10 shows how the EntryFrame window will looks like when running from VAJ. Not very good, part of the Id and E-mail fields are being clipped out of the Window. Your first idea will be increase the size of the Frame on Visual Composition Editor.

Create-GUI-run2.gif

But not so fast. See in fig.11 how the Frame will look when running from Communicator: the fields Id, First Name and E-mail do not show at all. And all the labels have the first letter clipped out.

Create-GUI-run4.gif

Just a resize and you can see the whole window, but you do not want your users to resize the details window every time they use the application, right? What you have is another consequence of the platform independence of Java: in the Visual Composition Editor, you set an initial size in pixels for the Window, but you do not know what is the correct size for each platform. The solution? Let the Frame itself calculate the size it needs.

Just before the show() method, call the pack() method. Then the frame will see what size its contents need to be visible and will resize itself.

  public void newEntry() {
    Frame frame = new EntryFrame(this, null, con);
    frame.pack();
    frame.show();
  }

And then complete the editEntry method:

  public void editEntry() {
    Entry entry = getEntryList().getSelectedEntry();
    Frame frame = new EntryFrame(this, entry, con);
    frame.pack();
    frame.show();
  }

Note that you do not need to keep a reference to a Frame object. It will discard itself when the method dispose() is invoked.

To have a complete Address Book Application, we are missing only the deleteEntry() method:

  public void deleteEntry() throws SQLException {
    Entry entry = getEntryList().getSelectedEntry();
    Entry.delete (con, entry.id);
    refreshEntriesList();
  }

Run the application, and test if all features are working as expected. Insert new entries, edit them and delete some. Check if the buttons are being enabled and disabled, if the List is being refreshed after any changes, and keep in mind that the List shows only entries whose last name starts with the letter selected on the combo box.

Final Touches

Now, our applet should be working with all its functions. We need only a way to provide feedback to the user about errors that may happen. For example, the mSQL daemon may not be available when you run the applet, or the user may try to insert an entry with all fields empty.

VAJ generates a method named handleException to catch all exceptions that were not caught somewhere on the GUI classes. Let's complete it, using the status line to report errors to the user:

  private void handleException(Throwable exception) {
    getStatusLine().setText(exception.getMessage());

    /* Uncomment the following lines to print uncaught exceptions to stdout */
    System.out.println("--------- UNCAUGHT EXCEPTION ---------");
    exception.printStackTrace(System.out);
  }

Only the first line was added by us. The remaining lines were generated by VAJ, but left commented out. It's useful, during the development phase of the life cycle of your application, to uncomment them, so any errors are reported to the VAJ Console Window. For the production application, the first line is sufficient and more clean.

But this catches only Exceptions in the AddrBookApplet. There are also the exceptions thrown in the EntryFrame class. We could add a status line to the frame, but this is not the common practice. The most common error will be the exception thrown by the validate() method from Entry, and the user expects a window pops up to tell him/her what fields need to receive data.

Unfortunately, the Java core classes do not provide a MessageBox, like Windows and OS/2 programmers take for granted. So I created a MessageBox class, which is a Frame window with a Label and an Ok button, and the following static method to ease the use of the MessageBox window:

  public static void popUp( String title, String message ) {
    MessageBox frame = new MessageBox();
    frame.setTitle(title);
    frame.getMessageLabel().setText(message);
    frame.pack();
    frame.show();
  }

As the remainder of the MessageBox class does not have anything new, I'll not delve into details. Check the sources from this article if you want more info.

The method handleEvent from EditFrame will use the MessageBox as follows:

  private void handleException(Throwable exception) {
    MessageBox.popUp("Java Address Book", exception.getMessage());

    /* Uncomment the following lines to print uncaught exceptions to stdout */
    // System.out.println("--------- UNCAUGHT EXCEPTION ---------");
    // exception.printStackTrace(System.out);
  }

Now, if the user tries to insert a new Entry with empty fields, he/she will get a window telling at least the last name and e-mail fields have to be filled.

Running From Communicator

To finish this article, let's show how you can run your applet from inside Netscape Communicator or any other browser. First, here's an HTML file to start the applet. Save it as JavaAddrBook.html:

   <HTML>
   <HEAD>
      <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
      <META NAME="Author" CONTENT="Fernando Lozano">
      <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (OS/2; I) [Netscape]">
      <TITLE>Java Address Book</TITLE>
   </HEAD>
   <BODY>
 
   <H1>
   Java Address Book
   <HR ALIGN=LEFT SIZE=1 WIDTH="100%"></H1>
   <APPLET width=380 height=250 code="AddrBookApplet.class"></APPLET>
   </BODY>
   </HTML>

Then, in the same directory as the HTML file, you need to have the class file of our application. Select the Project in the VAJ Workbench window, and choose "export" Select "directory" in the Smartguide and in the next step select the same directory where you saved the HTML file above.

You'll also need the mSQL-JDBC classes unzipped in the same directory, but preserving its internal directory structure. That is, in the same directory as the application class files, there should be a "com" directory. Inside "com" there should be an "imaginary" directory and so on.

If you store the application on your web server, you may have to change the URL to the mSQL database on the init() method of the applet. Remember that, when an applet is loaded from a web server, it can only connect to other services on the same host as the web server. A real application would not have hard-coded URLs, but would get them from the applet properties.

Conclusion

I hope you enjoyed this article and now have a better understanding of how to build Java GUI applications and how to access databases using Java. All code we developed can be run from any Java 1.1 VM, and could with minimal changes (the JDBC driver class name and the database URL) be used against other databases.

Visual Age for Java 2.0 also comes with proprietary Data Access Beans, which should help to build Java database applications. We should look at these in a future article, but keep in mind that Object-Oriented Development and Visual Programming sometimes heads you into opposite directions. You should have a clear understanding of the uses and limitations of each approach to choose the better one for each application you develop.

Last but not least, visit The mSQL PC Home Page (https://hughestech.com.au/products/msql/) to keep informed about the latest developments of the mSQL database and web development.