Java Notes
GUI-Model Rainfall program
This is an example serves two purposes, based on the very simple problem of recording rainfall statistics.
|
![]() |
GUI class
I'm sorry about the long lines that won't show up on a portrait page, but this is what NetBeans generated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
// RainfallGUI.java - Provides a GUI interface to the RainfallStats class. // Fred Swartz - Nov 29, 2005 // This was generated by NetBeans 5.0 beta2 GUI editor, and a few // additions were made to provide the "data binding" code. public class RainfallGUI extends javax.swing.JFrame { //================================================ my instance variables private RainfallStats _rainLogic; // Keeps data, calculates statistics. //Note 1 /** Creates new form RainfallGUI */ public RainfallGUI() { _rainLogic = new RainfallStats(500); // Initialize for 500 data points. //Note 2 initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc=" Generated Code "> private void initComponents() { jLabel1 = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); rainfallDataTA = new javax.swing.JTextArea(); calcStatsBtn = new javax.swing.JButton(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); averageTF = new javax.swing.JTextField(); numberTF = new javax.swing.JTextField(); totalTF = new javax.swing.JTextField(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("Rain Statistics"); jLabel1.setText("Enter rainfall measurements separated by spaces"); rainfallDataTA.setColumns(20); rainfallDataTA.setRows(5); jScrollPane1.setViewportView(rainfallDataTA); calcStatsBtn.setText("Calculate Statistics"); calcStatsBtn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { calcStatsBtnActionPerformed(evt); } }); jLabel2.setText("Total"); jLabel3.setText("Number"); jLabel4.setText("Average"); org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 249, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(jLabel1) .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jLabel4) .add(jLabel3) .add(jLabel2)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) .add(averageTF) .add(totalTF) .add(org.jdesktop.layout.GroupLayout.TRAILING, numberTF, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 69, Short.MAX_VALUE))) .add(calcStatsBtn)) .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup() .addContainerGap() .add(jLabel1) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 81, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(calcStatsBtn) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel2) .add(totalTF, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel3) .add(numberTF, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel4) .add(averageTF, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); pack(); }// </editor-fold> private void calcStatsBtnActionPerformed(java.awt.event.ActionEvent evt) { String oneDataString = ""; // Defined outside try so catch can use it. //Note 3 try { //... Start a new set of values. _rainLogic.clear(); //... Get data values as strings. String inputData = rainfallDataTA.getText().trim(); String[] inputStrings = inputData.split("\\s++"); //... Loop over each value, convert it, add to stats. for (int i = 0; i < inputStrings.length; i++) { oneDataString = inputStrings[i]; double data = Double.parseDouble(oneDataString); _rainLogic.add(data); } //... Update the display. totalTF.setText("" + _rainLogic.getTotal()); numberTF.setText("" + _rainLogic.getNumber()); averageTF.setText("" + _rainLogic.getAverage()); } catch (NumberFormatException unused) { //... Come here if there was a conversion error. javax.swing.JOptionPane.showMessageDialog(this, "Bad input value: " + oneDataString); totalTF.setText(""); numberTF.setText(""); averageTF.setText(""); } } /** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new RainfallGUI().setVisible(true); } }); } // Variables declaration - do not modify private javax.swing.JTextField averageTF; private javax.swing.JButton calcStatsBtn; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextField numberTF; private javax.swing.JTextArea rainfallDataTA; private javax.swing.JTextField totalTF; // End of variables declaration } |
Notes
- _rainLogic is the instance variable that allows the user interface to get to the model.
- You can add your own initializations to the constructor, as I did here.
- This "handler" is called by the button listener, and all the code it was written by me. This is the code that interfaces with the model (_rainLogic).
Model class
This class contains no user interface code. The user interface knows about it, but this code doesn't know who's using it. It would be just as easy to use this code with a console, dialog, GUI, or web-based interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
// RainfallStats - Class for keeping the rainfall statistics. // Fred Swartz - Nov 29, 2005 // Questions: // * How could this be modified to keep a running total? // * Is it reasonable to have getAverage call getNumber // instead of using _numberOfDataPoints directly? // * What happens if there are no data points and getAverage // is called? What should happen? public class RainfallStats { //============================================== instance variables private double[] _rainMeasurements; private int _numberOfDataPoints; //===================================================== constructor public RainfallStats(int maxSize) { _rainMeasurements = new double[maxSize]; _numberOfDataPoints = 0; } // Adds a data point to the rain data. public void add(double rain) { _rainMeasurements[_numberOfDataPoints] = rain; _numberOfDataPoints++; } //======================================================= getNumber // Return number of data points. public int getNumber() { return _numberOfDataPoints; } //======================================================== getTotal // Returns total rainfall. public double getTotal() { double total = 0.0; for (int i = 0; i < _numberOfDataPoints; i++) { total += _rainMeasurements[i]; } return total; } //====================================================== getAverage // Returns average rainfall public double getAverage() { return getTotal() / getNumber(); // Divide by zero bug. } //=========================================================== clear // Get rid of all data. public void clear() { _numberOfDataPoints = 0; } } |