Introduction
A callback mechanism in your software allows a window(*)
in your application to communicate with some other window
within the application (or applet). (For this article,
the term "application" refers to both Java
applications and Java applets, client-side.) The basic
mechanism is easy to implement and works well. With
complicated applications, the interactions of data and
other activity between windows can become confusing
so don't introduce any more complexity than is necessary.
Keep it simple.
Overview
of the Program
To begin, the Java entity that makes it all work are
Java interfaces. Remember that interfaces only contain
signatures and final definitions - no implementation
code. The advantage here is a vaunted object-oriented
trait: you can provide tailored implementations for
unique uses of common signatures. To illustrate, I'll
use a simple program with one main window and one secondary
window. The main window contains a textarea to show
data and a Modify button. When the Modify button is
pressed, a second window will be displayed where the
user can make selections then modify the main display.
In
the code, first the main display is built and shown.
Next, the user clicks the Modify button and the secondary
Options display is created. Upon invocation, it is passed
a reference handle for the main display. The Options
display is then shown. In the Options display's class
code below (OptionWin.java), you will see a class variable
declaration for the callback interface (CbkIF.java)
which is implemented in the main class (MainWin.java).
When the constructor for the Options display class is
executed, the reference handle to the main class that
arrives over the parameter, is assigned to this class
variable. This is what ties the two classes together
so the secondary window can communicate (send data)
back to the main class.
To
demonstrate, the user selects desired options. When
finished with the choices, the user clicks the Apply
button. Upon Apply, the choices are gathered from the
display widgets then passed to the main class by the
callback mechanism where they are used to modify the
main display.
Code
Example
Below is the code for the application described above.
It was compiled on a Linux box with the Java Standard
Edition version 1.2. Look carefully at this code. I
have added comments next the important points. The code
consists of two classes (MainWin and OptionWin) and
one interface (CbkIF).
Code
Style
Ordinarily, in real applications used in industry, I
put all String definitions into an interface so they
will be isolated from the code. This facilitates change
when change is needed so that the developer does not
have to poke through the code changing each string individually.
It is especially important to isolate string definitions
for internationalizing an application. Sometimes I also
put widget definitions into an interface to isolate
those, particularly when a widget is used on different
displays (probably not static). When doing that, the
widget definitions cannot be changed in the program.
You
may notice that for all methods, I have used the final
designation. This helps performance, especially in large
applications. The compiler will inline a final method
so calls on the callstack are reduced and that overhead
is eliminated. Final methods cannot be overridden.
A
couple of other design flaws exist in this example for
the sake of clarity and expediency. Some of those are:
-
the exit() method is simply invoked. In real applications,
any needed cleanup should be performed and possibly
confirmation requested from the user for the exit.
- when
the secondary window is closed, it is not destroyed
but rather simply set to not visible. This is acceptable
when the method invoking the secondary window checks
whether or not it is already created before just blindly
creating it.
INTERFACE:
// File: CbkIF.java
// Author: Marie Alm, Crystal Software, http://www.crystalsw.com/
// Date: 10 March 2002
//
use default package
import
java.awt.*;
/**
This interface defines the signatures used in illustrating
a callback mechanism.
@author Marie Alm
@date 10 March 2002
*/
public interface CbkIF
{
public void modifyData(String data);
public void modifyBgColor(Color colr);
}
MAIN
CLASS:
// File: MainWin.java
// Author: Marie Alm, Crystal Software, http://www.crystalsw.com/
// Date: 10 March 2002
//
use default package
import
java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
/**
This program illustrates a callback mechanism between
displays.
@author
Marie Alm
@date 10 March 2002
*/
public class MainWin
implements CbkIF
{
OptionsWin optWin;
JFrame frm = new JFrame();
JPanel pnlMain = new JPanel(new BorderLayout());
JButton btnMod = new JButton("Modify");
JButton btnExit = new JButton("Exit");
// use default FlowLayout
JPanel btnPnl = new JPanel();
// rows, cols
JTextArea ta = new JTextArea(10,30);
//=============================================
public static void main(String[] args)
{
MainWin mw = new MainWin();
}
//---------------------------------------------
// note: dividers between methods make code easier to
read.
//---------------------------------------------
public MainWin()
{
buildWindow();
frm.pack();
frm.show();
}
//---------------------------------------------
public final void buildWindow()
{
// add listeners
btnMod.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent evt)
{ showOptionsWin(); }
});
btnExit.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent evt)
{ doExit(); }
});
// add widgets to frame
btnPnl.add(btnMod);
btnPnl.add(btnExit);
pnlMain .add(ta, BorderLayout.CENTER);
pnlMain .add(btnPnl, BorderLayout.CENTER);
// contPane is handle to the root container
// use default BorderLayout
Container contPane = frm.getContentPane();
contPane.add(pnlMain, BorderLayout.CENTER);
}
//---------------------------------------------
public void doExit()
{ System.exit(0);
}
//---------------------------------------------
public void showOptionsWin()
{
// passing the "this" reference allows the
Option display
// to communicate back to the main display
optWin = new OptionsWin(this);
}
//---------------------------------------------
// This method sets the given string data into the textarea.
// It is invoked from the Option display through the
// callback mechanism.
public void modifyData(String data)
{ ta.setText(data);
}
//---------------------------------------------
// This method sets the background color of the main
panel.
// It is invoked from the Option display through the
// callback mechanism.
public void modifyBgColor(Color colr)
{ pnlMain.setBackground(colr);
}
} // end class
SECONDARY CLASS:
// File: OptionsWin.java
// Author: Marie Alm, Crystal Software, http://www.crystalsw.com/
// Date: 10 March 2002
//
use default package
import
java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
/**
This secondary window displays options to the user.
If the user clicks the Apply button, the currently chosen
settings are passed back to the main display via a callback
mechanism.
@author Marie Alm
@date 10 March 2002
*/
public class OptionsWin
{
private static final String[] COLORS = {"blue",
"red", "pink"};
// declare the callback class variable
CbkIF cbk;
// widgets
JFrame frm2 = new JFrame();
JPanel pnlMain2 = new JPanel(new BorderLayout());
JComboBox colors = new JComboBox(COLORS );
JButton btnAppl = new JButton("Apply");
JButton btnDone = new JButton("Done");
// use default FlowLayout
JPanel btnPnl = new JPanel();
// cols
JTextField tf = new JTextField (30);
//=============================================
public OptionsWin(CbkIF c)
{
cbk = c;
buildWindow();
frm2.pack();
frm2.show();
}
//---------------------------------------------
public final void buildWindow()
{
// add listeners
btnAppl.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent evt)
{ doApply(); }
});
btnDone .addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent evt)
{ doDone(); }
});
// add widgets to frame
btnPnl.add(btnAppl);
btnPnl.add(btnDone);
pnlMain2.add(colors, BorderLayout.CENTER);
pnlMain2.add(tf, BorderLayout.CENTER);
pnlMain2.add(btnPnl, BorderLayout.CENTER);
// contPane is handle to the root container
// use default BorderLayout
Container contPane = frm2.getContentPane();
contPane.add(pnlMain2, BorderLayout.CENTER);
}
//---------------------------------------------
public final void doDone()
{ frm2.setVisible(false);
}
//---------------------------------------------
// Grab user's choices and send them back to the main
display.
public final void doApply()
{
String txt = tf.getText();
Color colr = getColorString();
// this section invokes the methods implemented in the
main class
// this can be considered the heart of the callback
mechanism
if (cbk != null)
{
cbk.modifyData(txt);
cbk.modifyBgColor(colr);
}
}
//---------------------------------------------
// Determine the color selection.
public final Color getColorString()
{
Color colr = null;
String colrstr = (String)colors.getSelectedItem();
if (colrstr == COLORS[0])
colr = Color.blue;
else if (colrstr == COLORS[1])
colr = Color.red;
else
colr = Color.pink;
return colr;
}
} // end class
Main Points
The main important points for this callback system are
given here. Together, when placed in the proper locations
with the code, they comprise a callback mechanism which
allows a display to send data from a secondary window
to another window.
-
the definitions contained in the interface
public
void modifyData(String data);
public void modifyBgColor(Color colr);
- passing
a reference handle of the main class to the secondary
class
optWin
= new OptionWin(this);
-
the invocation of the work methods in the main class
from the secondary class
cbk.modifyData(txt);
cbk.modifyBgColor(colr);
- implementing
in the main class, the methods defined in the interface
public
void modifyData(String data)
{
}
public void modifyBgColor(Color colr)
{
}
Conclusion
A simple callback mechanism has been described within
the context of a simple two-window GUI application.
The example code can be used in your applications as
a starting point for implementing your own callbacks.
* the term "window" is used generically
and interchangeably with the term "display.
|