J/Link Tutorial

Creating a basic modal dialog box

This tutorial shows you how to create a basic dialog box that prompts the user to enter an angle, with a choice of whether it is being specified in degrees or radians. This example will demonstrate a dialog box that returns a value to a running Mathematica program when it is dismissed, much like Mathematica’s built-in Input[] function, which requests a string from the user before returning. Dialog boxes like this one are not modal in the traditional sense that they must be closed before other Java windows can be used, but they are modal with respect to the kernel, which is kept busy until they are dismissed (that is, until DoModal[] returns). Section 1.2.5 of the J/Link User Manual discusses modal and modeless Java windows in detail.

Starting Out

The code is rather straightforward and warrants little in the way of commentary. In creating the window and the controls within it, the code exactly mirrors the Java code you would use if you were writing the program in Java. One technique it demonstrates is determining whether the OK or Cancel button was clicked to dismiss the dialog box. This is done by having the MathActionListener objects assigned to the two buttons return different values in addition to calling EndModal[]. Recall that DoModal[] returns whatever the code that calls EndModal[] returns, so here you have the OK button execute (EndModal[]; True)&, a pure function that ignores its arguments, calls EndModal[], and returns True. The Cancel button executes (EndModal[]; False)&. Thus, DoModal[] returns True if the OK button was clicked, or False if the Cancel button was clicked. It will return Null if the window’s close box was clicked. This behavior comes from the MathFrame itself.

It may take several seconds to display the dialog box the first time GetAngle[] is called. This is because of the one-time cost of loading the several large AWT classes required. Subsequent invocations of GetAngle[] will be much quicker.

GetAngle[] :=
	JavaBlock[
		Module[\({frm, \ inputField, \ cbGroup, \ degBox, \ 
              radBox, 
					label, \ okButton, \ cancelButton, \ 
              wasOKButton, \ angle}\),

			InstallJava[];    

			frm  =  
                JavaNew["com.wolfram.jlink.MathFrame"];
			label  =  
                JavaNew["java.awt.Label",  "Enter an angle:"];
			inputField  =  
                JavaNew["java.awt.TextField",  20];
			cbGroup  =  
                JavaNew["java.awt.CheckboxGroup"];
			degBox  =  
                JavaNew["java.awt.Checkbox",  "degrees",  
                  cbGroup,  True];
			radBox  =  
                JavaNew["java.awt.Checkbox",  "radians",  
                  cbGroup,  False];
			okButton  =  
                JavaNew["java.awt.Button",  "OK"];
			cancelButton  =  
                JavaNew["java.awt.Button",  "Cancel"];
			
			frm@setLayout[Null];
			frm@add[label];
			frm@add[inputField];
			frm@add[degBox];
			frm@add[radBox];
			frm@add[okButton];
			frm@add[cancelButton];
			
			frm@setBounds[200,  200,  200,  160];
			label@setBounds[20,  30,  150,  20];
			inputField@setBounds[20,  70,  60,  20];
			degBox@setBounds[100,  60,  80,  20];
			radBox@setBounds[100,  80,  80,  20];
			okButton@setBounds[40,  120,  50,  20];
			cancelButton@
                setBounds[100,  120,  50,  20];
			frm@setResizable[False];

			\(okButton@
                addActionListener[
				JavaNew["com.wolfram.jlink.MathActionListener", 
							"(EndModal[]; True)&"]
			]\);
			\(cancelButton@
                addActionListener[
				JavaNew["com.wolfram.jlink.MathActionListener", 
							"(EndModal[]; False)&"]
			]\);
			
			  
			JavaShow[frm];

			frm@setModal[];
			wasOKButton  =  DoModal[];
			  
			If[TrueQ[wasOKButton],
				\(angle\  = \ 
                    ToExpression[inputField@getText[]]; 
				If[
                    angle\  =!= \ Null\  && \ degBox@getState[], \ 
                    angle\  *= \ Pi/180]\),
			  
				(* You will get here if the Cancel button was clicked \((wasOKButton
					will\ be\ False)\), \(or\ the\ dialog\ box\ was\ closed\ by\ clicking\ in\ its
					close\ box\ \(\((wasOKButton\ will\ be\ Null)\)\(.\)\)\)
				*)
				angle  =  $Failed
			];
			(* If the Cancel or OK buttons were clicked, frm is still visible,
				so we dispose it here. *)
			frm@dispose[];
			angle
		]
	]

Final Code

The following example combines all the above elements for J/Link to produce a basic dialog box for converting an angle into degrees or radians.

Needs["JLink`"]

GetAngle[] :=
	JavaBlock[
		Module[{frm, inputField, cbGroup, degBox, radBox, label, okButton, cancelButton, wasOKButton, angle},

			InstallJava[];

			frm = JavaNew["com.wolfram.jlink.MathFrame"];
			label = JavaNew["java.awt.Label", "Enter an angle:"];
			inputField = JavaNew["java.awt.TextField", 20];
			cbGroup = JavaNew["java.awt.CheckboxGroup"];
			degBox = JavaNew["java.awt.Checkbox", "degrees", cbGroup, True];
			radBox = JavaNew["java.awt.Checkbox", "radians", cbGroup, False];
			okButton = JavaNew["java.awt.Button", "OK"];
			cancelButton = JavaNew["java.awt.Button", "Cancel"];
			
			frm@setLayout[Null];
			frm@add[label];
			frm@add[inputField];
			frm@add[degBox];
			frm@add[radBox];
			frm@add[okButton];
			frm@add[cancelButton];
			
			frm@setBounds[200, 200, 200, 160];
			label@setBounds[20, 30, 150, 20];
			inputField@setBounds[20, 70, 60, 25];
			degBox@setBounds[100, 60, 80, 20];
			radBox@setBounds[100, 80, 80, 20];
			okButton@setBounds[40, 120, 50, 20];
			cancelButton@setBounds[100, 120, 50, 20];
			frm@setResizable[False];
			
			okButton@addActionListener[JavaNew["com.wolfram.jlink.MathActionListener", "(EndModal[]; True)&"]];
			cancelButton@addActionListener[JavaNew["com.wolfram.jlink.MathActionListener", "(EndModal[]; False)&"]];
			
			JavaShow[frm];

			frm@setModal[];
			wasOKButton = DoModal[];
			(* Even though the window may have been closed, it is perfectly okay to extract values from the
			   controls in the window.
			*)
			If[TrueQ[wasOKButton],
				angle = ToExpression[inputField@getText[]];
				If[angle =!= Null && degBox@getState[], angle *= Pi/180],
			(* else *)
				(* You will get here if the Cancel button was clicked (wasOKButton will be False),
				   or if the dialog box was closed by clicking in its close box (wasOKButton will be Null).
				*)
				angle = $Failed
			];
			(* If the Cancel or OK buttons were clicked, frm is still visible, so we dispose of it here. *)
			frm@dispose[];
			angle
		]
	]

Example

GetAngle[]