Let's suppose that we want to duplicate the button example of the previous section, but set up the Tcl callback ourselves in Java. In this example, we'll set up the event processing so that a Tcl script is executed every five times we press the button. The full source code is in tutorial/tcltk98/TclButton.java.
The class has instance variables that reference a Tcl interpreter, a string containing a Tcl script, and a counter:
public class TclButton extends java.awt.Button {
Interp tclInterp;
String tclScript;
int count = 5;
The constructor of TclButton requires a Tcl interpreter. Generally,
you will want to provide the same interpreter that is running the rest
of your Tcl/Tk interface, and which can be obtained by calling the
java::getinterp procedure. The constructor is:
public TclButton (Interp interp) {
super("Push me!");
tclInterp = interp;
addActionListener(new LocalListener());
}
We'll need a method to set the script to be executed:
public void setScript (String script) {
tclScript = script;
}
As before, we create a local class that implements the ActionListener
interface. This time, though, we get the "notifier" from the
interpreter and pass it an instance of tcl.lang.TclEvent. The
notifier ensures that the event will be processed by the primary
thread of the interpreter, thus avoiding thread synchronization
problems. (If, on the other hand, you execute tclInterp.eval
directly in the actionPerformed method, the button hangs.)
After queuing the event with the notifier, we call the sync
method of the Tcl event object to ensure that the script has been
evaluated before we return.
class LocalListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (--count == 0) {
count = 5;
Notifier n = tclInterp.getNotifier();
TclEvent t = new EvalEvent();
n.queueEvent(t,TCL.QUEUE_TAIL);
t.sync();
}
}
}
Finally, we need a subclass of tcl.lang.TclEvent that
overrides the processEvent method to evaluate the
script:
class EvalEvent extends TclEvent {
public int processEvent (int flags) {
try {
tclInterp.eval(tclScript);
}
catch (Exception x) {}
return 1;
}
}
To try this out, compile TclButton.java and then execute:
set button [java::new tutorial.tcltk98.TclButton [java::getinterp]]
$button setScript \
"toplevel .t; label .t.l -text {Five!}; pack .t.l; after 1000 {destroy .t}"
set window [java::new java.awt.Frame]
$window setLocation 100 100
$window {add java.awt.Component} $button
$window pack
$window show
Every five times the button is pressed, the Tcl script is executed,
which pops up a little Tk message window! We hope that this example,
although a bit forced, gives you the flavor of a mixed Java-Tcl event
handling environment.