This application features the Hibernate model for the MySQL books
table (see Java Books Application)
applied to a GUI Swing application.
The frame layout is intended to be strictly a demonstration of various
Java Swing and NetBeans designer usage.
For expedience, you can
download the
SwingBooks.zip
archive and install it as a Java Project with Existing Sources
(remembering to add the MySQL and Hibernate Libraries), but I recommend
following the step-by-step construction outlined below.
JDialog
A Java GUI application should only ever use
oneJFrame object.
The JDialog class is the Swing class used to generate additional
windows.
A JDialog object has all the capabilites of the JFrame;
the biggest difference is that it
must be "associated with" a JFrame.
In particular, the constructor for a JDialog class
must initialize the superclass with the
JFrame
"parent" object.
A constructor for the dialog class usually requires at least one parameter
in order to achieve this effect with code like this:
public class MyDialog extends JDialog {
public MyDialog(java.awt.Frame parent) {
super(parent);
...
}
}
The dialog is "popped up" and "popped down"
using the setVisible call with
values true and false, respectively.
modality
The other key feature of a JDialog is its boolean
modal property.
This property expresses whether the dialog should "block" actions
in the original GUI. A modality of
true means to block actions,
a modality of false (the default) means to let the actions
of the GUI continue. A common way to set the modality is through the
superclass constructor passed via a second parameter in the dialog's
constructor, like this:
public class MyDialog extends JDialog {
public MyDialog(java.awt.Frame parent, boolean modal) {
super(parent, boolean modal);
...
}
}
The dialog creation is likely to be this (expressing the most
common situation):
... frame = /* the GUI application's JFrame */
MyDialog dialog = new MyDialog(frame,true);
The modality can be modified after instantiation
using the setModal function:
dialog.setModal(<true or false>);
View Construction
You have to have the books table set up in the test database
accessible by the guest user with empty password as discussed
in Java Books Application.
For definiteness sake, initialize the table using
the mysql client in a shell:
mysql -u guest test < table.sql
Create a new Java Application project.
Set the project name to be SwingBooks.
Add the MySQL and Hibernate libraries to the project.
Add the .xml files and hibernatemodels package from
BooksApp into this project. The easiest way to do so is to
select the <default package> in BooksApp
right-click and select Copy
select Source Packages in SwingBooks
and paste
Repeat for the hibernatemodels package.
Rename hibernatemodels to models. This can be achieved
by right-clicking the hibernatemodels package, selecting
Refactor Rename, changing the
name to "models" and pressing the Refactor button.
You may get a warning message which should just be ignored.
Double-check that the refactoring was complete.
Look at books.hbm.xml and check that you have
<class name="models.Book" table="books">
Create a new JFrame Form with:
Class Name: Frame
Package: views
Modify Frame in design mode.
Using the Free Design layout for simplicity,
drag 4 JButtons,
1 JLabel and 1 JTextField onto the form in a design something
like this:
Edit Frame in source mode, adding the import:
import java.awt.event.*;
and adding this code within the Frame class:
public String getIdText() {
return id.getText();
}
public void addDumpActionListener(ActionListener listener) {
dump.addActionListener(listener);
}
public void addSelectActionListener(ActionListener listener) {
select.addActionListener(listener);
}
public void addAddActionListener(ActionListener listener) {
add.addActionListener(listener);
}
public void addUpdateActionListener(ActionListener listener) {
update.addActionListener(listener);
}
Create a new JDialog Form (first time, go through Other)
with:
Class Name: AddUpdateDialog
Package: views
Modify AddUpdateDialog in design mode.
Using the Free Design layout for simplicity, drag 1 JButton,
3 JLabels and 3 JTextFields onto the form in a design something
like this:
Edit AddUpdateDialog in source mode,
adding the import:
import java.awt.event.*;
and adding this code within the AddUpdateDialog class:
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getTitleText() { return title.getText(); }
public void setTitleText(String text) { title.setText(text); }
public String getTypeText() { return type.getText(); }
public void setTypeText(String text) { type.setText(text); }
public String getQtyText() { return qty.getText(); }
public void setQtyText(String text) { qty.setText(text); }
public enum Mode { ADD, UPDATE };
private Mode mode;
public Mode getMode() { return mode; }
public void setMode(Mode mode) {
this.mode = mode;
if (mode == Mode.ADD) {
button.setText("Add");
setTitle("Add");
} else if (mode == Mode.UPDATE) {
button.setText("Update");
setTitle("Update");
}
}
public void addButtonActionListener(ActionListener listener) {
button.addActionListener(listener);
}
Controller Construction
To emphasize what effects what, we'll add functionality to
the application one step at a time. In this demo application,
the effects are seen in the Ouput window as standard output.
You may want to uncomment the "System.err.close()" statement
to clean up the appearance of the output.
The code illustrates the user-defined interface of the
Frame and AddUpdateDialog classes by bolding the member
access.
Frame functionality
Modify Main to be the code below.
Test run your application to ensure that the GUI frame appears.
package swingbooks;
import javax.swing.*;
import java.awt.event.*;
import org.hibernate.*;
import org.hibernate.criterion.*;
import java.util.*;
import views.*;
import models.*;
public class Main {
private Frame frame = new Frame();
private DB db = new DB();
private AddUpdateDialog dialog = new AddUpdateDialog(frame, true);
private void error(String message) {
JOptionPane.showMessageDialog(frame, message);
}
public Main() {
frame.setBounds(0, 0, 250, 350);
frame.setTitle("Books GUI Example");
frame.setVisible(true);
/* add functionality here */
}
public static void main(String[] args) {
//System.err.close();
new Main();
}
}
Add functionality for the Dump Books Table button
by appending this code to Main():
The dialog should pop up, but nothing will happen yet.
Add functionality for the Select by id button
by appending this code to Main():
frame.addSelectActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
try {
int id = Integer.parseInt(frame.getIdText().trim());
Session sess = db.getSession();
Book book = (Book) sess.load(Book.class, id);
System.out.println(book);
System.out.println("------------------------");
} catch (NumberFormatException x) {
JOptionPane.showMessageDialog(frame, "id field is incorrect");
} catch (Exception x) {
JOptionPane.showMessageDialog(frame, x.toString());
}
}
});
Enter an id into the text field and activate the button.
Try correct id's (1-5), junk values like "", and out-of range
values like -1, 10.
Add initial functionality for the Update by id button
by appending this code to Main():
frame.addUpdateActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
try {
int id = Integer.parseInt(frame.getIdText().trim());
Session sess = db.getSession();
Book book = (Book) sess.load(Book.class, id);
dialog.setMode(AddUpdateDialog.Mode.UPDATE);
dialog.setId(id);
dialog.setTitleText(book.getTitle());
dialog.setTypeText(book.getType());
dialog.setQtyText("" + book.getQty());
dialog.setVisible(true);
} catch (NumberFormatException x) {
error("id field is incorrect");
} catch (Exception x) {
error(x.toString());
}
}
});
The dialog should pop up with the correct
values inserted, but nothing will happen yet.
You can see how we reuse this dialog for both add
and update functions.
Dialog functionality
We continue the process by adding functionality for
the dialog.
Complete the functionality for the
Add and
Update by id buttons
by appending this code to Main():
dialog.addButtonActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
Session sess = db.getSession();
sess.getTransaction().begin();
try {
String title = dialog.getTitleText().trim();
String type = dialog.getTypeText().trim();
int qty = Integer.parseInt(dialog.getQtyText().trim());
AddUpdateDialog.Mode mode = dialog.getMode();
if (mode == AddUpdateDialog.Mode.UPDATE) {
int id = dialog.getId();
Book book = (Book) sess.load(Book.class, id);
book.setTitle(title);
book.setType(type);
book.setQty(qty);
} else {
// mode == AddUpdateDialog.Mode.ADD
Book book = new Book(title, type, qty);
sess.save(book);
}
sess.getTransaction().commit();
dialog.setVisible(false);
} catch (NumberFormatException x) {
error("id field is incorrect");
} catch(HibernateException x) {
error(x.getCause().toString().replaceFirst(".*: ", ""));
} catch (Exception x) {
error(x.toString());
}
}
});
Test the Add Book button by keying in:
title: Another Book
type: paper
quantity: 22
and pressing the dialog's Add button.
Activate the Dump Books Table button to confirm.
Test the Update button by entering an id of your choice,
modifying it (like changing the quantity), pressing
the dialog's Update button and then Dump Books Table button to confirm.
Modify the closing behavior of the dialog
by appending this code to Main():
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
if (dialog.getMode() == AddUpdateDialog.Mode.ADD) {
if (dialog.getTitleText().trim().equals("") &&
dialog.getTypeText().trim().equals("") &&
dialog.getQtyText().trim().equals("")) {
dialog.setVisible(false);
} else {
// in "Add Mode" query the user to close if something
// has been entered into one of the fields
String message = "Do you want to exit\n" +
"without saving changes ?";
int response = JOptionPane.showOptionDialog(
frame, message, null, JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE, null, new String[]{"yes", "no"}, "no");
if (response == JOptionPane.YES_OPTION) {
dialog.setVisible(false);
}
}
} else {
// dialog.getMode() == AddUpdateDialog.Mode.UPDATE;
// this would be more difficult to check for changes
dialog.setVisible(false);
}
}
});
This change only affects the Add dialog.
Test it by activating the Add Book button, entering something
in any of the fields and closing the window with the "x". You'll
see that you have to "say yes" to complete the closing.
The idea is to prevent unintended loss of an addition.