The temperature converter GUI consists of two labels and two text fields. Typing a temperature into the Celsius field and then pressing the "Enter" key causes the equivalent Fahrenheit temperature to appear in the Fahrenheit field and vice versa.
Typing a non-numeric value into either field causes the following error dialog to appear:
Model, View, and Controller are just roles to be played by user-defined classes. In this application the role of Model is played by TempConverter. The role of View is played by ConverterGUI, and the role of Controller is played by ConverterController.
All views extends Swing's JPanel class. All controllers implement AWT's ActionListener interface:
TempConverter plays the role of model and is very simple:
ConverterGUI plays the role of view. It extends JPanel and contains two text fields and a title. It also contains references to the model and controller.
One point of interest in the ConverterGUI is the reusable display method. This method creates a top-level or desktop JFrame to hold this JPanel, then sets visibility to true. This launches a parallel thread
public
void display() {
JFrame frame = new
JFrame();
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setVisible(true);
}
Here's main. When display is called a parallel thread is launched containing the GUI's listener loop. When the top-level window is closed, then main terminates.
public
static void
main(String[] args) {
ConverterGUI gui = new ConverterGUI();
gui.display();
}
The ConverterController plays the role of controller. It implements the ActionListener interface. This means two things. First, the controller can register itself with controls that it is interested in:
celsiusField.addActionListener(controller);
farField.addActionListener(controller);
Second, it must implement the actionPerformed method:
public void
actionPerformed(ActionEvent e) {
// interact with model and view here
}
Each time the user types something into one of the text fields then presses the "enter" key, the Java VM creates an instance of ActionEvent containing the identity of the control that fired the event, then passes this object to the actionPerformed method of every registered listener.
Here's the complete implementation:
We can improve the design of a view by declaring the controllers to be inner classes.
Instances of inner classes (called products) are associated with instances of the outer class that created them (called factories). Products have full access to the fields of their associated factories, private or otherwise. It is not necessary for an "inner" controller to constantly call getter and setter methods to access the controls and models of its outer view class.
Here's an example:
ConverterGUI.java (version 2)
In the next version of our temperature converter, we add a command menu:
Selecting a command displays an input dialog:
Clicking the "OK" button updates the main window:
Here's the implementation:
The menu bar is a field:
private JMenuBar menuBar;
Note that the display method attaches the menu bar to the desktop frame:
public
void display() {
JFrame frame = new JFrame();
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(menuBar);
frame.add(this);
frame.pack();
frame.setVisible(true);
}
The menu bar is initialized in the constructor with a call to makeMenus:
private
void makeMenus() {
menuBar
= new JMenuBar();
JMenu cmmdMenu = new JMenu("Commands");
JMenuItem item = new JMenuItem("f2c");
item.addActionListener(menuController);
cmmdMenu.add(item);
item = new
JMenuItem("c2f");
item.addActionListener(menuController);
cmmdMenu.add(item);
item = new
JMenuItem("exit");
item.addActionListener(menuController);
cmmdMenu.add(item);
menuBar.add(cmmdMenu);
}
Finally, an inner controller class is declared:
class
MenuController implements
ActionListener {
private
double getTemperature(String prompt)
{
String response = JOptionPane.showInputDialog(prompt);
return
new Double(response);
}
public
void actionPerformed(ActionEvent e) {
String cmmd =
e.getActionCommand();
if
(cmmd.equals("f2c")) {
double
fTemp = getTemperature("Enter Fahrenheit
temperature");
double
cTemp = model.f2c(fTemp);
celsiusField.setText("" + cTemp);
farField.setText("" + fTemp);
} else
if (cmmd.equals("c2f")) {
double
cTemp = getTemperature("Enter Celisius
temperature");
double
fTemp = model.c2f(cTemp);
celsiusField.setText("" + cTemp);
farField.setText("" + fTemp);
} else
{ // cmmd == exit
System.exit(0);
}
}
}