The purpose of this lab exercise is to introduce you to several more elements commonly used in GUI programs - menus, dialogs, and scrolling lists.
In this lab exercise we are going to put together a simple contact list application that will allow you to create and maintain a list of contacts.
Start by making a new, empty project in NetBeans. Create a package in the project named 'contacts'. All of the classes we will create for this project will go in that package.
Before we talk about an interface for our application, we need to create the classes that will be responsible for storing and maintaining the application's data.
The first class we will need is a simple Contact class that stores information about a single contact. Create a new class named Contact in the contacts package. Copy and paste this code into that source file.
package contacts;
import java.io.*;
public class Contact {
public String firstName;
public String lastName;
public String phone;
public String email;
public Contact() {
firstName = "";
lastName = "";
phone = "";
email = "";
}
public void readFrom(BufferedReader in) throws Exception {
String[] name = in.readLine().split(" ");
firstName = name[0];
lastName = name[1];
phone = in.readLine();
email = in.readLine();
}
public void writeTo(PrintWriter out) {
out.println(firstName + " " + lastName);
out.println(phone);
out.println(email);
}
}
Note that the data elements in this class are all public, so we can access them directly without having to go through set and get methods.
The Contact class also contains a pair of convenience methods designed to make it easier to read Contacts from a text file and write them back to a text file again.
The second class we will create, ContactList, is the primary data class for our application. It maintains a list of Contact objects in an ArrayList and provides useful methods for reading and writing the contacts to a text file, adding and removing contacts, and so on.
package contacts;
import java.io.*;
import java.util.ArrayList;
public class ContactList {
private ArrayList<Contact> contacts;
public ContactList() throws Exception {
contacts = new ArrayList<Contact>();
BufferedReader input = new BufferedReader(new FileReader("contacts.txt"));
int howMany = Integer.parseInt(input.readLine());
for (int n = 0; n < howMany; n++) {
Contact nextContact = new Contact();
nextContact.readFrom(input);
contacts.add(nextContact);
}
input.close();
}
public void saveToFile() throws Exception {
PrintWriter output = new PrintWriter(new File("contacts.txt"));
output.println(contacts.size());
for (int n = 0; n < contacts.size(); n++) {
contacts.get(n).writeTo(output);
}
output.close();
}
public String[] getNames() {
String[] names = new String[contacts.size()];
for (int n = 0; n < contacts.size(); n++) {
Contact c = contacts.get(n);
String cName = c.firstName + " " + c.lastName;
names[n] = cName;
}
return names;
}
public Contact makeNewContact() {
Contact c = new Contact();
contacts.add(c);
return c;
}
public Contact getContact(int n) {
return contacts.get(n);
}
public void removeContact(int n) {
contacts.remove(n);
}
}
Copy and paste this code into your project.
In addition to these two classes, we will also need a text file to save contact information to. Right-click on your project in the Projects pane and create a new, empty file named 'contacts.txt'. Paste the following text into that file.
1 Joe Gregg 832-9573 greggj@lawrence.edu
The first line in the 'contacts.txt' file is an integer count of how many contacts are stored in the file. The information for the individual contacts follows, three lines per contact.
The application we are going to create has both a main window and a dialog. The first step is to create the interface for the main window.
Right-click on the contacts package and select New/JFrame Form to create a new window class. Name the new class 'ContactsManager'.
The interface for this main window will consist of a menu bar with a File menu and an Edit menu and a scrolling list of contacts.
To create the menu bar, scroll down to the Swing Menus section in the GUI designer's Palette, and drag a Menu Bar component into the design pane. Place menu at the top of the window. By default, you will get a menu bar with two menus, a File menu and an Edit menu.
![]() |
Next, scroll back up to the Swing Containers section in the Palette. Drag a Scroll Pane into the window. Resize the Scroll Pane so that it takes up the entire window below the menu bar. Scroll down to the Swing Controls section of the Palette and locate the List component. Drag the List component into the window and drop it on the Scroll Pane you added earlier.
![]() |
Using the properties pane, set the variable name associated with the JList component to 'contactsList'.
Next, we are going to add menu items to the File and Edit menus. To add a menu item, drag a Menu Item from the Swing Menus section of the Palette to the menu in the menu bar.
![]() |
Create Save and Quit menu items in the File menu, and three items for the Edit menu as shown here. Set the text for these five menu items to match what you see here. Using the properties pane, set the variable names for these five menu items to saveCommand, quitCommand, newContactCommand, editCommand, and deleteCommand.
![]() |
Our contacts editor will include a simple dialog that the user can use to set the data for a Contact object. Next, we will build this dialog window in the designer.
Scroll down to the Swing Windows section in the Palette and locate the Dialog window type. Drag and drop a Dialog into the design pane.
The lower left pane in the NetBeans window should display the Inspector pane. If the Inspector pane is not open, select Navigating/Inspector from the Window menu to open it. The Inspector pane shows a heirarchical view of all of the components in your interface, which provides a nice alternative way to locate and select components you would like to work one. Locate the dialog you just dropped into the design pane and click to select it.
![]() |
With the dialog selected, make the following changes in the Properties pane:
Next, double-click on the dialog in the Inspector view to open up a design view on the dialog itself. Using labels, text fields, and buttons, lay out the interface for the dialog as shown below.
![]() |
Using the properties pane, set the variable names for the four text fields to firstNameField, lastNameField, phoneField, and emailField. Set the variable names for the two buttons to cancelButton and okButton.
Now that we have finished setting up the interface for our application, it is time to switch our attention to the internal details of the application. Click the Source tab at the top of the design window to switch to the source code view.
The ContactList class you added to your project earlier is the primary data class for this application. It is responsible for maintaining the list of contacts and saving and restoring the contacts from a text file. Also, from time to time we will need to edit individual Contact objects. Add these two member variables to the ContactManager class.
private ContactList allContacts; private Contact currentContact;
These two variables will need to be initialized in the constructor for the ContactManager class. Place the following code in the constructor after the call to initComponents():
currentContact = null;
try {
allContacts = new ContactList();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"Unable to open contacts file.\nApplication will exit.");
System.exit(0);
}
contactsList.setListData(allContacts.getNames());
Since the constructor for the ContactList class may throw an exception if the application is unable to find and open the 'contacts.txt' file, we have to place the constructor call in a try/catch block that quits the application automatically whenever we are unable to find and open that file.
Once the ContactList has been set up successfully, we need to tell the JList to display the list of names by calling its setListData method with an array of names we obtain from the ContactList. This will ensure that all of our contacts show up in the list in the main window when the application starts.
Next, switch back to the design view. Double-click on the JFrame in the inspector to bring the design view back to the view of the main window.
Next, we are going to create action methods for each of the menu commands we added earlier. To attach an action method to a menu item, right-click on the menu item and select Events/Action/actionPerformed. Do this for all five of the menu commands.
![]() |
Fill in the code for these five action methods as shown here.
private void saveCommandActionPerformed(java.awt.event.ActionEvent evt) {
try {
allContacts.saveToFile();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"Exception while trying to save.\n" + ex);
}
}
private void quitCommandActionPerformed(java.awt.event.ActionEvent evt) {
System.exit(1);
}
private void newContactCommandActionPerformed(java.awt.event.ActionEvent evt) {
currentContact = allContacts.makeNewContact();
// To do: set fields in dialog with values from currentContact
contactDialog.pack();
contactDialog.setLocationRelativeTo(this);
contactDialog.setVisible(true);
contactsList.setListData(allContacts.getNames());
}
private void editCommandActionPerformed(java.awt.event.ActionEvent evt) {
int selected = contactsList.getSelectedIndex();
if (selected != -1) {
currentContact = allContacts.getContact(selected);
// To do: set fields in dialog with values from currentContact
contactDialog.pack();
contactDialog.setLocationRelativeTo(this);
contactDialog.setVisible(true);
contactsList.setListData(allContacts.getNames());
}
}
private void deleteCommandActionPerformed(java.awt.event.ActionEvent evt) {
int selected = contactsList.getSelectedIndex();
if (selected != -1) {
allContacts.removeContact(selected);
contactsList.setListData(allContacts.getNames());
}
}
For the 'to do' sections in the methods newContactCommandActionPerformed and editCommandActionPerformed, fill in code that uses text found in the currentContact object to fill in the text fields in the dialog with appropriate values.
To invoke the dialog and make it visible on the screen, we call the dialog's setVisible method. That method will return when the dialog has been dismissed by the user. After the user has finished interacting with the dialog, we will want to update the list of names displayed in the JList in the main window, as a name in the contact list may just have changed. To update the JList with all current values for names, we do
contactsList.setListData(allContacts.getNames());
Switch back to the design view and double-click the dialog in the inspector to bring the dialog up in the design pane. Double-click on the Cancel and OK buttons to create action methods for these two buttons in the dialog. Place the following code in those two methods.
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {
contactDialog.setVisible(false);
}
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
currentContact.firstName = firstNameField.getText();
currentContact.lastName = lastNameField.getText();
currentContact.phone = phoneField.getText();
currentContact.email = emailField.getText();
contactDialog.setVisible(false);
}
Dialogs that are invoked with setVisible(true) stay active until the corresponding call to setVisible(false) is made. Note that the action code for both buttons in the dialog call setVisible(false) on the dialog to dismiss the dialog.
The application is now fully functional. Try adding some new contacts, editting and deleting contacts. Save and quit, and restart the application to see that saving and restoring data from the contacts.txt file works correctly.