MokaByte 61 - Marzo 2002 
Round Trip GUI Display Communication
di
Marie Alm
This article describes a simple callback mechanism. Different displays in a GUI application use this to send and receive data to and from each other

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.

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it