/* * [SandDepth.java] * * Summary: compute amount of sand needed for an aquarium. * * Copyright: (c) 2014-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2014-08-11 initial version * 1.1 2014-12-10 lint */ package com.mindprod.sanddepth; import com.mindprod.common18.Build; import com.mindprod.common18.CMPAboutJBox; import com.mindprod.common18.Common18; import com.mindprod.common18.FontFactory; import com.mindprod.common18.HybridJ; import com.mindprod.common18.Laf; import com.mindprod.common18.Misc; import com.mindprod.common18.ST; import com.mindprod.common18.VersionCheck; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.Color; import java.awt.Container; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.net.URL; import java.text.DecimalFormat; /** * possible tank shapes */ enum Shape { RECTANGULAR, CYLINDRICAL, MOON } /** * compute amount of sand needed for an aquarium. *

* Must be signed to allow Look and Feel to work. * * @author Roedy Green, Canadian Mind Products * @version 1.1 2014-12-10 lint * @since 2014-08-11 */ public class SandDepth extends JApplet { // declarations /** * height of Applet box in pixels. Does not include surrounding frame. * Includes menu bar and frame bar but not frame surrounding that. Includes bottom margin. */ private static final int APPLET_HEIGHT = 600; /** * Width of Applet box in pixels. */ private static final int APPLET_WIDTH = 840; /** * first year the program copyrighted */ private static final int FIRST_COPYRIGHT_YEAR = 2014; /** * inner margin. margin about a component not touching the edge of the frame */ private static final int INNER = 5; /** * outer margin, margin about a component touching the edge of the frame */ private static final int OUTER = 20; private static final double DEFAULT_SG = 1.5d; /** * how many US gallons in a cubic inch */ private static final double US_GALS_PER_CU_INCH = 0.004329d; /** * how much a cc of water weighs in kilograms */ private static final double WEIGHT_OF_CC_WATER_IN_KG = 0.001d; /** * how much a cubic inch of water weighs in pounds */ private static final double WEIGHT_OF_CU_INCH_WATER_IN_POUNDS = 0.036_126_684_455d; /** * undisplayed copyright notice * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2014-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * when program released to the public */ private static final String RELEASE_DATE = "2014-12-10"; /** * title for about box */ private static final String TITLE_STRING = "Aquarium Sand Depth Calculator"; /** * program version for about box */ private static final String VERSION_STRING = "1.1"; /** * background colour, light yellow */ private static final Color BACKGROUND_FOR_BODY = new Color( 0xf7fbd7 ); /** * light green resultColor background */ private static final Color BACKGROUND_FOR_RESULT_LIGHT = new Color( 0xe3fdf7 ); /** * medium green resultColor background */ private static final Color BACKGROUND_FOR_RESULT_MEDIUM = new Color( 0xafffe4 ); /** * darker green resultColor background. */ private static final Color DARK_BACKGROUND_FOR_RESULT = new Color( 0x9fffd4 ); /** * instructions colour */ private static final Color FOREGROUND_FOR_INSTRUCTIONS = new Color( 0x008000 ); /** * label foreground */ private static final Color FOREGROUND_FOR_LABEL = new Color( 0x0000b0 ); /** * foreground for titles */ private static final Color FOREGROUND_FOR_TITLE = new Color( 0xdc143c ); /** * format for one decimal place */ private static final DecimalFormat DF1 = new DecimalFormat( "0.0" ); /** * format for two decimal places */ private static final DecimalFormat DF2 = new DecimalFormat( "0.00" ); /** * font for labels */ private static final Font FONT_FOR_LABEL = FontFactory.build( "Dialog", Font.PLAIN, 14 ); /** * Font for for titles and About buttons */ private static final Font FONT_FOR_TITLE = FontFactory.build( "Dialog", Font.BOLD, 16 ); /** * Font for for title second line */ private static final Font FONT_FOR_TITLE2 = FontFactory.build( "Dialog", Font.PLAIN, 14 ); /** * used to stop cycle triggering of event when sliders set */ private boolean defibrillate = false; /** * true if we are in metric mode, false in imperial mode */ private boolean metric; /** * conversion factor when calculating sand depth, either imperial or metric */ private double depthConverter; /** * size of a slider tick for the length of tank */ private double lengthTickSize; /** * size of the a slider tick specific gravity */ private double specificGravityTickSize; /** * conversion factor for volume calc, either imperial or metric */ private double volumeConverter; /** * conversion factor for weight calc, either imperial or metric */ private double weightConverter; /** * size of the a slider tick for weight */ private double weightTickSize; /** * metric/imperial pair of toggle buttons */ private ButtonGroup modes; /** * toggle button for tank shape */ private ButtonGroup tankShape; /** * radio button to choose tank shape */ private JButton chooseCylindrical; /** * radio button to choose tank shape */ private JButton chooseMoon; /** * radio button to choose tank shape */ private JButton chooseRectangular; /** * label for the cylinder shape */ private JLabel cylindricalLabel; /** * label for the instructions */ private JLabel instructions; /** * label for the moon shape */ private JLabel moonLabel; /** * label for the rectangle shape */ private JLabel rectangularLabel; /** * label for sand depth */ private JLabel sandDepthLabel; /** * label for sand weight */ private JLabel sandWeightLabel; /** * label for specific gravity */ private JLabel specificGravityLabel; /** * label for tank area */ private JLabel tankAreaLabel; /** * label to tank diameter */ private JLabel tankDiameterLabel; /** * label to tank height */ private JLabel tankHeightLabel; /** * label to tank length */ private JLabel tankLengthLabel; /** * label for tank volume */ private JLabel tankVolumeLabel; /** * label to tank width */ private JLabel tankWidthLabel; /** * Applet Title */ private JLabel title; /** * title, second part */ private JLabel title2; /** * panel to held the three shape buttons */ private JPanel shapePanel; /** * radio button to choose imperial mode */ private JRadioButton chooseImperial; /** * radio button to choose metric mode */ private JRadioButton chooseMetric; /** * slider to control sand depth */ private JSlider sandDepthSlider; /** * slider to control sand weight */ private JSlider sandWeightSlider; /** * slider to control specific gravity */ private JSlider specificGravitySlider; /** * slider to control tank diameter */ private JSlider tankDiameterSlider; /** * slider to control tank height */ private JSlider tankHeightSlider; /** * slider to control tank length */ private JSlider tankLengthSlider; /** * slider to control tank width */ private JSlider tankWidthSlider; /** * sand depth display */ private JTextField sandDepth; /** * sand weight display */ private JTextField sandWeight; /** * specific gravity display */ private JTextField specificGravity; /** * tank area display */ private JTextField tankArea; /** * tank diameter display */ private JTextField tankDiameter; /** * tank height display */ private JTextField tankHeight; /** * tank length display */ private JTextField tankLength; /** * tank volume display */ private JTextField tankVolume; /** * tank width display */ private JTextField tankWidth; private Shape shape = Shape.RECTANGULAR; // /declarations // methods /** * Simple way to create an ImageIcon * Read a png, gif or jpg from the archive resource jar file. * * @param imageResourceName fully resource name of the image in the jar. if leave off off lead / will be relative to * com.mindprod.example. * * @return ImageIcon corresponding to the png/gif/jpg. */ private static ImageIcon createImageIcon( String imageResourceName ) { URL url = SandDepth.class.getResource( imageResourceName ); if ( url == null ) { return null; } return new ImageIcon( url ); } /** * allocate the components */ private void buildComponents() { modes = new ButtonGroup(); tankShape = new ButtonGroup(); // chooseMetric = new JRadioButton( "metric", false ); chooseMetric.setFont( FONT_FOR_LABEL ); chooseMetric.setForeground( FOREGROUND_FOR_LABEL ); // chooseImperial = new JRadioButton( "imperial", true ); chooseImperial.setFont( FONT_FOR_LABEL ); chooseImperial.setForeground( FOREGROUND_FOR_LABEL ); // modes.add( chooseMetric ); modes.add( chooseImperial ); // shapePanel = new JPanel(); shapePanel.setBackground( BACKGROUND_FOR_BODY ); shapePanel.setLayout( new FlowLayout() ); // chooseRectangular = new JButton(); decorateButton( chooseRectangular, "rect" ); // chooseCylindrical = new JButton(); decorateButton( chooseCylindrical, "cyl" ); // chooseMoon = new JButton(); decorateButton( chooseMoon, "moon" ); // tankShape.add( chooseRectangular ); tankShape.add( chooseCylindrical ); tankShape.add( chooseMoon ); // title = new JLabel( TITLE_STRING + " " + VERSION_STRING ); title.setFont( FONT_FOR_TITLE ); title.setForeground( FOREGROUND_FOR_TITLE ); // title2 = new JLabel( "released:" + RELEASE_DATE + " build:" + Build.BUILD_NUMBER ); title2.setFont( FONT_FOR_TITLE2 ); title2.setForeground( FOREGROUND_FOR_TITLE ); // tankLengthLabel = new JLabel(); tankLengthLabel.setFont( FONT_FOR_LABEL ); tankLengthLabel.setForeground( FOREGROUND_FOR_LABEL ); // tankWidthLabel = new JLabel(); tankWidthLabel.setFont( FONT_FOR_LABEL ); tankWidthLabel.setForeground( FOREGROUND_FOR_LABEL ); // tankDiameterLabel = new JLabel(); tankDiameterLabel.setFont( FONT_FOR_LABEL ); tankDiameterLabel.setForeground( FOREGROUND_FOR_LABEL ); // tankHeightLabel = new JLabel(); tankHeightLabel.setFont( FONT_FOR_LABEL ); tankHeightLabel.setForeground( FOREGROUND_FOR_LABEL ); // sandDepthLabel = new JLabel(); sandDepthLabel.setFont( FONT_FOR_LABEL ); sandDepthLabel.setForeground( FOREGROUND_FOR_LABEL ); // sandWeightLabel = new JLabel(); sandWeightLabel.setFont( FONT_FOR_LABEL ); sandWeightLabel.setForeground( FOREGROUND_FOR_LABEL ); sandWeightLabel.setBackground( DARK_BACKGROUND_FOR_RESULT ); // tankVolumeLabel = new JLabel(); tankVolumeLabel.setFont( FONT_FOR_LABEL ); tankVolumeLabel.setForeground( FOREGROUND_FOR_LABEL ); // tankAreaLabel = new JLabel(); tankAreaLabel.setFont( FONT_FOR_LABEL ); tankAreaLabel.setForeground( FOREGROUND_FOR_LABEL ); // specificGravityLabel = new JLabel(); specificGravityLabel.setFont( FONT_FOR_LABEL ); specificGravityLabel.setForeground( FOREGROUND_FOR_LABEL ); // rectangularLabel = new JLabel( "rectangular" ); rectangularLabel.setFont( FONT_FOR_LABEL ); rectangularLabel.setForeground( FOREGROUND_FOR_LABEL ); // cylindricalLabel = new JLabel( "cylindrical" ); cylindricalLabel.setFont( FONT_FOR_LABEL ); cylindricalLabel.setForeground( FOREGROUND_FOR_LABEL ); // moonLabel = new JLabel( "half-moon" ); moonLabel.setFont( FONT_FOR_LABEL ); moonLabel.setForeground( FOREGROUND_FOR_LABEL ); tankLengthSlider = new JSlider( JSlider.HORIZONTAL ); tankWidthSlider = new JSlider( JSlider.HORIZONTAL ); tankDiameterSlider = new JSlider( JSlider.HORIZONTAL ); tankHeightSlider = new JSlider( JSlider.HORIZONTAL ); sandDepthSlider = new JSlider( JSlider.HORIZONTAL ); sandWeightSlider = new JSlider( JSlider.HORIZONTAL ); specificGravitySlider = new JSlider( JSlider.HORIZONTAL ); // tankLength = new JTextField(); tankLength.setHorizontalAlignment( JTextField.RIGHT ); tankLength.setEditable( false ); // tankWidth = new JTextField(); tankWidth.setHorizontalAlignment( JTextField.RIGHT ); tankWidth.setEditable( false ); // tankDiameter = new JTextField(); tankDiameter.setHorizontalAlignment( JTextField.RIGHT ); tankDiameter.setEditable( false ); // tankHeight = new JTextField(); tankHeight.setHorizontalAlignment( JTextField.RIGHT ); tankHeight.setEditable( false ); // sandDepth = new JTextField(); sandDepth.setHorizontalAlignment( JTextField.RIGHT ); sandDepth.setEditable( false ); sandDepth.setBackground( BACKGROUND_FOR_RESULT_MEDIUM ); // sandWeight = new JTextField(); sandWeight.setHorizontalAlignment( JTextField.RIGHT ); sandWeight.setEditable( false ); sandWeight.setBackground( DARK_BACKGROUND_FOR_RESULT ); // tankVolume = new JTextField(); tankVolume.setHorizontalAlignment( JTextField.RIGHT ); tankVolume.setEditable( false ); tankVolume.setBackground( BACKGROUND_FOR_RESULT_LIGHT ); // tankArea = new JTextField(); tankArea.setHorizontalAlignment( JTextField.RIGHT ); tankArea.setEditable( false ); tankArea.setBackground( BACKGROUND_FOR_RESULT_LIGHT ); // specificGravity = new JTextField(); specificGravity.setHorizontalAlignment( JTextField.RIGHT ); specificGravity.setEditable( false ); // instructions = new JLabel( "

    " + "
  1. Select metric or imperial/US measure.
  2. " + "
  3. Select your tank shape image: rectangular, cylindrical or half-moon. Selected shape will brighten.
  4. " + "
  5. Use the sliders to select the size of your aquarium.
  6. " + "
  7. Use the slider to select the desired depth of sand to find out how much sand you need.
  8. " + "
  9. If you have a better value than " + DF2.format( DEFAULT_SG ) + " for the specific gravity of your sand, enter that too.
  10. " + "
  11. Alternatively, use the slider to enter the " + "weight of a quantity of sand to find out how deeply it will spread.
  12. " + "
  13. You can also play with the look and feel menu.
" ); instructions.setFont( FontFactory.build( "Dialog", Font.PLAIN, 12 ) ); instructions.setForeground( FOREGROUND_FOR_INSTRUCTIONS ); instructions.setBackground( BACKGROUND_FOR_BODY ); chooseImperial(); }// /method /** * build a menu with Look & Feel and About across the top */ private void buildMenu() { // turn on anti-alias System.setProperty( "swing.aatext", "true" ); final JMenuBar menubar = new JMenuBar(); setJMenuBar( menubar ); final JMenu lafMenu = Laf.buildLookAndFeelMenu(); if ( lafMenu != null ) { menubar.add( lafMenu ); } final JMenu menuHelp = new JMenu( "Help" ); menubar.add( menuHelp ); final JMenuItem aboutItem = new JMenuItem( "About" ); menuHelp.add( aboutItem ); aboutItem.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { // open about frame new CMPAboutJBox( Misc.getParentFrame( SandDepth.this ), TITLE_STRING, VERSION_STRING, "Calculate how much sand you need", "for your aquarium.", "freeware", RELEASE_DATE, FIRST_COPYRIGHT_YEAR, "Roedy Green", "SANDDEPTH", "1.8" ); } } ); }// /method /** * recalculate the sand depth */ private void calcSandDepth() { final String areaString = tankArea.getText(); if ( ST.isEmpty( areaString ) ) { return; } final double area = Double.parseDouble( areaString ); final String weightString = sandWeight.getText(); if ( ST.isEmpty( weightString ) ) { return; } final double weight = Double.parseDouble( weightString ); final String specificGravityString = specificGravity.getText(); if ( ST.isEmpty( specificGravityString ) ) { return; } final double specificGravity = Double.parseDouble( specificGravityString ); double depth = weight / area * depthConverter / specificGravity; sandDepth.setText( DF1.format( depth ) ); defibrillate = true; sandDepthSlider.setValue( ( int ) ( depth / lengthTickSize ) ); }// /method /** * recalculate the sand Weight */ private void calcSandWeight() { final String areaString = tankArea.getText(); if ( ST.isEmpty( areaString ) ) { return; } final double area = Double.parseDouble( areaString ); final String depthString = sandDepth.getText(); if ( ST.isEmpty( depthString ) ) { return; } final double sandDepth = Double.parseDouble( depthString ); final String specificGravityString = specificGravity.getText(); if ( ST.isEmpty( specificGravityString ) ) { return; } final double specificGravity = Double.parseDouble( specificGravityString ); // volume in cc * specific gravity gives weight in grams, convert to kg. // or volume in cubic inches, * weight cubic inch of water in pounds, * specify gravity. final double weight = area * sandDepth * weightConverter * specificGravity; sandWeight.setText( DF1.format( weight ) ); defibrillate = true; sandWeightSlider.setValue( ( int ) ( weight / weightTickSize ) ); }// /method /** * recalculate the tank area */ private void calcTankArea() { switch ( shape ) { case RECTANGULAR: final String lengthString = tankLength.getText(); // abort calc if all number snot ready. if ( ST.isEmpty( lengthString ) ) { return; } final double length = Double.parseDouble( lengthString ); // final String widthString = tankWidth.getText(); // abort calc if all number snot ready. if ( ST.isEmpty( widthString ) ) { return; } final double width = Double.parseDouble( widthString ); // // no unit conversions needed in metric or imperial tankArea.setText( DF1.format( length * width ) ); break; case CYLINDRICAL: case MOON: final String diameterString = tankDiameter.getText(); // abort calc if all number is not ready. if ( ST.isEmpty( diameterString ) ) { return; } final double diameter = Double.parseDouble( diameterString ); final double radius = diameter / 2; double area = Math.PI * radius * radius; if ( shape == Shape.MOON ) { area /= 2; } tankArea.setText( DF1.format( area ) ); break; default: throw new IllegalArgumentException( "unexpected enum" ); } }// /method /** * recalculate the tank volume */ private void calcTankVolume() { final String areaString = tankArea.getText(); if ( ST.isEmpty( areaString ) ) { return; } final double area = Double.parseDouble( areaString ); final String heightString = tankHeight.getText(); // abort calc if all number snot ready. if ( ST.isEmpty( heightString ) ) { return; } final double height = Double.parseDouble( heightString ); // convert cc to liters or convert cu in to us gallons final double capacity = area * height * volumeConverter; tankVolume.setText( DF1.format( capacity ) ); }// /method /** * set up for calculating in imperial measure */ void chooseImperial() { lengthTickSize = 0.2d; // convert ints to two tenths of inches. weightTickSize = 0.2d; // convert ints to 0.2 pounds. specificGravityTickSize = 0.01d; // convert int to 0.01 sg final int lengthSliderMultiplier = 5; final int weightSliderMultiplier = 5; volumeConverter = US_GALS_PER_CU_INCH; weightConverter = WEIGHT_OF_CU_INCH_WATER_IN_POUNDS; depthConverter = 1.0d / ( WEIGHT_OF_CU_INCH_WATER_IN_POUNDS ); tankAreaLabel.setText( "square in: area of the floor of the tank" ); sandDepthLabel.setText( "in: desired depth of sand" ); sandWeightLabel.setText( "pounds: weight of sand" ); tankDiameterLabel.setText( "in: diameter of the tank." ); tankHeightLabel.setText( "in: height of tank, " + "(measured top to bottom,
including part above the water line). [optional]" ); tankLengthLabel.setText( "in: length of tank (measured left to right)" ); tankWidthLabel.setText( "in: width of tank (measured front to back)" ); tankVolumeLabel.setText( "US gallons: computed nominal capacity of the tank" ); specificGravityLabel.setText( "specific gravity: density of the sand" ); // in fifths of an inch tankLengthSlider.setMinimum( 5 * lengthSliderMultiplier ); tankLengthSlider.setMaximum( 100 * lengthSliderMultiplier ); tankLengthSlider.setValue( 20 * lengthSliderMultiplier ); // tankWidthSlider.setMinimum( 5 * lengthSliderMultiplier ); tankWidthSlider.setMaximum( 50 * lengthSliderMultiplier ); tankWidthSlider.setValue( 10 * lengthSliderMultiplier ); // tankDiameterSlider.setMinimum( 5 * lengthSliderMultiplier ); tankDiameterSlider.setMaximum( 50 * lengthSliderMultiplier ); tankDiameterSlider.setValue( 12 * lengthSliderMultiplier ); // tankHeightSlider.setMinimum( 5 * lengthSliderMultiplier ); tankHeightSlider.setMaximum( 50 * lengthSliderMultiplier ); tankHeightSlider.setValue( 12 * lengthSliderMultiplier ); // sandDepthSlider.setMinimum( 0 * lengthSliderMultiplier + 1 ); sandDepthSlider.setMaximum( 12 * lengthSliderMultiplier ); sandDepthSlider.setValue( 1 * lengthSliderMultiplier ); // 1/5 of a pound sandWeightSlider.setMinimum( 0 * weightSliderMultiplier + 1 ); sandWeightSlider.setMaximum( 500 * weightSliderMultiplier ); sandWeightSlider.setValue( 10 * weightSliderMultiplier ); // specificGravitySlider.setMinimum( 80 ); // by 0.01 specificGravitySlider.setMaximum( 250 ); specificGravitySlider.setValue( 160 ); // // mark all numerical choices as not yet selected, even though slider has a current position. sandDepth.setText( null ); sandWeight.setText( null ); tankArea.setText( null ); tankDiameter.setText( null ); tankHeight.setText( null ); tankLength.setText( null ); tankVolume.setText( null ); tankWidth.setText( null ); specificGravity.setText( DF2.format( DEFAULT_SG ) ); }// /method /** * set up to calculate in metric measure */ void chooseMetric() { lengthTickSize = 0.5d; // convert ints to half cms . weightTickSize = 0.1d; // convert ints to 0.1 kg . specificGravityTickSize = 0.01d; // convert int to 0.01 sg final int lengthSliderMultiplier = 2; final int weightSliderMultiplier = 10; volumeConverter = 1 / 1000d; weightConverter = WEIGHT_OF_CC_WATER_IN_KG; depthConverter = 1 / ( WEIGHT_OF_CC_WATER_IN_KG ); tankAreaLabel.setText( "square cm: area of the floor of the tank" ); sandDepthLabel.setText( "cm: desired depth of sand" ); sandWeightLabel.setText( "kg: weight of sand" ); tankDiameterLabel.setText( "cm: diameter of the tank" ); tankHeightLabel.setText( "cm: height of tank, " + "(measured top to bottom,
including part above the water line). [optional]" ); tankLengthLabel.setText( "cm: length of tank (measured left to right)" ); tankWidthLabel.setText( "cm: width of tank (measured front to back)" ); tankVolumeLabel.setText( "liters: computed nominal capacity of the tank" ); specificGravityLabel.setText( "specific gravity: density of the sand" ); // in half cms. tankLengthSlider.setMinimum( 10 * lengthSliderMultiplier ); tankLengthSlider.setMaximum( 275 * lengthSliderMultiplier ); tankLengthSlider.setValue( 51 * lengthSliderMultiplier ); // tankWidthSlider.setMinimum( 10 * lengthSliderMultiplier ); tankWidthSlider.setMaximum( 115 * lengthSliderMultiplier ); tankWidthSlider.setValue( 25 * lengthSliderMultiplier ); // tankHeightSlider.setMinimum( 10 * lengthSliderMultiplier ); tankHeightSlider.setMaximum( 115 * lengthSliderMultiplier ); tankHeightSlider.setValue( 31 * lengthSliderMultiplier ); // sandDepthSlider.setMinimum( 0 * lengthSliderMultiplier + 1 ); sandDepthSlider.setMaximum( 32 * lengthSliderMultiplier ); sandDepthSlider.setValue( 3 * lengthSliderMultiplier ); // // in 0.1 kg sandWeightSlider.setMinimum( 0 * weightSliderMultiplier + 1 ); sandWeightSlider.setMaximum( 250 * weightSliderMultiplier ); sandWeightSlider.setValue( 5 * weightSliderMultiplier ); // specificGravitySlider.setMinimum( 80 ); // by 0.01 specificGravitySlider.setMaximum( 250 ); specificGravitySlider.setValue( 160 ); // sandDepth.setText( null ); sandWeight.setText( null ); tankArea.setText( null ); tankDiameter.setText( null ); tankHeight.setText( null ); tankLength.setText( null ); tankVolume.setText( null ); tankWidth.setText( null ); specificGravity.setText( DF2.format( DEFAULT_SG ) ); }// /method private void decorateButton( JButton jbutton, String name ) { jbutton.setName( name ); // suppress borders jbutton.setBorderPainted( false ); // suppress press decoration jbutton.setContentAreaFilled( false ); // suppress the ability of the jButton1 to be triggered by enter jbutton.setDefaultCapable( false ); // hide focus rectangle jbutton.setFocusPainted( false ); // set how wide the space must be around the text to the buttonBevelBorder. Also use ipadx/ipady jbutton.setMargin( new Insets( 3, 3, 3, 3 ) ); // ignore clicks that come too fast jbutton.setMultiClickThreshhold( 100/* millis */ ); // the images have transparent background jbutton.setOpaque( false ); // hover help jbutton.setToolTipText( "Select " + name + " for your aquarium shape." ); // Various icon images live in the jar as resources in directory // What button looks like normally. jbutton.setIcon( createImageIcon( "buttonimages/" + name + "normal.png" ) ); // What button looks like normally after setSelected( true ). jbutton.setSelectedIcon( createImageIcon( "buttonimages/" + name + "selected.png" ) ); } /** * hook up button listeners */ private void hookListeners() { final ItemListener modeListener = new ItemListener() { public void itemStateChanged( ItemEvent e ) { metric = chooseMetric.isSelected(); if ( metric ) { chooseMetric(); } else { chooseImperial(); } } }; chooseMetric.addItemListener( modeListener ); chooseImperial.addItemListener( modeListener ); // tankDiameterSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { tankDiameter.setText( DF1.format( tankDiameterSlider.getValue() * lengthTickSize ) ); calcTankArea(); calcTankVolume(); calcSandWeight(); } } ); // tankLengthSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { tankLength.setText( DF1.format( tankLengthSlider.getValue() * lengthTickSize ) ); calcTankArea(); calcTankVolume(); calcSandWeight(); } } ); tankWidthSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { tankWidth.setText( DF1.format( tankWidthSlider.getValue() * lengthTickSize ) ); calcTankArea(); calcTankVolume(); calcSandWeight(); } } ); tankHeightSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { tankHeight.setText( DF1.format( tankHeightSlider.getValue() * lengthTickSize ) ); calcTankVolume(); calcSandWeight(); } } ); sandDepthSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { if ( defibrillate ) { defibrillate = false; return; } sandDepth.setText( DF1.format( sandDepthSlider.getValue() * lengthTickSize ) ); calcSandWeight(); } } ); sandWeightSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { if ( defibrillate ) { defibrillate = false; return; } sandWeight.setText( DF1.format( sandWeightSlider.getValue() * weightTickSize ) ); calcSandDepth(); } } ); specificGravitySlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( final ChangeEvent e ) { if ( defibrillate ) { defibrillate = false; return; } specificGravity.setText( DF2.format( specificGravitySlider.getValue() * specificGravityTickSize ) ); calcSandWeight(); } } ); chooseRectangular.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent e ) { shape = Shape.RECTANGULAR; pruneDisplay(); } } ); chooseCylindrical.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent e ) { shape = Shape.CYLINDRICAL; pruneDisplay(); } } ); chooseMoon.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent e ) { shape = Shape.MOON; pruneDisplay(); } } ); }// /method /** * layout all the components in a GridBag * * @param contentPane where to place the components */ private void layoutComponents( Container contentPane ) { // --0---0-----------1-------- 2------3--------- // 0 title -------------------- title2---------- // 2 chooseMetric checkImperial/ panel // 3 slider value label diameter // 3 slider value label length // 4 slider value label width // 5 --- value label area // 6 slider value label height // 7 --- value label volume // 8 slider value label sand depth // 9 slider value label sand weight // 10 slider value label specific gravity // 11 instructions --------------------------------------- int row = 0; // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( title, new GridBagConstraints( 0, row, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( OUTER, OUTER, INNER, INNER ), 0, 0 ) ); contentPane.add( title2, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( OUTER, INNER, INNER, OUTER ), 0, 0 ) ); contentPane.add( chooseMetric, new GridBagConstraints( 0, row, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( INNER, OUTER, INNER, INNER ), 0, 0 ) ); contentPane.add( chooseImperial, new GridBagConstraints( 1, row, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( INNER, INNER, INNER, INNER ), 0, 0 ) ); contentPane.add( shapePanel, new GridBagConstraints( 2, row++, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, INNER, OUTER ), 0, 0 ) ); shapePanel.add( chooseRectangular ); shapePanel.add( rectangularLabel ); shapePanel.add( chooseCylindrical ); shapePanel.add( cylindricalLabel ); shapePanel.add( chooseMoon ); shapePanel.add( moonLabel ); contentPane.add( tankDiameterSlider, new GridBagConstraints( 0, row, 2, 1, 5.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( tankDiameter, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 35, 0 ) ); contentPane.add( tankDiameterLabel, new GridBagConstraints( 3, row++, 1, 1, 2.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( tankLengthSlider, new GridBagConstraints( 0, row, 2, 1, 5.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( tankLength, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 35, 0 ) ); contentPane.add( tankLengthLabel, new GridBagConstraints( 3, row++, 1, 1, 2.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( tankWidthSlider, new GridBagConstraints( 0, row, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( tankWidth, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( tankWidthLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( tankArea, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( tankAreaLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( tankHeightSlider, new GridBagConstraints( 0, row, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( tankHeight, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( tankHeightLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( tankVolume, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( tankVolumeLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( sandDepthSlider, new GridBagConstraints( 0, row, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( sandDepth, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( sandDepthLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( sandWeightSlider, new GridBagConstraints( 0, row, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( sandWeight, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( sandWeightLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( specificGravitySlider, new GridBagConstraints( 0, row, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, 0, INNER ), 0, 0 ) ); contentPane.add( specificGravity, new GridBagConstraints( 2, row, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, INNER ), 0, 0 ) ); contentPane.add( specificGravityLabel, new GridBagConstraints( 3, row++, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, INNER, 0, OUTER ), 0, 0 ) ); contentPane.add( instructions, new GridBagConstraints( 0, row, 4, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( INNER, OUTER, OUTER, OUTER ), 0, 0 ) ); }// /method /** * hide parts of display not relevant now */ void pruneDisplay() { switch ( shape ) { case RECTANGULAR: chooseRectangular.setSelected( true ); chooseCylindrical.setSelected( false ); chooseMoon.setSelected( false ); tankLengthSlider.setVisible( true ); tankLength.setVisible( true ); tankLengthLabel.setVisible( true ); tankWidthSlider.setVisible( true ); tankWidth.setVisible( true ); tankWidthLabel.setVisible( true ); tankDiameterSlider.setVisible( false ); tankDiameter.setVisible( false ); tankDiameterLabel.setVisible( false ); break; case CYLINDRICAL: chooseRectangular.setSelected( false ); chooseCylindrical.setSelected( true ); chooseMoon.setSelected( false ); tankLengthSlider.setVisible( false ); tankLength.setVisible( false ); tankLengthLabel.setVisible( false ); tankWidthSlider.setVisible( false ); tankWidth.setVisible( false ); tankWidthLabel.setVisible( false ); tankDiameterSlider.setVisible( true ); tankDiameter.setVisible( true ); tankDiameterLabel.setVisible( true ); break; case MOON: chooseRectangular.setSelected( false ); chooseCylindrical.setSelected( false ); chooseMoon.setSelected( true ); tankLengthSlider.setVisible( false ); tankLength.setVisible( false ); tankLengthLabel.setVisible( false ); tankWidthSlider.setVisible( false ); tankWidth.setVisible( false ); tankWidthLabel.setVisible( false ); tankDiameterSlider.setVisible( true ); tankDiameter.setVisible( true ); tankDiameterLabel.setVisible( true ); break; default: throw new IllegalArgumentException( "unexpected enum" ); } // we want to clear fields and reset sliders. This is the easiest way to do it. if ( metric ) { chooseMetric(); } else { chooseImperial(); } } /** * Allow this Applet to run as as application as well. * * @param args command line arguments ignored. */ public static void main( String args[] ) { HybridJ.fireup( new SandDepth(), TITLE_STRING + " " + VERSION_STRING, APPLET_WIDTH, APPLET_HEIGHT ); }// /method /** * Called by the browser or Applet viewer to inform * this Applet that it is being reclaimed and that it should destroy * any resources that it has allocated. */ public void destroy() { title = null; title2 = null; instructions = null; }// /method /** * Called by the browser or Applet viewer to inform * this Applet that it has been loaded into the system. */ @Override public void init() { if ( !VersionCheck.isJavaVersionOK( 1, 7, 0, this.getContentPane() ) ) { // effectively abort return; } Common18.setLaf(); Container contentPane = this.getContentPane(); contentPane.setLayout( new GridBagLayout() ); contentPane.setBackground( BACKGROUND_FOR_BODY ); buildMenu(); // also initial L&F buildComponents(); hookListeners(); layoutComponents( contentPane ); pruneDisplay(); this.validate(); this.setVisible( true ); }// /method // /methods }