AMAPstudio

User Tools


How to build a specific dialog box for an intervener

This is a complement to the doc How to write an intervention tool, it explains how to replace the automatic dialog box by a more specific one.

In this documentation, we will consider the example of the Diameter Height Age intervener, with two classes:

  • capsis.extension.intervener.DHAThinner
  • capsis.extension.intervener.DHAThinnerDialog

To build the dialog box:

  • a new class is built in the same package to implement the dialog box,
  • in the intervener, the initGUI () is changed.

Create a new class for the dialog box

In the same package than the intervener, create a class with same name and appending an extra “Dialog” .java. E.g. for DHAThinner → DHAThinnerDialog. You may copy the code below as a template and adapt it for your own case.

Before beginning

It is generally a good idea to draw your dialog on a sheet of paper before beginning. When you think your drawing is ok, it will help you code it in one single pass. It is recommended to choose nice and accurate names for the variables. The numeric variables in the intervener (e.g. private float min;) and the widgets variables in the dialog (e.g. private JTextField min;) may have the same names (they are not in the same class, no possible confusion).

The code of the dialog is commented below step by step.

/*
 * Capsis 4 - Computer-Aided Projections of Strategies in Silviculture
 * 
 * Copyright (C) 2000-2003 Francois de Coligny
 * 
 * This library is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with this library;
 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 */
 
package capsis.extension.intervener;
 
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.Locale;
 
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
 
import jeeb.lib.util.AmapDialog;
import jeeb.lib.util.Check;
import jeeb.lib.util.ColumnPanel;
import jeeb.lib.util.MessageDialog;
import jeeb.lib.util.LinePanel;
import jeeb.lib.util.Translator;
import capsis.commongui.command.tmp.Helper;
import capsis.defaulttype.Tree;
 
/**
 * This dialog box is used to set DHAThinner parameters in interactive context.
 * 
 * @author F. de Coligny - march 2002
 */
public class DHAThinnerDialog extends AmapDialog implements ActionListener {
 
	// 24.6.2002 - fc - bug correction (phd) : getMin () and getMax () returned int values, now they
	// return float. DHAThinner version passed to 1.1.

Depending on the compatibility of this extension (see the matchWith () method in the intervener class, e.g. DHAThinner), it should be written in different packages:

