app Wizard

Now that you've created an ADO app manually, it's time to give Visual J Plus Plus a chance to automatically build an app to your specifications. The following example app, AutoADO, reads the MyCompany.mdb file and generates a window where the user can delete or update entries in the Customers table. Of course, it's possible to include other button controls, database options, and table options, but let's keep it simple for now.

Wizard Work

Choose New Project from the File menu, as usual. This time, select app Wizard instead of Windows app. In the wizard, supply the project name AutoADO. When you choose the Open button, the wizard presents you with a window asking whether you want to load a previously stored profile. (I'll explain profiles soon.) Since you have no stored profiles yet, leave the profile name as the default (None) and choose the Next button.

The second window is critical to creating this app. Make sure that you choose the Form Based app With Data radio button, as shown in Figure 12-2. The default is for the form not to be attached to data, which would lead you down a completely different path.

Java Click to view at full size.

Screenshot-2. The second window of the app Wizard showing the Form Based app With Data option selected.

The third wizard window asks whether you want to use ODBC to access your data file, or instead use a more direct access method unique to Access databases. Choose ODBC.

The fourth window is intimidating at first glance. First (if you don't remember from the ManualADO example), as soon as you click the DSN drop-down menu it will quickly become clear that this field refers to the type of database you want to use. Select MS Access 97 Database. As soon as you make this selection, the bottom two options are deselected since they no longer apply. You already know from previous experience in this chapter that you'll normally want to leave the User ID and Password blank. Now fill in the Database entry. You can do this by clicking on the ellipses button at the far right of the edit box. From there, you can navigate to the MyCompany.mdb database. When you have made these changes to the fourth window, it should look like Figure 12-3. Choose Next.

You can accept the defaults in the fifth window, so choose Next again.

The sixth window presents you with a list of the columns in the Customers table. This table was chosen automatically, because it's the first (and only) table in the database. Double-click the ContactFirstName, ContactLastName, and PhoneNumber columns to move them from the list of available columns to the list of columns to be displayed. That done, choose Next.

Java Click to view at full size.

Screenshot-3. The completed fourth window in the app Wizard.

The seventh window enables you to select the buttons you want in your app. The wizard will add a button and the associated event handler function for each option that you select. Select the Delete Button, Update Button, Close Button, and Data Navigator options. The resulting window looks as shown in Figure 12-4.

Java Click to view at full size.

Screenshot-4. Choosing the buttons in the seventh window of the app Wizard.

Choosing the Next button takes you to the eighth wizard window. Here, you select the type of output you want. The default is an .EXE file, which is what we want. Choosing Next takes you to the ninth and final wizard window. Here, you are given the option of saving this profile for future use. (Remember that you were given the option of reading a profile back in the first window when the wizard started.) You can save it, if you want to, by supplying a profile file name; however, whether you save the profile isn't critical to this demonstration app.

Just to make sure that the settings you made with the wizard are correct, select View Report in this last wizard window. Your results should look like that shown in Figure 12-5. If they don't, choose Back until you reach the window whose settings differ, and start over again. If all of the options match, choose Finish to allow the wizard to build a complete app to your specifications.

Java Click to view at full size.

Screenshot-5. The summary report for the AutoADO demonstration app.

app Wizard Result

To see the result of your wizardly work, compile and execute the program. The results are shown in Figure 12-6.

WARNING
When you first try to compile the wizard-generated code in AutoADO, you'll get the following compile-time error:
Undefined name m_bAddnew
This error is the result of a bug in the Visual J++ 6 app Wizard. In order to compile the program, you need to edit the btnUpdate_Click() method. Delete the following section of code from btnUpdate_Click():
if( m_bAddNew )
{
 this.setCursor( Cursor.DEFAULT );
 return;
}
 else


Screenshot

Screenshot-6. The output from the app Wizard.

The wizard created a separate edit box for each field you selected in the sixth wizard window. The user can navigate through the records in the Customers table using the buttons at the bottom of the form.

This app was easy to build, and it's functional for quickly accessing a database; however, I find the results rather ugly. You can make it look slightly better by using the Forms Designer to adjust the size and position of the controls.

A worse problem is the unusual display of the phone number field. To be fair, I choose to store the phone number data as simple numbers, but other formats are available. Later in this chapter, I'll demonstrate how to customize this field to look like the phone number displayed in the ManualADO app.

Code

Let me start by displaying a portion of the code created by the app Wizard. I will then explain it.

The code generated by the app Wizard is lengthy but interesting. A highly edited version of this code that shows only the interesting parts—including the code for one of the buttons—is shown here:

//MyCompany.java import com.ms.wfc.app.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
import com.ms.wfc.data.*;
import com.ms.wfc.data.ui.*;
public class MyCompany extends Form
{
 public void btnDelete_Click(Object sender, Event evt)
 {
 try
 {
 dataSource1.getRecordset().delete(AdoEnums.Affect.CURRENT);
 if( !dataSource1.getRecordset().getEOF() )
 {
 dataSource1.getRecordset().moveNext();
 if( dataSource1.getRecordset().getEOF() )
 dataSource1.getRecordset().movePrevious();
 }
 }
 catch (Exception e)
 {
 handleADOException(e);
 dataSource1.getRecordset().cancelBatch();
 }
 }
 .
 .
 .
 void handleADOException(Exception e)
 {
 e.printStackTrace();
 MessageBox.show( e.toString(), "MyCompany" );
 }
 .
 .
 .
 Container components = new Container();
 DataSource dataSource1 = new DataSource(components);
 DataBinder dataBinder1 = new DataBinder(components);
 .
 .
 .
 DataNavigator dataNavigator = new DataNavigator();
 private void initForm()
 {
 .
 .
 .
 // the following has been edited by dividing the
 // strings up and then concatenating them back
 // together using '+' signs to keep the strings
 // from wrapping on the page
 dataSource1.setConnectionString(
 "PROVIDER=MSDASQL;dsn=MS Access 97 Database;" + "uid=;pwd=;" +
 "DBQ=C:\\ProgramVJ\\" +
 "Windows Database apps\\Databases\\MyCompany.mdb");
 dataSource1.setCommandText(
 "select ContactFirstName, ContactLastName, " +
 "PhoneNumber from Customers");
 .
 .
 .
 dataBinder1.setDataSource(dataSource1);
 dataBinder1.setBindings(new DataBinding[] {
 new DataBinding(editContactFirstName, "Text",
 "ContactFirstName"), new DataBinding(editContactLastName, "Text",
 "ContactLastName"), new DataBinding(editPhoneNumber, "Text",
 "PhoneNumber")});
 .
 .
 .
 btnDelete.setText("&Delete");
 btnDelete.addOnClick(new EventHandler(this.btnDelete_Click));
 .
 .
 .
 dataNavigator.setDataSource(dataSource1);
 this.setNewControls(new Control[] {
 dataNavigator, btnDelete,
 btnUpdate,
 btnClose,
 panel1, labelContactFirstName, editContactFirstName, labelContactLastName, editContactLastName, labelPhoneNumber, editPhoneNumber});
 panel1.setNewControls(new Control[] {
 btnDelete, btnUpdate, btnClose});
 dataSource1.begin();
 dataBinder1.begin();
 .
 .
 .
 }


initForm() method

The first thing you'll notice is the lack of a Connection or a Recordset object anywhere within the program. However, if you look at the declarations for the initForm() method, you'll see an object of class DataSource. The role of the DataSource class is similar to that of the ManualADO class defined earlier. This is made obvious by the arguments to the setConnectionString() and the setCommandText() methods. Apparently, the first method creates the Connection and Recordset objects, and the second method sets the SQL call within the Recordset.

If you look at the next block of code within initForm(), you'll see an object of class DataBinder. The DataBinder.setDataSource() method binds the DataBinder object to the DataSource. The next call is to the method setBindings(). This method receives an array of objects of class DataBinding. Each DataBinding object ties a field within the Customers table to an edit box in the form.

Farther down in the code, the DataNavigator.setDataSource() method call ties an object of type DataNavigator back to the DataSource class. In the final method call shown—the call to setNewControls()—the DataNavigator object is listed as one of the controls.

Explanation of initForm()

As mentioned earlier, the DataSource class is a more sophisticated version of the ManualADO class that was defined in the ManualADO example. It creates the Connection and the Recordset with the associated SQL query.

The DataBinder and DataBinding classes are completely new since our previous example. The DataBinder class, along with its DataBinding class members, allows the program to display an entry in the table by using a single call. This call would have to go through the following steps to display the current record from the table:

  1. Read the current record from the DataSource object.
  2. Extract the field name contained in the DataBinding object.
  3. Display the returned data in the edit box that is contained in the same DataBinding object.
  4. Increment to the next DataBinding object within the DataBinder object and return to Step 2, until all of the DataBinding objects have been processed.

The process is similar when performing other operations on the table such as update and delete.

delete operation

Towards the bottom of the initForm() method, you can see that the Delete button is tied to the btnDelete_Click() event handler. This method starts by deleting the CURRENT record from the Recordset contained in the DataSource that contains the Connection object. The btnDelete_Click() method then moves the CURRENT record pointer to the next member of the recordset by calling moveNext().

The moveNext() method also updates the display using the DataBinding objects attached to the DataBinder object for this DataSource, as in the display steps described above. The remaining code in btnDelete_Click() ensures that we don't read beyond the end of the table.

Any exception thrown during this process—which would probably be because of an error in the database—is handled by the handleADOException() internal method. This method first calls printStackTrace(), which displays a trace in the debugger of the methods called if the program was executed from within the Visual J Plus Plus Integrated Development Environment (IDE). (The printStackTrace() method does nothing if the program wasn't running in the IDE.) The handleADOException() method then displays a MessageBox to the user.

DataNavigator object

The DataNavigator object is the control that appears at the bottom of the form. This control uses the moveNext(), movePrevious(), moveFirst(), and moveLast() methods of the DataSource object to change the CURRENT record pointer within the DataSource object. Each of these move methods displays the results using the DataBinder as explained above. The DataNavigator is convenient, but not necessary to the workings of the DataSource, DataBinder, and DataBinding classes. A similar control, the DataGrid object, displays the table data in tabular form using the same data classes. Comments