  • If the extension is generic (can work for several Capsis modules), it should go into the package names capsis.extension.intervener and should be distributed under the LGPL license (free software, copy the license comment at the top.
  • If the extension is specific to some module named somemodule, it should be put in a package named somemodule.extension.intervener and the distribution license is the choice of the author (maybe do not copy the LGPL license text at the top).

The class comment should explain clearly what the class does and the @author tag is required (author's name and 'month year').

The dialog class should extend AmapDialog and implement ActionListener (to manage the responses to button clicks, see below).

	private NumberFormat nf;
 
	private DHAThinner thinner;
 
	private ButtonGroup group1;
	private JRadioButton dbh;
	private JRadioButton height;
	private JRadioButton age;
	private JTextField min;
	private JTextField max;
 
	protected JButton ok;
	protected JButton cancel;
	protected JButton help;

The instance variables (the main variables of the dialog) :

  • The reference to the intervener which configuration this dialog is for
  • Widgets to get the user values (all beginning by J…, part of the java swing widgets system)
    • JTextField to get from the user (or show) a number or String value
    • JCheckBox to activate / desactivate an option
    • JRadioButtons to choose one single option among several proposals (they must be added in a ButtonGroup)
    • JButtons to open other dialogs or validate this dialog
  • Additional variables, e.g. a NumberFormat to format numbers nicely in textfields (e.g. 1.1768002 → 1.18)
 
	/**	
	 * Constructor
	 */
	public DHAThinnerDialog (DHAThinner thinner) {
		super ();
 
		this.thinner = thinner;
 
		// To show numbers in a nice way
		nf = NumberFormat.getInstance (Locale.ENGLISH);
		nf.setGroupingUsed (false);
		nf.setMaximumFractionDigits (3);
 
		createUI ();
		presetMinMax ();
		setTitle (Translator.swap ("DHAThinnerDialog"));
 
		setModal (true);
 
		// location is set by the AmapDialog superclass
		pack (); // uses component's preferredSize
		show ();
 
	}

The constructor should accept one parameter (at least one, more is possible): the intervener under configuration.

It first calls the constructor of the superclass (AmapDialog), then memorizes the intervener in its instance variable and prepares the dialog:

  • create and tune the NumberFormat
  • call the createUI () method to build the dialog contents (createUI () is generally long, placed at the source bottom for convenience, see lower)
  • optionally run some 'first time operations' (presetMinMax ())
  • setTitle (something through the Translator)
  • setModal (true): nothing can be done outside the dialog until it is closed, needed here
  • pack (): calculate the dialog size according to the components added in createUI ()
  • show (): set the dialog visible

When the dialog is set visible, the code execution is suspended to the user actions: using the widgets to configure the options and clicking on the buttons will trigger actions (see below for the linking). When the dialog is set invisible again, the code of the caller will go on again.

	/**
	 * Accessor for context.
	 */
	public int getContext () {
		if (dbh.isSelected ()) {
			return DHAThinner.DBH;
		} else if (height.isSelected ()) {
			return DHAThinner.HEIGHT;
		} else {
			return DHAThinner.AGE;
		}
	}
 
	/**
	 * Accessor for min value.
	 */
	public float getMin () {
		if (min.getText ().trim ().length () == 0) { return 0; }
		return (float) Check.doubleValue (min.getText ().trim ());
	}
 
	/**
	 * Accessor for max value.
	 */
	public float getMax () {
		if (max.getText ().trim ().length () == 0) { return Float.MAX_VALUE; }
		return (float) Check.doubleValue (max.getText ().trim ());
	}

Accessors to get the user values at the end. These accessors may return directly the values they extract from the widgets without checking for error.

Checking the user entries

All the user entries checks are done when hitting the Ok button. If an error is found, a message appears and the method stops (see OkAction () below). That's why it is not requested to recheck here: these methods will be used by the caller once the dialog shut by Ok.
	/**
	 * Action on ok button.
	 */
	private void okAction () {
 
		boolean minIsEmpty = Check.isEmpty (min.getText ().trim ());
		boolean maxIsEmpty = Check.isEmpty (max.getText ().trim ());
 
		// Checks...
		if (minIsEmpty && maxIsEmpty) {
			MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.someValueIsNeeded"));
			return;
		}
 
		// Age must be an int
		if (age.isSelected ()) {
			if (!minIsEmpty && !Check.isInt (min.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap (
                                        "DHAThinnerDialog.ageMustBeAnInteger"));
				return;
			}
			if (!maxIsEmpty && !Check.isInt (max.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap (
                                        "DHAThinnerDialog.ageMustBeAnInteger"));
				return;
			}
 
		// Dbh and height must be doubles
		} else {
			if (!minIsEmpty && !Check.isDouble (min.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ( 
                                        "DHAThinnerDialog.bothValuesMustBeNumbers"));
				return;
			}
			if (!maxIsEmpty && !Check.isDouble (max.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ( 
                                        "DHAThinnerDialog.bothValuesMustBeNumbers"));
				return;
			}
 
		}
 
		// Min must be lower than max
		if (!minIsEmpty && !maxIsEmpty) {
			if (Check.doubleValue (min.getText ().trim ()) 
                                > Check.doubleValue (max.getText ().trim ())) {
			    MessageDialog.print (this, Translator.swap (
                                    "DHAThinnerDialog.minMustBeLowerThanMax"));
				return;
			}
		}
 
		// All has been checked successfully, set the dialog invisible 
		// and go back to caller (will check for validity and dispose the dialog)
		setValidDialog (true);
	}
 
	/**
	 * Action on cancel button.
	 */
	private void cancelAction () {
		// Set the dialog invisible 
		// and go back to caller (will check for validity and dispose the dialog)
		setValidDialog (false);
	}

These two methods are called resp. when the user hits Ok or Cancel (see below for linking buttons to methods).

okAction (): it is imperative that this method checks all the user entries before setting the dialog valid by setValid (true). To check the user JTextFields, you may use the Check class: pass its methods the String in the JTextField and ask if it is an int, a double, what is the int or double value… See Check for more details.

For example, if we assess that the min JTextField must contain a double value :

  1. We can get the String in the JTextField with min.getText ().trim () (trim () removes the optional leading and trailing spaces or tabs, convenient and suggested).
  2. We can test if this is a decimal number with if (Check.isDouble (…)) {…}.
  3. If not, we must send a message with MessageDialog (e.g. “min should be a number”) and return. Returning will exit the method and the user will be able to change the value and hit ok again for a second try.

Only if all the user entries are checked correct, set the dialog valid AND invisible with setValidDialog (true).

cancelAction (): called on Cancel, sets the dialog invalid AND invisible.

	/**
	 * Someone hit a button.
	 */
	public void actionPerformed (ActionEvent evt) {
		if (evt.getSource () instanceof JRadioButton) {
			presetMinMax ();
		} else if (evt.getSource ().equals (ok)) {
			okAction ();
		} else if (evt.getSource ().equals (cancel)) {
			cancelAction ();
		} else if (evt.getSource ().equals (help)) {
			Helper.helpFor (this);
		}
	}

actionPerformed () is called each time the user clicks on a button which was registered 'this' (the reflexive reference to the dialog itself) as listener (see createUI () below).

Depending on the source of the given event, we link with some prepared methods. If some buttons are added in createUI (), some new links may be added here.

	/**
	 * Writes the available min max values in the min and max textfields as an information
	 * for the user.
	 */
	private void presetMinMax () {
		if (thinner.concernedTrees == null || thinner.concernedTrees.isEmpty ()) { return; }
 
		double m = Double.MAX_VALUE;
		double M = -Double.MAX_VALUE;
 
		double v = 0;
		for (Tree t : thinner.concernedTrees) {
			if (dbh.isSelected ()) {
				v = t.getDbh ();
 
			} else if (height.isSelected ()) {
				v = t.getHeight ();
 
			} else if (age.isSelected ()) {
				v = t.getAge ();
 
			}
 
			m = Math.min (m, v);
			M = Math.max (M, v);
 
		}
		min.setText (nf.format (m));
		max.setText (nf.format (M));
 
	}

This user method updates the min and max values each time it is called (optional).

	/**
	 * Creates the dialog box user interface.
	 */
	private void createUI () {
 
		// All lines will be inserted in this main column
		ColumnPanel panel = new ColumnPanel ();
 
		// Choose the mode: diameter, height OR age
		LinePanel l1 = new LinePanel ();
		l1.add (new JLabel (Translator.swap ("DHAThinnerDialog.cutTreesWith") + " :"));
		l1.addGlue ();
		panel.add (l1);
 
		// Radio buttons
		LinePanel l10 = new LinePanel ();
		LinePanel l11 = new LinePanel ();
		LinePanel l12 = new LinePanel ();
 
		dbh = new JRadioButton (Translator.swap ("DHAThinnerDialog.dbh"));
		dbh.addActionListener (this);
		height = new JRadioButton (Translator.swap ("DHAThinnerDialog.height"));
		height.addActionListener (this);
		age = new JRadioButton (Translator.swap ("DHAThinnerDialog.age"));
		age.addActionListener (this);
 
		// Add the radio buttons in their group
		group1 = new ButtonGroup ();
		group1.add (dbh);
		group1.add (height);
		group1.add (age);
		// Choose the default selection
		group1.setSelected (dbh.getModel (), true);
 
		l10.add (dbh);
		l10.addGlue ();
		l11.add (height);
		l11.addGlue ();
		l12.add (age);
		l12.addGlue ();
		panel.add (l10);
		panel.add (l11);
		panel.add (l12);
 
		// Min and max fields on a single line
		LinePanel l21 = new LinePanel ();
		min = new JTextField (5);
		max = new JTextField (5);
		l21.add (new JLabel (Translator.swap ("DHAThinnerDialog.between") + " : "));
		l21.add (min);
		l21.add (new JLabel (" " + Translator.swap ("DHAThinnerDialog.and") + " : "));
		l21.add (max);
		l21.addStrut0 ();
		panel.add (l21);
		panel.addGlue ();
 
		// Put the main panel at the top (north) of the user interface
		getContentPane ().setLayout (new BorderLayout ());
		getContentPane ().add (panel, BorderLayout.NORTH);
 
		// Control panel (Ok Cancel Help)
		LinePanel controlPanel = new LinePanel ();
		ok = new JButton (Translator.swap ("Shared.ok"));
		cancel = new JButton (Translator.swap ("Shared.cancel"));
		help = new JButton (Translator.swap ("Shared.help"));
 
		controlPanel.addGlue ();  // adding glue first -> the buttons will be right justified
		controlPanel.add (ok);
		controlPanel.add (cancel);
		controlPanel.add (help);
		controlPanel.addStrut0 ();
 
		ok.addActionListener (this);
		cancel.addActionListener (this);
		help.addActionListener (this);
 
		// Put the control panel at the bottom (south)
		getContentPane ().add (controlPanel, BorderLayout.SOUTH);
 
		// Set Ok as default (see AmapDialog)
		setDefaultButton (ok);
 
	}
 
}

createUI (): this method is called in the constructor before the dialog is set visible. It builds all the dialog inner user interface by creating widgets and placing them nicely.

Why are the JLabels not declared at the top like the other widgets ?

Local JLabels may be created to write some text: we will not need to read them again and we can make them local variables. The other widgets will be created in this method but will be checked and read in others, that's why they are instance variables at the top of the class.

Managing the layout

To place the widgets, we use LinePanels and ColumnPanels:

  • a LinePanel will show all the added widgets on a single line respecting the insertion order
  • a ColumnPanel will show all the widgets in a single column respecting the insertion order

Note: here, we add several lines in a single column to get the final aspect for our dialog (see image upper).

LinePanels and ColumnPanels must be 'closed' by adding a final glue or strut0 component:

  • p.addGlue () adds a variable size space
  • p.addStrut0 () adds a fixed size space (default is 2 pixels)
  • when adding components in a Line or ColumnPanel, strut1 components are automatically added between them (generally 4 pixels)

Finally, we use a BorderLayout to add our panels at the NORTH and SOUTH of the dialog (EAST, WEST and CENTER are also available).

Creating the widgets

All widgets must be instanciated by 'new', taking care of their titles, names…

The widgets which must be listened to must be added a listener with w.addActionListener (this);

They must be all added in some panels to appear on the user interface.

A default button may be set with setDefaultButton (b);

Translations

All texts going to the user interface must be translated by the Translator. This includes the buttons, labels, titles and error messages.

At runtime, the Translator will replace the translation keys (e.g. “DHAThinnerDialog.dbh”) by a text according to the language of the user interface (decided at Capsis launch time, e.g. capsis -l en).

Conventions for the translation keys:

  • ClassName.aMeaningfulText: e.g. “DHAThinnerDialog.dbh”, “Shared.ok” (ok is a shared key in Capsis)…
  • If no translation is found by the Translator, the key will be written 'as is' on the gui: we will see what translation is missing for what key in what class and the user will be able to understand what it means (Dbh, Ok…).
  • The translated texts must be provided in 2 files called DHAThinner_en.properties and DHAThinner_fr.properties for english and french resp. These files are in the same package than the intervener and its dialog. They are loaded into the Translator by this kind of statement (may be found in the intervener OR dialog code):
	static {
		Translator.addBundle ("capsis.extension.intervener.DHAThinner");
	}

Adapt the initGUI () method

In the thinner class (here DHAThinner), the initGUI () method must handle the new dialog box. (i) It first open the dialog. (ii) Then the code is executed within the dialog class until it is set invisible (see the dialog class source code for setValidDialog (true or false). (iii) When the dialog is set invisible, the code continues here and we check if it was either validated or canceled by the user (dlg.isValidDialog ()). (iv) If validated, we get the parameters entered in the dialog and copy them in the intervener instance variables (here context, min and max). Finally and in any case, we dispose() the dialog (destruction and memory release).

	@Override
	public boolean initGUI () throws Exception {
		// Interactive start
		DHAThinnerDialog dlg = new DHAThinnerDialog (this);
 
		constructionCompleted = false;
		if (dlg.isValidDialog ()) {
			// valid -> ok was hit and all checks were ok
			try {
				context = dlg.getContext ();
				min = dlg.getMin ();
				max = dlg.getMax ();
				constructionCompleted = true;
			} catch (Exception e) {
				constructionCompleted = false;
				throw new Exception ("DHAThinner (): Could not get parameters in DHAThinnerDialog", e);
			}
		}
		dlg.dispose ();
		return constructionCompleted;
 
	}

The complete code of the dialog

/*
 * Capsis 4 - Computer-Aided Projections of Strategies in Silviculture
 * 
 * Copyright (C) 2000-2003 Francois de Coligny
 * 
 * This library is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with this library;
 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 */
 
package capsis.extension.intervener;
 
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.Locale;
 
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
 
import jeeb.lib.util.AmapDialog;
import jeeb.lib.util.Check;
import jeeb.lib.util.ColumnPanel;
import jeeb.lib.util.MessageDialog;
import jeeb.lib.util.LinePanel;
import jeeb.lib.util.Translator;
import capsis.commongui.command.tmp.Helper;
import capsis.defaulttype.Tree;
 
/**
 * This dialog box is used to set DHAThinner parameters in interactive context.
 * 
 * @author F. de Coligny - march 2002
 */
public class DHAThinnerDialog extends AmapDialog implements ActionListener {
 
	// 24.6.2002 - fc - bug correction (phd) : getMin () and getMax () returned int values, now they
	// return float. DHAThinner version passed to 1.1.
 
	private NumberFormat nf;
 
	private DHAThinner thinner;
 
	private ButtonGroup group1;
	private JRadioButton dbh;
	private JRadioButton height;
	private JRadioButton age;
	private JTextField min;
	private JTextField max;
 
	protected JButton ok;
	protected JButton cancel;
	protected JButton help;
 
 
 
	/**	
	 * Constructor
	 */
	public DHAThinnerDialog (DHAThinner thinner) {
		super ();
 
		this.thinner = thinner;
 
		// To show numbers in a nice way
		nf = NumberFormat.getInstance (Locale.ENGLISH);
		nf.setGroupingUsed (false);
		nf.setMaximumFractionDigits (3);
 
		createUI ();
		presetMinMax ();
		setTitle (Translator.swap ("DHAThinnerDialog"));
 
		setModal (true);
 
		// location is set by the AmapDialog superclass
		pack (); // uses component's preferredSize
		show ();
 
	}
 
	/**
	 * Accessor for context.
	 */
	public int getContext () {
		if (dbh.isSelected ()) {
			return DHAThinner.DBH;
		} else if (height.isSelected ()) {
			return DHAThinner.HEIGHT;
		} else {
			return DHAThinner.AGE;
		}
	}
 
	/**
	 * Accessor for min value.
	 */
	public float getMin () {
		if (min.getText ().trim ().length () == 0) { return 0; }
		return (float) Check.doubleValue (min.getText ().trim ());
	}
 
	/**
	 * Accessor for max value.
	 */
	public float getMax () {
		if (max.getText ().trim ().length () == 0) { return Float.MAX_VALUE; }
		return (float) Check.doubleValue (max.getText ().trim ());
	}
 
	/**
	 * Action on ok button.
	 */
	private void okAction () {
 
		boolean minIsEmpty = Check.isEmpty (min.getText ().trim ());
		boolean maxIsEmpty = Check.isEmpty (max.getText ().trim ());
 
		// Checks...
		if (minIsEmpty && maxIsEmpty) {
			MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.someValueIsNeeded"));
			return;
		}
 
		// Age must be an int
		if (age.isSelected ()) {
			if (!minIsEmpty && !Check.isInt (min.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.ageMustBeAnInteger"));
				return;
			}
			if (!maxIsEmpty && !Check.isInt (max.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.ageMustBeAnInteger"));
				return;
			}
 
		// Dbh and height must be doubles
		} else {
			if (!minIsEmpty && !Check.isDouble (min.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.bothValuesMustBeNumbers"));
				return;
			}
			if (!maxIsEmpty && !Check.isDouble (max.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.bothValuesMustBeNumbers"));
				return;
			}
 
		}
 
		// Min must be lower than max
		if (!minIsEmpty && !maxIsEmpty) {
			if (Check.doubleValue (min.getText ().trim ()) > Check.doubleValue (max.getText ().trim ())) {
				MessageDialog.print (this, Translator.swap ("DHAThinnerDialog.minMustBeLowerThanMax"));
				return;
			}
		}
 
		// All has been checked successfully, set the dialog invisible 
		// and go back to caller (will check for validity and dispose the dialog)
		setValidDialog (true);
	}
 
	/**
	 * Action on cancel button.
	 */
	private void cancelAction () {
		// Set the dialog invisible 
		// and go back to caller (will check for validity and dispose the dialog)
		setValidDialog (false);
	}
 
	/**
	 * Someone hit a button.
	 */
	public void actionPerformed (ActionEvent evt) {
		if (evt.getSource () instanceof JRadioButton) {
			presetMinMax ();
		} else if (evt.getSource ().equals (ok)) {
			okAction ();
		} else if (evt.getSource ().equals (cancel)) {
			cancelAction ();
		} else if (evt.getSource ().equals (help)) {
			Helper.helpFor (this);
		}
	}
 
	/**
	 * Writes the available min max values in the min and max textfields as an information
	 * for the user.
	 */
	private void presetMinMax () {
		if (thinner.concernedTrees == null || thinner.concernedTrees.isEmpty ()) { return; }
 
		double m = Double.MAX_VALUE;
		double M = -Double.MAX_VALUE;
 
		double v = 0;
		for (Tree t : thinner.concernedTrees) {
			if (dbh.isSelected ()) {
				v = t.getDbh ();
 
			} else if (height.isSelected ()) {
				v = t.getHeight ();
 
			} else if (age.isSelected ()) {
				v = t.getAge ();
 
			}
 
			m = Math.min (m, v);
			M = Math.max (M, v);
 
		}
		min.setText (nf.format (m));
		max.setText (nf.format (M));
 
	}
 
	/**
	 * Creates the dialog box user interface.
	 */
	private void createUI () {
 
		// All lines will be inserted in this main column
		ColumnPanel panel = new ColumnPanel ();
 
		// Choose the mode: diameter, height OR age
		LinePanel l1 = new LinePanel ();
		l1.add (new JLabel (Translator.swap ("DHAThinnerDialog.cutTreesWith") + " :"));
		l1.addGlue ();
		panel.add (l1);
 
		// Radio buttons
		LinePanel l10 = new LinePanel ();
		LinePanel l11 = new LinePanel ();
		LinePanel l12 = new LinePanel ();
 
		dbh = new JRadioButton (Translator.swap ("DHAThinnerDialog.dbh"));
		dbh.addActionListener (this);
		height = new JRadioButton (Translator.swap ("DHAThinnerDialog.height"));
		height.addActionListener (this);
		age = new JRadioButton (Translator.swap ("DHAThinnerDialog.age"));
		age.addActionListener (this);
 
		// Add the radio buttons in their group
		group1 = new ButtonGroup ();
		group1.add (dbh);
		group1.add (height);
		group1.add (age);
		// Choose the default selection
		group1.setSelected (dbh.getModel (), true);
 
		l10.add (dbh);
		l10.addGlue ();
		l11.add (height);
		l11.addGlue ();
		l12.add (age);
		l12.addGlue ();
		panel.add (l10);
		panel.add (l11);
		panel.add (l12);
 
		// Min and max fields on a single line
		LinePanel l21 = new LinePanel ();
		min = new JTextField (5);
		max = new JTextField (5);
		l21.add (new JLabel (Translator.swap ("DHAThinnerDialog.between") + " : "));
		l21.add (min);
		l21.add (new JLabel (" " + Translator.swap ("DHAThinnerDialog.and") + " : "));
		l21.add (max);
		l21.addStrut0 ();
		panel.add (l21);
		panel.addGlue ();
 
		// Put the main panel at the top (north) of the user interface
		getContentPane ().setLayout (new BorderLayout ());
		getContentPane ().add (panel, BorderLayout.NORTH);
 
		// Control panel (Ok Cancel Help)
		LinePanel controlPanel = new LinePanel ();
		ok = new JButton (Translator.swap ("Shared.ok"));
		cancel = new JButton (Translator.swap ("Shared.cancel"));
		help = new JButton (Translator.swap ("Shared.help"));
 
		controlPanel.addGlue ();  // adding glue first -> the buttons will be right justified
		controlPanel.add (ok);
		controlPanel.add (cancel);
		controlPanel.add (help);
		controlPanel.addStrut0 ();
 
		ok.addActionListener (this);
		cancel.addActionListener (this);
		help.addActionListener (this);
 
		// Put the control panel at the bottom (south)
		getContentPane ().add (controlPanel, BorderLayout.SOUTH);
 
		// Set Ok as default (see AmapDialog)
		setDefaultButton (ok);
 
	}
 
}
documentation/howtobuildaspecificdialogboxforanintervener.txt · Last modified: 2016/12/16 16:22 by beudez